mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-02-05 04:23:48 +01:00
commit
814f854c5a
74 changed files with 1808 additions and 1851 deletions
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -258,9 +258,15 @@ build/Makefile
|
|||
|
||||
# qt
|
||||
|
||||
qt/i2pd_qt/*.ui.autosave
|
||||
qt/i2pd_qt/*.autosave
|
||||
qt/i2pd_qt/*.ui.bk*
|
||||
qt/i2pd_qt/*.ui_*
|
||||
|
||||
#unknown android stuff
|
||||
android/libs/
|
||||
|
||||
#various logs
|
||||
*LOGS/
|
||||
|
||||
qt/build-*.sh*
|
||||
|
||||
|
|
0
.gitmodules
vendored
Normal file
0
.gitmodules
vendored
Normal file
|
@ -4,7 +4,7 @@ cache:
|
|||
os:
|
||||
- linux
|
||||
#- osx
|
||||
dist: trusty
|
||||
dist: xenial
|
||||
sudo: required
|
||||
compiler:
|
||||
- g++
|
||||
|
|
4
Makefile
4
Makefile
|
@ -27,10 +27,6 @@ else
|
|||
LD_DEBUG = -s
|
||||
endif
|
||||
|
||||
ifeq ($(WEBSOCKETS),1)
|
||||
NEEDED_CXXFLAGS += -DWITH_EVENTS
|
||||
endif
|
||||
|
||||
ifneq (, $(findstring darwin, $(SYS)))
|
||||
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
|
||||
ifeq ($(HOMEBREW),1)
|
||||
|
|
|
@ -15,13 +15,14 @@ ifeq ($(shell expr match $(CXX) 'clang'),5)
|
|||
NEEDED_CXXFLAGS += -std=c++11
|
||||
else ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # gcc >= 4.10
|
||||
NEEDED_CXXFLAGS += -std=c++11
|
||||
else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7
|
||||
else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # gcc 4.7 - 4.9
|
||||
NEEDED_CXXFLAGS += -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1
|
||||
else ifeq ($(shell expr match ${CXXVER} "4\.6"),3) # = 4.6
|
||||
NEEDED_CXXFLAGS += -std=c++0x
|
||||
else ifeq ($(shell expr match ${CXXVER} "[5-9]"),1) # gcc >= 5
|
||||
else ifeq ($(shell expr match ${CXXVER} "[5-6]"),1) # gcc 5 - 6
|
||||
NEEDED_CXXFLAGS += -std=c++11
|
||||
LDLIBS = -latomic
|
||||
else ifeq ($(shell expr match ${CXXVER} "[7-9]"),1) # gcc >= 7
|
||||
NEEDED_CXXFLAGS += -std=c++17
|
||||
LDLIBS = -latomic
|
||||
else # not supported
|
||||
$(error Compiler too old)
|
||||
endif
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[![GitHub release](https://img.shields.io/github/release/PurpleI2P/i2pd.svg?label=latest%20release)](https://github.com/PurpleI2P/i2pd/releases/latest)
|
||||
[![Snapcraft release](https://snapcraft.io/i2pd/badge.svg)](https://snapcraft.io/i2pd)
|
||||
[![License](https://img.shields.io/github/license/PurpleI2P/i2pd.svg)](https://github.com/PurpleI2P/i2pd/blob/openssl/LICENSE)
|
||||
[![Packaging status](https://repology.org/badge/tiny-repos/i2pd.svg)](https://repology.org/project/i2pd/versions)
|
||||
|
||||
i2pd
|
||||
====
|
||||
|
@ -63,9 +64,10 @@ Build instructions:
|
|||
**Supported systems:**
|
||||
|
||||
* GNU/Linux - [![Build Status](https://travis-ci.org/PurpleI2P/i2pd.svg?branch=openssl)](https://travis-ci.org/PurpleI2P/i2pd)
|
||||
* CentOS / Fedora / Mageia - [![Build Status](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/status_image/last_build.png)](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/)
|
||||
* Alpine, ArchLinux, openSUSE, Gentoo, Debian, Ubuntu, etc.
|
||||
* Windows - [![Build status](https://ci.appveyor.com/api/projects/status/1908qe4p48ff1x23?svg=true)](https://ci.appveyor.com/project/PurpleI2P/i2pd)
|
||||
* Mac OS X - [![Build Status](https://travis-ci.org/PurpleI2P/i2pd.svg?branch=openssl)](https://travis-ci.org/PurpleI2P/i2pd)
|
||||
* CentOS / Fedora / Mageia - [![Build Status](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/status_image/last_build.png)](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/)
|
||||
* Docker image - [![Build Status](https://dockerbuildbadges.quelltext.eu/status.svg?organization=meeh&repository=i2pd)](https://hub.docker.com/r/meeh/i2pd/builds/)
|
||||
* Snap - [![Snap Status](https://build.snapcraft.io/badge/PurpleI2P/i2pd-snap.svg)](https://build.snapcraft.io/user/PurpleI2P/i2pd-snap)
|
||||
* FreeBSD
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
android:label="@string/app_name"
|
||||
android:theme="@android:style/Theme.Holo.Light.DarkActionBar"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:usesCleartextTraffic="true"
|
||||
>
|
||||
<receiver android:name=".NetworkStateChangeReceiver">
|
||||
<intent-filter>
|
||||
|
|
19
android/README.md
Normal file
19
android/README.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
# how to compile?
|
||||
## Install the gradle + NDK or use android-studio
|
||||
[https://gradle.org/install/](https://gradle.org/install/)
|
||||
|
||||
## Install the depencies
|
||||
```
|
||||
git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git -b boost-1_72_0
|
||||
git clone https://github.com/PurpleI2P/android-ifaddrs.git
|
||||
git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git
|
||||
git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git
|
||||
```
|
||||
## Set libs in jni/Application.mk on 24 line:
|
||||
```
|
||||
# change to your own
|
||||
I2PD_LIBS_PATH = /home/user/i2pd/android/
|
||||
```
|
||||
|
||||
## compile apk file
|
||||
gradle clean assembleRelease
|
|
@ -32,6 +32,7 @@ android {
|
|||
minSdkVersion 14
|
||||
versionCode 2300
|
||||
versionName "2.30.0"
|
||||
setProperty("archivesBaseName", archivesBaseName + "-" + versionName)
|
||||
ndk {
|
||||
abiFilters 'armeabi-v7a'
|
||||
abiFilters 'x86'
|
||||
|
@ -56,9 +57,10 @@ android {
|
|||
splits {
|
||||
abi {
|
||||
// change that to true if you need splitted apk
|
||||
enable false
|
||||
enable true
|
||||
reset()
|
||||
include "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
|
||||
//include "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
|
||||
include "armeabi-v7a", "x86"
|
||||
universalApk true
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +74,7 @@ android {
|
|||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
minifyEnabled false
|
||||
signingConfig signingConfigs.orignal
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
|
||||
}
|
||||
|
@ -87,3 +89,16 @@ android {
|
|||
targetCompatibility = '1.8'
|
||||
}
|
||||
}
|
||||
|
||||
ext.abiCodes = ['armeabi-v7a':1, 'x86':2, 'arm64-v8a':3, 'x86_64':4]
|
||||
import com.android.build.OutputFile
|
||||
|
||||
android.applicationVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
def baseAbiVersionCode = project.ext.abiCodes.get(output.getFilter(OutputFile.ABI))
|
||||
|
||||
if (baseAbiVersionCode != null) {
|
||||
output.versionCodeOverride = baseAbiVersionCode + variant.versionCode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,29 +25,29 @@ include $(BUILD_SHARED_LIBRARY)
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := boost_system
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_system.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_system.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := boost_date_time
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_date_time.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_date_time.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := boost_filesystem
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := boost_program_options
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_program_options.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_program_options.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
|
|
@ -9,15 +9,15 @@ NDK_TOOLCHAIN_VERSION := clang
|
|||
#APP_STL := c++_shared
|
||||
APP_STL := c++_static
|
||||
|
||||
# Enable c++11 extensions in source code
|
||||
APP_CPPFLAGS += -std=c++11 -fexceptions -frtti
|
||||
# Enable c++17 extensions in source code
|
||||
APP_CPPFLAGS += -std=c++17 -fexceptions -frtti
|
||||
|
||||
APP_CPPFLAGS += -DANDROID -D__ANDROID__ -DUSE_UPNP
|
||||
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||
APP_CPPFLAGS += -DANDROID_ARM7A
|
||||
endif
|
||||
|
||||
# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git
|
||||
# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git -b boost-1_72_0
|
||||
# git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git
|
||||
# git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git
|
||||
# git clone https://github.com/PurpleI2P/android-ifaddrs.git
|
||||
|
|
13
android/res/layout/webview.xml
Normal file
13
android/res/layout/webview.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<LinearLayout android:id="@+id/layout_prompt"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
tools:context=".I2PDActivity">
|
||||
|
||||
<WebView
|
||||
android:id="@+id/webview1"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -12,6 +12,10 @@
|
|||
android:id="@+id/action_graceful_stop"
|
||||
android:orderInCategory="98"
|
||||
android:title="@string/action_graceful_stop" />
|
||||
<item
|
||||
android:id="@+id/action_start_webview"
|
||||
android:orderInCategory="97"
|
||||
android:title="@string/action_start_webview" />
|
||||
</group>
|
||||
<group android:id="@+id/group_various" >
|
||||
<item
|
||||
|
|
|
@ -25,4 +25,5 @@
|
|||
<string name="menu_item_battery_optimizations_str">Battery Optimizations</string>
|
||||
<string name="os_version_does_not_support_battery_optimizations_show_os_dialog_api">Your Android OS version does not support showing the dialog for battery optimizations for applications.</string>
|
||||
<string name="shutdown_canceled">Planned shutdown canceled</string>
|
||||
<string name="action_start_webview">Start webview</string>
|
||||
</resources>
|
||||
|
|
|
@ -39,15 +39,23 @@ import android.view.MenuItem;
|
|||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
// For future package update checking
|
||||
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
|
||||
import static android.provider.Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS;
|
||||
|
||||
public class I2PDActivity extends Activity {
|
||||
private WebView webView;
|
||||
|
||||
private static final String TAG = "i2pdActvt";
|
||||
private static final int MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 1;
|
||||
public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000;
|
||||
|
@ -56,6 +64,7 @@ public class I2PDActivity extends Activity {
|
|||
private TextView textView;
|
||||
private boolean assetsCopied;
|
||||
private String i2pdpath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/";
|
||||
//private ConfigParser parser = new ConfigParser(i2pdpath); // TODO:
|
||||
|
||||
private static final DaemonSingleton daemon = DaemonSingleton.getInstance();
|
||||
|
||||
|
@ -262,6 +271,16 @@ public class I2PDActivity extends Activity {
|
|||
case R.id.action_battery_otimizations:
|
||||
onActionBatteryOptimizations();
|
||||
return true;
|
||||
case R.id.action_start_webview:
|
||||
setContentView(R.layout.webview);
|
||||
this.webView = (WebView) findViewById(R.id.webview1);
|
||||
this.webView.setWebViewClient(new WebViewClient());
|
||||
|
||||
WebSettings webSettings = this.webView.getSettings();
|
||||
webSettings.setBuiltInZoomControls(true);
|
||||
webSettings.setJavaScriptEnabled(false);
|
||||
this.webView.loadUrl("http://127.0.0.1:7070"); // TODO: instead 7070 I2Pd....HttpPort
|
||||
break;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
|
|
|
@ -26,29 +26,29 @@ include $(BUILD_EXECUTABLE)
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := boost_system
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_system.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_system.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := boost_date_time
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_date_time.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_date_time.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := boost_filesystem
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := boost_program_options
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_program_options.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_program_options.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
|
|
@ -9,8 +9,8 @@ APP_PLATFORM := android-14
|
|||
NDK_TOOLCHAIN_VERSION := clang
|
||||
APP_STL := c++_static
|
||||
|
||||
# Enable c++11 extensions in source code
|
||||
APP_CPPFLAGS += -std=c++11 -fvisibility=default -fPIE
|
||||
# Enable c++17 extensions in source code
|
||||
APP_CPPFLAGS += -std=c++17 -fvisibility=default -fPIE
|
||||
|
||||
APP_CPPFLAGS += -DANDROID_BINARY -DANDROID -D__ANDROID__ -DUSE_UPNP
|
||||
APP_LDFLAGS += -rdynamic -fPIE -pie
|
||||
|
@ -21,7 +21,7 @@ endif
|
|||
# Forcing debug optimization. Use `ndk-build NDK_DEBUG=1` instead.
|
||||
#APP_OPTIM := debug
|
||||
|
||||
# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git
|
||||
# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git -b boost-1_72_0
|
||||
# git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git
|
||||
# git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git
|
||||
# git clone https://github.com/PurpleI2P/android-ifaddrs.git
|
||||
|
|
|
@ -20,7 +20,6 @@ option(WITH_MESHNET "Build for cjdns test network" OFF)
|
|||
option(WITH_ADDRSANITIZER "Build with address sanitizer unix only" OFF)
|
||||
option(WITH_THREADSANITIZER "Build with thread sanitizer unix only" OFF)
|
||||
option(WITH_I2LUA "Build for i2lua" OFF)
|
||||
option(WITH_WEBSOCKETS "Build with websocket ui" OFF)
|
||||
|
||||
# paths
|
||||
set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" )
|
||||
|
@ -75,7 +74,6 @@ set (LIBI2PD_SRC
|
|||
"${LIBI2PD_SRC_DIR}/Signature.cpp"
|
||||
"${LIBI2PD_SRC_DIR}/Timestamp.cpp"
|
||||
"${LIBI2PD_SRC_DIR}/api.cpp"
|
||||
"${LIBI2PD_SRC_DIR}/Event.cpp"
|
||||
"${LIBI2PD_SRC_DIR}/Gost.cpp"
|
||||
"${LIBI2PD_SRC_DIR}/ChaCha20.cpp"
|
||||
"${LIBI2PD_SRC_DIR}/Poly1305.cpp"
|
||||
|
@ -86,11 +84,6 @@ set (LIBI2PD_SRC
|
|||
"${LIBI2PD_SRC_DIR}/ECIESX25519AEADRatchetSession.cpp"
|
||||
)
|
||||
|
||||
if (WITH_WEBSOCKETS)
|
||||
add_definitions(-DWITH_EVENTS)
|
||||
find_package(websocketpp REQUIRED)
|
||||
endif ()
|
||||
|
||||
if (WIN32 OR MSYS)
|
||||
list (APPEND LIBI2PD_SRC "${CMAKE_SOURCE_DIR}/I2PEndian.cpp")
|
||||
endif ()
|
||||
|
@ -124,13 +117,8 @@ set (CLIENT_SRC
|
|||
"${LIBI2PD_CLIENT_SRC_DIR}/SOCKS.cpp"
|
||||
"${LIBI2PD_CLIENT_SRC_DIR}/HTTPProxy.cpp"
|
||||
"${LIBI2PD_CLIENT_SRC_DIR}/I2CP.cpp"
|
||||
"${LIBI2PD_CLIENT_SRC_DIR}/WebSocks.cpp"
|
||||
)
|
||||
|
||||
if(WITH_WEBSOCKETS)
|
||||
list (APPEND CLIENT_SRC "${LIBI2PD_CLIENT_SRC_DIR}/Websocket.cpp")
|
||||
endif ()
|
||||
|
||||
add_library(libi2pdclient ${CLIENT_SRC})
|
||||
set_target_properties(libi2pdclient PROPERTIES PREFIX "")
|
||||
|
||||
|
@ -184,17 +172,17 @@ else()
|
|||
set( CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Wl,--gc-sections" ) # -flto is added from above
|
||||
endif ()
|
||||
|
||||
# check for c++11 support
|
||||
# check for c++17 & c++11 support
|
||||
include(CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++17" CXX17_SUPPORTED)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" CXX11_SUPPORTED)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++0x" CXX0X_SUPPORTED)
|
||||
if (CXX11_SUPPORTED)
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" )
|
||||
elseif (CXX0X_SUPPORTED) # gcc 4.6
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x" )
|
||||
elseif (NOT MSVC)
|
||||
message(SEND_ERROR "C++11 standard not seems to be supported by compiler. Too old version?")
|
||||
endif ()
|
||||
if(CXX17_SUPPORTED)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
|
||||
elseif(CXX11_SUPPORTED)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
else()
|
||||
message(SEND_ERROR "C++17 nor C++11 standard not seems to be supported by compiler. Too old version?")
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pipe")
|
||||
|
@ -427,7 +415,6 @@ message(STATUS " MESHNET : ${WITH_MESHNET}")
|
|||
message(STATUS " ADDRSANITIZER : ${WITH_ADDRSANITIZER}")
|
||||
message(STATUS " THREADSANITIZER : ${WITH_THREADSANITIZER}")
|
||||
message(STATUS " I2LUA : ${WITH_I2LUA}")
|
||||
message(STATUS " WEBSOCKETS : ${WITH_WEBSOCKETS}")
|
||||
message(STATUS "---------------------------------------")
|
||||
|
||||
#Handle paths nicely
|
||||
|
|
|
@ -55,14 +55,22 @@ cd build
|
|||
%endif
|
||||
%endif
|
||||
|
||||
%if 0%{?mageia} > 7
|
||||
pushd build
|
||||
make %{?_smp_mflags}
|
||||
popd
|
||||
%else
|
||||
make %{?_smp_mflags}
|
||||
%endif
|
||||
|
||||
|
||||
%install
|
||||
cd build
|
||||
pushd build
|
||||
|
||||
%if 0%{?mageia}
|
||||
cd build
|
||||
pushd build
|
||||
%endif
|
||||
|
||||
chrpath -d i2pd
|
||||
%{__install} -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd
|
||||
%{__install} -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf
|
||||
|
|
|
@ -53,14 +53,22 @@ cd build
|
|||
%endif
|
||||
%endif
|
||||
|
||||
%if 0%{?mageia} > 7
|
||||
pushd build
|
||||
make %{?_smp_mflags}
|
||||
popd
|
||||
%else
|
||||
make %{?_smp_mflags}
|
||||
%endif
|
||||
|
||||
|
||||
%install
|
||||
cd build
|
||||
pushd build
|
||||
|
||||
%if 0%{?mageia}
|
||||
cd build
|
||||
pushd build
|
||||
%endif
|
||||
|
||||
chrpath -d i2pd
|
||||
install -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd
|
||||
install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf
|
||||
|
|
|
@ -26,9 +26,6 @@
|
|||
#include "Timestamp.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "Event.h"
|
||||
#include "Websocket.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace util
|
||||
|
@ -43,9 +40,6 @@ namespace i2p
|
|||
std::unique_ptr<i2p::client::I2PControlService> m_I2PControlService;
|
||||
std::unique_ptr<i2p::transport::UPnP> UPnP;
|
||||
std::unique_ptr<i2p::util::NTPTimeSync> m_NTPSync;
|
||||
#ifdef WITH_EVENTS
|
||||
std::unique_ptr<i2p::event::WebsocketServer> m_WebsocketServer;
|
||||
#endif
|
||||
};
|
||||
|
||||
Daemon_Singleton::Daemon_Singleton() : isDaemon(false), running(true), d(*new Daemon_Singleton_Private()) {}
|
||||
|
@ -62,12 +56,12 @@ namespace i2p
|
|||
return service;
|
||||
}
|
||||
|
||||
bool Daemon_Singleton::init(int argc, char* argv[]) {
|
||||
return init(argc, argv, nullptr);
|
||||
}
|
||||
bool Daemon_Singleton::init(int argc, char* argv[]) {
|
||||
return init(argc, argv, nullptr);
|
||||
}
|
||||
|
||||
bool Daemon_Singleton::init(int argc, char* argv[], std::shared_ptr<std::ostream> logstream)
|
||||
{
|
||||
bool Daemon_Singleton::init(int argc, char* argv[], std::shared_ptr<std::ostream> logstream)
|
||||
{
|
||||
i2p::config::Init();
|
||||
i2p::config::ParseCmdline(argc, argv);
|
||||
|
||||
|
@ -110,10 +104,10 @@ namespace i2p
|
|||
logs = "file";
|
||||
|
||||
i2p::log::Logger().SetLogLevel(loglevel);
|
||||
if (logstream) {
|
||||
LogPrint(eLogInfo, "Log: will send messages to std::ostream");
|
||||
i2p::log::Logger().SendTo (logstream);
|
||||
} else if (logs == "file") {
|
||||
if (logstream) {
|
||||
LogPrint(eLogInfo, "Log: will send messages to std::ostream");
|
||||
i2p::log::Logger().SendTo (logstream);
|
||||
} else if (logs == "file") {
|
||||
if (logfile == "")
|
||||
logfile = i2p::fs::DataDirPath("i2pd.log");
|
||||
LogPrint(eLogInfo, "Log: will send messages to ", logfile);
|
||||
|
@ -127,7 +121,7 @@ namespace i2p
|
|||
// use stdout -- default
|
||||
}
|
||||
|
||||
LogPrint(eLogInfo, "i2pd v", VERSION, " starting");
|
||||
LogPrint(eLogInfo, "i2pd v", VERSION, " starting");
|
||||
LogPrint(eLogDebug, "FS: main config file: ", config);
|
||||
LogPrint(eLogDebug, "FS: data directory: ", datadir);
|
||||
|
||||
|
@ -151,8 +145,8 @@ namespace i2p
|
|||
LogPrint(eLogInfo, "Daemon: accepting incoming connections at port ", port);
|
||||
i2p::context.UpdatePort (port);
|
||||
}
|
||||
i2p::context.SetSupportsV6 (ipv6);
|
||||
i2p::context.SetSupportsV4 (ipv4);
|
||||
i2p::context.SetSupportsV6 (ipv6);
|
||||
i2p::context.SetSupportsV4 (ipv4);
|
||||
|
||||
bool ntcp; i2p::config::GetOption("ntcp", ntcp);
|
||||
i2p::context.PublishNTCPAddress (ntcp, !ipv6);
|
||||
|
@ -233,15 +227,15 @@ namespace i2p
|
|||
if (family.length () > 0)
|
||||
LogPrint(eLogInfo, "Daemon: family set to ", family);
|
||||
|
||||
bool trust; i2p::config::GetOption("trust.enabled", trust);
|
||||
if (trust)
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: explicit trust enabled");
|
||||
std::string fam; i2p::config::GetOption("trust.family", fam);
|
||||
bool trust; i2p::config::GetOption("trust.enabled", trust);
|
||||
if (trust)
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: explicit trust enabled");
|
||||
std::string fam; i2p::config::GetOption("trust.family", fam);
|
||||
std::string routers; i2p::config::GetOption("trust.routers", routers);
|
||||
bool restricted = false;
|
||||
if (fam.length() > 0)
|
||||
{
|
||||
if (fam.length() > 0)
|
||||
{
|
||||
std::set<std::string> fams;
|
||||
size_t pos = 0, comma;
|
||||
do
|
||||
|
@ -253,7 +247,7 @@ namespace i2p
|
|||
while (comma != std::string::npos);
|
||||
i2p::transport::transports.RestrictRoutesToFamilies(fams);
|
||||
restricted = fams.size() > 0;
|
||||
}
|
||||
}
|
||||
if (routers.length() > 0) {
|
||||
std::set<i2p::data::IdentHash> idents;
|
||||
size_t pos = 0, comma;
|
||||
|
@ -272,14 +266,15 @@ namespace i2p
|
|||
}
|
||||
if(!restricted)
|
||||
LogPrint(eLogError, "Daemon: no trusted routers of families specififed");
|
||||
}
|
||||
bool hidden; i2p::config::GetOption("trust.hidden", hidden);
|
||||
if (hidden)
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: using hidden mode");
|
||||
i2p::data::netdb.SetHidden(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hidden; i2p::config::GetOption("trust.hidden", hidden);
|
||||
if (hidden)
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: using hidden mode");
|
||||
i2p::data::netdb.SetHidden(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Daemon_Singleton::start()
|
||||
|
@ -322,7 +317,7 @@ namespace i2p
|
|||
bool http; i2p::config::GetOption("http.enabled", http);
|
||||
if (http) {
|
||||
std::string httpAddr; i2p::config::GetOption("http.address", httpAddr);
|
||||
uint16_t httpPort; i2p::config::GetOption("http.port", httpPort);
|
||||
uint16_t httpPort; i2p::config::GetOption("http.port", httpPort);
|
||||
LogPrint(eLogInfo, "Daemon: starting HTTP Server at ", httpAddr, ":", httpPort);
|
||||
d.httpServer = std::unique_ptr<i2p::http::HTTPServer>(new i2p::http::HTTPServer(httpAddr, httpPort));
|
||||
d.httpServer->Start();
|
||||
|
@ -344,26 +339,11 @@ namespace i2p
|
|||
d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort));
|
||||
d.m_I2PControlService->Start ();
|
||||
}
|
||||
#ifdef WITH_EVENTS
|
||||
|
||||
bool websocket; i2p::config::GetOption("websockets.enabled", websocket);
|
||||
if(websocket) {
|
||||
std::string websocketAddr; i2p::config::GetOption("websockets.address", websocketAddr);
|
||||
uint16_t websocketPort; i2p::config::GetOption("websockets.port", websocketPort);
|
||||
LogPrint(eLogInfo, "Daemon: starting Websocket server at ", websocketAddr, ":", websocketPort);
|
||||
d.m_WebsocketServer = std::unique_ptr<i2p::event::WebsocketServer>(new i2p::event::WebsocketServer (websocketAddr, websocketPort));
|
||||
d.m_WebsocketServer->Start();
|
||||
i2p::event::core.SetListener(d.m_WebsocketServer->ToListener());
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Daemon_Singleton::stop()
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
i2p::event::core.SetListener(nullptr);
|
||||
#endif
|
||||
LogPrint(eLogInfo, "Daemon: shutting down");
|
||||
LogPrint(eLogInfo, "Daemon: stopping Client");
|
||||
i2p::client::context.Stop();
|
||||
|
@ -397,13 +377,6 @@ namespace i2p
|
|||
d.m_I2PControlService->Stop ();
|
||||
d.m_I2PControlService = nullptr;
|
||||
}
|
||||
#ifdef WITH_EVENTS
|
||||
if (d.m_WebsocketServer) {
|
||||
LogPrint(eLogInfo, "Daemon: stopping Websocket server");
|
||||
d.m_WebsocketServer->Stop();
|
||||
d.m_WebsocketServer = nullptr;
|
||||
}
|
||||
#endif
|
||||
i2p::crypto::TerminateCrypto ();
|
||||
i2p::log::Logger().Stop();
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ namespace http {
|
|||
" body { font: 100%/1.5em sans-serif; margin: 0; padding: 1.5em; background: #FAFAFA; color: #103456; }\r\n"
|
||||
" a, .slide label { text-decoration: none; color: #894C84; }\r\n"
|
||||
" a:hover, .slide label:hover { color: #FAFAFA; background: #894C84; }\r\n"
|
||||
" a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none; color: initial; width: 1.5em;}\r\n"
|
||||
" .header { font-size: 2.5em; text-align: center; margin: 1.5em 0; color: #894C84; }\r\n"
|
||||
" .wrapper { margin: 0 auto; padding: 1em; max-width: 60em; }\r\n"
|
||||
" .left { float: left; position: absolute; }\r\n"
|
||||
|
@ -63,9 +64,11 @@ namespace http {
|
|||
" .tunnel.failed { color: #D33F3F; }\r\n"
|
||||
" .tunnel.building { color: #434343; }\r\n"
|
||||
" caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n"
|
||||
" table { width: 100%; border-collapse: collapse; text-align: center; }\r\n"
|
||||
" .slide p, .slide [type='checkbox']{ display:none; }\r\n"
|
||||
" .slide [type='checkbox']:checked ~ p { display:block; margin-top: 0; padding: 0; }\r\n"
|
||||
" table { display: table; border-collapse: collapse; text-align: center; }\r\n"
|
||||
" table.extaddr { text-align: left; }\r\n table.services { width: 100%; }"
|
||||
" .streamdest { width: 120px; max-width: 240px; overflow: hidden; text-overflow: ellipsis;}\r\n"
|
||||
" .slide div.content, .slide [type='checkbox'] { display: none; }\r\n"
|
||||
" .slide [type='checkbox']:checked ~ div.content { display: block; margin-top: 0; padding: 0; }\r\n"
|
||||
" .disabled:after { color: #D33F3F; content: \"Disabled\" }\r\n"
|
||||
" .enabled:after { color: #56B734; content: \"Enabled\" }\r\n"
|
||||
"</style>\r\n";
|
||||
|
@ -89,10 +92,12 @@ namespace http {
|
|||
const char HTTP_COMMAND_RUN_PEER_TEST[] = "run_peer_test";
|
||||
const char HTTP_COMMAND_RELOAD_CONFIG[] = "reload_config";
|
||||
const char HTTP_COMMAND_LOGLEVEL[] = "set_loglevel";
|
||||
const char HTTP_COMMAND_KILLSTREAM[] = "closestream";
|
||||
const char HTTP_PARAM_SAM_SESSION_ID[] = "id";
|
||||
const char HTTP_PARAM_ADDRESS[] = "address";
|
||||
|
||||
static std::string ConvertTime (uint64_t time);
|
||||
std::map<uint32_t, uint32_t> HTTPConnection::m_Tokens;
|
||||
|
||||
static void ShowUptime (std::stringstream& s, int seconds)
|
||||
{
|
||||
|
@ -177,8 +182,10 @@ namespace http {
|
|||
"<div class=left>\r\n"
|
||||
" <a href=\"" << webroot << "\">Main page</a><br>\r\n<br>\r\n"
|
||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_COMMANDS << "\">Router commands</a><br>\r\n"
|
||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATIONS << "\">Local destinations</a><br>\r\n"
|
||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_LEASESETS << "\">LeaseSets</a><br>\r\n"
|
||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATIONS << "\">Local destinations</a><br>\r\n";
|
||||
if (i2p::context.IsFloodfill ())
|
||||
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_LEASESETS << "\">LeaseSets</a><br>\r\n";
|
||||
s <<
|
||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TUNNELS << "\">Tunnels</a><br>\r\n"
|
||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSIT_TUNNELS << "\">Transit tunnels</a><br>\r\n"
|
||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSPORTS << "\">Transports</a><br>\r\n"
|
||||
|
@ -203,10 +210,7 @@ namespace http {
|
|||
s << "<b>ERROR:</b> " << string << "<br>\r\n";
|
||||
}
|
||||
|
||||
void ShowStatus (
|
||||
std::stringstream& s,
|
||||
bool includeHiddenContent,
|
||||
i2p::http::OutputFormatEnum outputFormat)
|
||||
void ShowStatus (std::stringstream& s, bool includeHiddenContent, i2p::http::OutputFormatEnum outputFormat)
|
||||
{
|
||||
s << "<b>Uptime:</b> ";
|
||||
ShowUptime(s, i2p::context.GetUptime ());
|
||||
|
@ -233,11 +237,8 @@ namespace http {
|
|||
}
|
||||
s << "<br>\r\n";
|
||||
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
|
||||
if (auto remains = Daemon.gracefulShutdownInterval) {
|
||||
s << "<b>Stopping in:</b> ";
|
||||
s << remains << " seconds";
|
||||
s << "<br>\r\n";
|
||||
}
|
||||
if (auto remains = Daemon.gracefulShutdownInterval)
|
||||
s << "<b>Stopping in:</b> " << remains << " seconds<br>\r\n";
|
||||
#endif
|
||||
auto family = i2p::context.GetFamily ();
|
||||
if (family.length () > 0)
|
||||
|
@ -253,51 +254,56 @@ namespace http {
|
|||
ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ());
|
||||
s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " KiB/s)<br>\r\n";
|
||||
s << "<b>Data path:</b> " << i2p::fs::GetDataDir() << "<br>\r\n";
|
||||
s << "<div class='slide'>";
|
||||
if((outputFormat==OutputFormatEnum::forWebConsole)||!includeHiddenContent) {
|
||||
s << "<label for='slide-info'>Hidden content. Press on text to see.</label>\r\n<input type='checkbox' id='slide-info'/>\r\n<p class='content'>\r\n";
|
||||
}
|
||||
if(includeHiddenContent) {
|
||||
s << "<b>Router Ident:</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
|
||||
s << "<b>Router Family:</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n";
|
||||
s << "<div class='slide'>";
|
||||
if((outputFormat==OutputFormatEnum::forWebConsole)||!includeHiddenContent) {
|
||||
s << "<label for='slide-info'>Hidden content. Press on text to see.</label>\r\n<input type='checkbox' id='slide-info'/>\r\n<div class='content'>\r\n";
|
||||
}
|
||||
if(includeHiddenContent) {
|
||||
s << "<b>Router Ident:</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
|
||||
if (!i2p::context.GetRouterInfo().GetProperty("family").empty())
|
||||
s << "<b>Router Family:</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n";
|
||||
s << "<b>Router Caps:</b> " << i2p::context.GetRouterInfo().GetProperty("caps") << "<br>\r\n";
|
||||
s << "<b>Our external address:</b>" << "<br>\r\n" ;
|
||||
s << "<b>Our external address:</b>" << "<br>\r\n<table class=\"extaddr\"><tbody>\r\n";
|
||||
for (const auto& address : i2p::context.GetRouterInfo().GetAddresses())
|
||||
{
|
||||
s << "<tr>\r\n";
|
||||
if (address->IsNTCP2 () && !address->IsPublishedNTCP2 ())
|
||||
{
|
||||
s << "NTCP2";
|
||||
s << "<td>NTCP2";
|
||||
if (address->host.is_v6 ()) s << "v6";
|
||||
s << " supported <br>\r\n";
|
||||
s << "</td><td>supported</td>\r\n</tr>\r\n";
|
||||
continue;
|
||||
}
|
||||
switch (address->transportStyle)
|
||||
{
|
||||
case i2p::data::RouterInfo::eTransportNTCP:
|
||||
{
|
||||
s << "NTCP";
|
||||
s << "<td>NTCP";
|
||||
if (address->IsPublishedNTCP2 ()) s << "2";
|
||||
if (address->host.is_v6 ()) s << "v6";
|
||||
s << " ";
|
||||
s << "</td>\r\n";
|
||||
break;
|
||||
}
|
||||
case i2p::data::RouterInfo::eTransportSSU:
|
||||
{
|
||||
s << "<td>SSU";
|
||||
if (address->host.is_v6 ())
|
||||
s << "SSUv6 ";
|
||||
else
|
||||
s << "SSU ";
|
||||
break;
|
||||
s << "v6";
|
||||
s << "</td>\r\n";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
s << "Unknown ";
|
||||
s << "<td>Unknown</td>\r\n";
|
||||
}
|
||||
s << address->host.to_string() << ":" << address->port << "<br>\r\n";
|
||||
s << "<td>" << address->host.to_string() << ":" << address->port << "</td>\r\n</tr>\r\n";
|
||||
}
|
||||
}
|
||||
s << "</p>\r\n</div>\r\n";
|
||||
if(outputFormat==OutputFormatEnum::forQtUi) {
|
||||
s << "<br>";
|
||||
}
|
||||
s << "<b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " ";
|
||||
s << "</tbody></table>\r\n";
|
||||
}
|
||||
s << "</div>\r\n</div>\r\n";
|
||||
if(outputFormat==OutputFormatEnum::forQtUi) {
|
||||
s << "<br>";
|
||||
}
|
||||
s << "<b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " ";
|
||||
s << "<b>Floodfills:</b> " << i2p::data::netdb.GetNumFloodfills () << " ";
|
||||
s << "<b>LeaseSets:</b> " << i2p::data::netdb.GetNumLeaseSets () << "<br>\r\n";
|
||||
|
||||
|
@ -308,17 +314,17 @@ namespace http {
|
|||
s << "<b>Client Tunnels:</b> " << std::to_string(clientTunnelCount) << " ";
|
||||
s << "<b>Transit Tunnels:</b> " << std::to_string(transitTunnelCount) << "<br>\r\n<br>\r\n";
|
||||
|
||||
if(outputFormat==OutputFormatEnum::forWebConsole) {
|
||||
s << "<table><caption>Services</caption><tr><th>Service</th><th>State</th></tr>\r\n";
|
||||
s << "<tr><td>" << "HTTP Proxy" << "</td><td><div class='" << ((i2p::client::context.GetHttpProxy ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||
s << "<tr><td>" << "SOCKS Proxy" << "</td><td><div class='" << ((i2p::client::context.GetSocksProxy ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||
s << "<tr><td>" << "BOB" << "</td><td><div class='" << ((i2p::client::context.GetBOBCommandChannel ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||
s << "<tr><td>" << "SAM" << "</td><td><div class='" << ((i2p::client::context.GetSAMBridge ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||
s << "<tr><td>" << "I2CP" << "</td><td><div class='" << ((i2p::client::context.GetI2CPServer ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||
bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol);
|
||||
s << "<tr><td>" << "I2PControl" << "</td><td><div class='" << ((i2pcontrol) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||
s << "</table>\r\n";
|
||||
}
|
||||
if(outputFormat==OutputFormatEnum::forWebConsole) {
|
||||
bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol);
|
||||
s << "<table class=\"services\"><caption>Services</caption><tbody>\r\n";
|
||||
s << "<tr><td>" << "HTTP Proxy" << "</td><td><div class='" << ((i2p::client::context.GetHttpProxy ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||
s << "<tr><td>" << "SOCKS Proxy" << "</td><td><div class='" << ((i2p::client::context.GetSocksProxy ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||
s << "<tr><td>" << "BOB" << "</td><td><div class='" << ((i2p::client::context.GetBOBCommandChannel ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||
s << "<tr><td>" << "SAM" << "</td><td><div class='" << ((i2p::client::context.GetSAMBridge ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||
s << "<tr><td>" << "I2CP" << "</td><td><div class='" << ((i2p::client::context.GetI2CPServer ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||
s << "<tr><td>" << "I2PControl" << "</td><td><div class='" << ((i2pcontrol) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||
s << "</tbody></table>\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
void ShowLocalDestinations (std::stringstream& s)
|
||||
|
@ -352,24 +358,25 @@ namespace http {
|
|||
|
||||
static void ShowLeaseSetDestination (std::stringstream& s, std::shared_ptr<const i2p::client::LeaseSetDestination> dest)
|
||||
{
|
||||
s << "<b>Base64:</b><br>\r\n<textarea readonly=\"readonly\" cols=\"64\" rows=\"11\" wrap=\"on\">";
|
||||
s << "<b>Base64:</b><br>\r\n<textarea readonly cols=\"80\" rows=\"11\" wrap=\"on\">";
|
||||
s << dest->GetIdentity ()->ToBase64 () << "</textarea><br>\r\n<br>\r\n";
|
||||
if (dest->IsEncryptedLeaseSet ())
|
||||
{
|
||||
i2p::data::BlindedPublicKey blinded (dest->GetIdentity (), dest->IsPerClientAuth ());
|
||||
s << "<div class='slide'><label for='slide-b33'><b>Encrypted B33 address:</b></label>\r\n<input type='checkbox' id='slide-b33'/>\r\n<p class='content'>\r\n";
|
||||
s << "<div class='slide'><label for='slide-b33'><b>Encrypted B33 address:</b></label>\r\n<input type='checkbox' id='slide-b33'/>\r\n<div class='content'>\r\n";
|
||||
s << blinded.ToB33 () << ".b32.i2p<br>\r\n";
|
||||
s << "</p>\r\n</div>\r\n";
|
||||
s << "</div>\r\n</div>\r\n";
|
||||
}
|
||||
|
||||
if(dest->GetNumRemoteLeaseSets())
|
||||
{
|
||||
s << "<div class='slide'><label for='slide-lease'><b>LeaseSets:</b> <i>" << dest->GetNumRemoteLeaseSets () << "</i></label>\r\n<input type='checkbox' id='slide-lease'/>\r\n<p class='content'>\r\n";
|
||||
s << "<div class='slide'><label for='slide-lease'><b>LeaseSets:</b> <i>" << dest->GetNumRemoteLeaseSets ()
|
||||
<< "</i></label>\r\n<input type='checkbox' id='slide-lease'/>\r\n<div class='content'>\r\n<table><thead><th>Address</th><th>Type</th><th>EncType</th></thead><tbody>";
|
||||
for(auto& it: dest->GetLeaseSets ())
|
||||
s << it.first.ToBase32 () << " " << (int)it.second->GetStoreType () << "<br>\r\n";
|
||||
s << "</p>\r\n</div>\r\n";
|
||||
s << "<tr><td>" << it.first.ToBase32 () << "</td><td>" << (int)it.second->GetStoreType () << "</td><td>" << (int)it.second->GetEncryptionType () <<"</td></tr>\r\n";
|
||||
s << "</tbody></table>\r\n</div>\r\n</div>\r\n<br>\r\n";
|
||||
} else
|
||||
s << "<b>LeaseSets:</b> <i>0</i><br>\r\n";
|
||||
s << "<b>LeaseSets:</b> <i>0</i><br>\r\n<br>\r\n";
|
||||
auto pool = dest->GetTunnelPool ();
|
||||
if (pool)
|
||||
{
|
||||
|
@ -394,28 +401,31 @@ namespace http {
|
|||
if (!dest->GetSessions ().empty ()) {
|
||||
std::stringstream tmp_s; uint32_t out_tags = 0;
|
||||
for (const auto& it: dest->GetSessions ()) {
|
||||
tmp_s << i2p::client::context.GetAddressBook ().ToAddress(it.first) << " " << it.second->GetNumOutgoingTags () << "<br>\r\n";
|
||||
tmp_s << "<tr><td>" << i2p::client::context.GetAddressBook ().ToAddress(it.first) << "</td><td>" << it.second->GetNumOutgoingTags () << "</td></tr>\r\n";
|
||||
out_tags = out_tags + it.second->GetNumOutgoingTags ();
|
||||
}
|
||||
s << "<div class='slide'><label for='slide-tags'>Outgoing: <i>" << out_tags << "</i></label>\r\n<input type='checkbox' id='slide-tags'/>\r\n<p class='content'>\r\n" << tmp_s.str () << "</p>\r\n</div>\r\n";
|
||||
s << "<div class='slide'><label for='slide-tags'>Outgoing: <i>" << out_tags << "</i></label>\r\n<input type='checkbox' id='slide-tags'/>\r\n"
|
||||
<< "<div class='content'>\r\n<table><tbody><thead><th>Destination</th><th>Amount</th></thead>\r\n" << tmp_s.str () << "</tbody></table>\r\n</div>\r\n</div>\r\n";
|
||||
} else
|
||||
s << "Outgoing: <i>0</i><br>\r\n";
|
||||
s << "<br>\r\n";
|
||||
}
|
||||
|
||||
void ShowLocalDestination (std::stringstream& s, const std::string& b32)
|
||||
void ShowLocalDestination (std::stringstream& s, const std::string& b32, uint32_t token)
|
||||
{
|
||||
s << "<b>Local Destination:</b><br>\r\n<br>\r\n";
|
||||
i2p::data::IdentHash ident;
|
||||
ident.FromBase32 (b32);
|
||||
auto dest = i2p::client::context.FindLocalDestination (ident);
|
||||
|
||||
if (dest)
|
||||
{
|
||||
ShowLeaseSetDestination (s, dest);
|
||||
// show streams
|
||||
s << "<table><caption>Streams</caption>\r\n<tr>";
|
||||
s << "<th>StreamID</th>";
|
||||
s << "<th>Destination</th>";
|
||||
s << "<table>\r\n<caption>Streams</caption>\r\n<thead>\r\n<tr>";
|
||||
s << "<th style=\"width:25px;\">StreamID</th>";
|
||||
s << "<th style=\"width:5px;\" \\>"; // Stream closing button column
|
||||
s << "<th class=\"streamdest\">Destination</th>";
|
||||
s << "<th>Sent</th>";
|
||||
s << "<th>Received</th>";
|
||||
s << "<th>Out</th>";
|
||||
|
@ -424,13 +434,20 @@ namespace http {
|
|||
s << "<th>RTT</th>";
|
||||
s << "<th>Window</th>";
|
||||
s << "<th>Status</th>";
|
||||
s << "</tr>\r\n";
|
||||
s << "</tr>\r\n</thead>\r\n<tbody>\r\n";
|
||||
|
||||
for (const auto& it: dest->GetAllStreams ())
|
||||
{
|
||||
auto streamDest = i2p::client::context.GetAddressBook ().ToAddress(it->GetRemoteIdentity ());
|
||||
s << "<tr>";
|
||||
s << "<td>" << it->GetSendStreamID () << "</td>";
|
||||
s << "<td>" << i2p::client::context.GetAddressBook ().ToAddress(it->GetRemoteIdentity ()) << "</td>";
|
||||
s << "<td>" << it->GetRecvStreamID () << "</td>";
|
||||
if (it->GetRecvStreamID ()) {
|
||||
s << "<td><a class=\"button\" href=\"/?cmd=" << HTTP_COMMAND_KILLSTREAM << "&b32=" << b32 << "&streamID="
|
||||
<< it->GetRecvStreamID () << "&token=" << token << "\" title=\"Close stream\"> ✘ </a></td>";
|
||||
} else {
|
||||
s << "<td \\>";
|
||||
}
|
||||
s << "<td class=\"streamdest\" title=\"" << streamDest << "\">" << streamDest << "</td>";
|
||||
s << "<td>" << it->GetNumSentBytes () << "</td>";
|
||||
s << "<td>" << it->GetNumReceivedBytes () << "</td>";
|
||||
s << "<td>" << it->GetSendQueueSize () << "</td>";
|
||||
|
@ -441,7 +458,7 @@ namespace http {
|
|||
s << "<td>" << (int)it->GetStatus () << "</td>";
|
||||
s << "</tr>\r\n";
|
||||
}
|
||||
s << "</table>";
|
||||
s << "</tbody>\r\n</table>";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,46 +480,57 @@ namespace http {
|
|||
|
||||
void ShowLeasesSets(std::stringstream& s)
|
||||
{
|
||||
s << "<b>LeaseSets:</b><br>\r\n<br>\r\n";
|
||||
int counter = 1;
|
||||
// for each lease set
|
||||
i2p::data::netdb.VisitLeaseSets(
|
||||
[&s, &counter](const i2p::data::IdentHash dest, std::shared_ptr<i2p::data::LeaseSet> leaseSet)
|
||||
{
|
||||
// create copy of lease set so we extract leases
|
||||
auto storeType = leaseSet->GetStoreType ();
|
||||
std::unique_ptr<i2p::data::LeaseSet> ls;
|
||||
if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
||||
ls.reset (new i2p::data::LeaseSet (leaseSet->GetBuffer(), leaseSet->GetBufferLen()));
|
||||
else
|
||||
ls.reset (new i2p::data::LeaseSet2 (storeType, leaseSet->GetBuffer(), leaseSet->GetBufferLen()));
|
||||
if (!ls) return;
|
||||
s << "<div class='leaseset";
|
||||
if (ls->IsExpired())
|
||||
s << " expired"; // additional css class for expired
|
||||
s << "'>\r\n";
|
||||
if (!ls->IsValid())
|
||||
s << "<div class='invalid'>!! Invalid !! </div>\r\n";
|
||||
s << "<div class='slide'><label for='slide" << counter << "'>" << dest.ToBase32() << "</label>\r\n";
|
||||
s << "<input type='checkbox' id='slide" << (counter++) << "'/>\r\n<p class='content'>\r\n";
|
||||
s << "<b>Store type:</b> " << (int)storeType << "<br>\r\n";
|
||||
s << "<b>Expires:</b> " << ConvertTime(ls->GetExpirationTime()) << "<br>\r\n";
|
||||
if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET || storeType == i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2)
|
||||
if (i2p::data::netdb.GetNumLeaseSets ())
|
||||
{
|
||||
s << "<b>LeaseSets:</b><br>\r\n<br>\r\n";
|
||||
int counter = 1;
|
||||
// for each lease set
|
||||
i2p::data::netdb.VisitLeaseSets(
|
||||
[&s, &counter](const i2p::data::IdentHash dest, std::shared_ptr<i2p::data::LeaseSet> leaseSet)
|
||||
{
|
||||
// leases information is available
|
||||
auto leases = ls->GetNonExpiredLeases();
|
||||
s << "<b>Non Expired Leases: " << leases.size() << "</b><br>\r\n";
|
||||
for ( auto & l : leases )
|
||||
// create copy of lease set so we extract leases
|
||||
auto storeType = leaseSet->GetStoreType ();
|
||||
std::unique_ptr<i2p::data::LeaseSet> ls;
|
||||
if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
||||
ls.reset (new i2p::data::LeaseSet (leaseSet->GetBuffer(), leaseSet->GetBufferLen()));
|
||||
else
|
||||
ls.reset (new i2p::data::LeaseSet2 (storeType, leaseSet->GetBuffer(), leaseSet->GetBufferLen()));
|
||||
if (!ls) return;
|
||||
s << "<div class='leaseset";
|
||||
if (ls->IsExpired())
|
||||
s << " expired"; // additional css class for expired
|
||||
s << "'>\r\n";
|
||||
if (!ls->IsValid())
|
||||
s << "<div class='invalid'>!! Invalid !! </div>\r\n";
|
||||
s << "<div class='slide'><label for='slide" << counter << "'>" << dest.ToBase32() << "</label>\r\n";
|
||||
s << "<input type='checkbox' id='slide" << (counter++) << "'/>\r\n<div class='content'>\r\n";
|
||||
s << "<b>Store type:</b> " << (int)storeType << "<br>\r\n";
|
||||
s << "<b>Expires:</b> " << ConvertTime(ls->GetExpirationTime()) << "<br>\r\n";
|
||||
if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET || storeType == i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2)
|
||||
{
|
||||
s << "<b>Gateway:</b> " << l->tunnelGateway.ToBase64() << "<br>\r\n";
|
||||
s << "<b>TunnelID:</b> " << l->tunnelID << "<br>\r\n";
|
||||
s << "<b>EndDate:</b> " << ConvertTime(l->endDate) << "<br>\r\n";
|
||||
// leases information is available
|
||||
auto leases = ls->GetNonExpiredLeases();
|
||||
s << "<b>Non Expired Leases: " << leases.size() << "</b><br>\r\n";
|
||||
for ( auto & l : leases )
|
||||
{
|
||||
s << "<b>Gateway:</b> " << l->tunnelGateway.ToBase64() << "<br>\r\n";
|
||||
s << "<b>TunnelID:</b> " << l->tunnelID << "<br>\r\n";
|
||||
s << "<b>EndDate:</b> " << ConvertTime(l->endDate) << "<br>\r\n";
|
||||
}
|
||||
}
|
||||
s << "</div>\r\n</div>\r\n</div>\r\n";
|
||||
}
|
||||
s << "</p>\r\n</div>\r\n</div>\r\n";
|
||||
}
|
||||
);
|
||||
// end for each lease set
|
||||
);
|
||||
// end for each lease set
|
||||
}
|
||||
else if (!i2p::context.IsFloodfill ())
|
||||
{
|
||||
s << "<b>LeaseSets:</b> not floodfill.<br>\r\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
s << "<b>LeaseSets:</b> 0<br>\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
void ShowTunnels (std::stringstream& s)
|
||||
|
@ -564,16 +592,23 @@ namespace http {
|
|||
|
||||
void ShowTransitTunnels (std::stringstream& s)
|
||||
{
|
||||
s << "<b>Transit tunnels:</b><br>\r\n<br>\r\n";
|
||||
for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ())
|
||||
if(i2p::tunnel::tunnels.CountTransitTunnels())
|
||||
{
|
||||
if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelGateway>(it))
|
||||
s << it->GetTunnelID () << " ⇒ ";
|
||||
else if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelEndpoint>(it))
|
||||
s << " ⇒ " << it->GetTunnelID ();
|
||||
else
|
||||
s << " ⇒ " << it->GetTunnelID () << " ⇒ ";
|
||||
s << " " << it->GetNumTransmittedBytes () << "<br>\r\n";
|
||||
s << "<b>Transit tunnels:</b><br>\r\n<br>\r\n";
|
||||
for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ())
|
||||
{
|
||||
if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelGateway>(it))
|
||||
s << it->GetTunnelID () << " ⇒ ";
|
||||
else if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelEndpoint>(it))
|
||||
s << " ⇒ " << it->GetTunnelID ();
|
||||
else
|
||||
s << " ⇒ " << it->GetTunnelID () << " ⇒ ";
|
||||
s << " " << it->GetNumTransmittedBytes () << "<br>\r\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s << "<b>Transit tunnels:</b> no transit tunnels currently built.<br>\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -607,13 +642,15 @@ namespace http {
|
|||
}
|
||||
if (!tmp_s.str ().empty ())
|
||||
{
|
||||
s << "<div class='slide'><label for='slide_" << boost::algorithm::to_lower_copy(name) << "'><b>" << name << "</b> ( " << cnt << " )</label>\r\n<input type='checkbox' id='slide_" << boost::algorithm::to_lower_copy(name) << "'/>\r\n<p class='content'>";
|
||||
s << tmp_s.str () << "</p>\r\n</div>\r\n";
|
||||
s << "<div class='slide'><label for='slide_" << boost::algorithm::to_lower_copy(name) << "'><b>" << name
|
||||
<< "</b> ( " << cnt << " )</label>\r\n<input type='checkbox' id='slide_" << boost::algorithm::to_lower_copy(name) << "'/>\r\n<div class='content'>"
|
||||
<< tmp_s.str () << "</div>\r\n</div>\r\n";
|
||||
}
|
||||
if (!tmp_s6.str ().empty ())
|
||||
{
|
||||
s << "<div class='slide'><label for='slide_" << boost::algorithm::to_lower_copy(name) << "v6'><b>" << name << "v6</b> ( " << cnt6 << " )</label>\r\n<input type='checkbox' id='slide_" << boost::algorithm::to_lower_copy(name) << "v6'/>\r\n<p class='content'>";
|
||||
s << tmp_s6.str () << "</p>\r\n</div>\r\n";
|
||||
s << "<div class='slide'><label for='slide_" << boost::algorithm::to_lower_copy(name) << "v6'><b>" << name
|
||||
<< "v6</b> ( " << cnt6 << " )</label>\r\n<input type='checkbox' id='slide_" << boost::algorithm::to_lower_copy(name) << "v6'/>\r\n<div class='content'>"
|
||||
<< tmp_s6.str () << "</div>\r\n</div>\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -640,7 +677,7 @@ namespace http {
|
|||
auto sessions = ssuServer->GetSessions ();
|
||||
if (!sessions.empty ())
|
||||
{
|
||||
s << "<div class='slide'><label for='slide_ssu'><b>SSU</b> ( " << (int) sessions.size() << " )</label>\r\n<input type='checkbox' id='slide_ssu'/>\r\n<p class='content'>";
|
||||
s << "<div class='slide'><label for='slide_ssu'><b>SSU</b> ( " << (int) sessions.size() << " )</label>\r\n<input type='checkbox' id='slide_ssu'/>\r\n<div class='content'>";
|
||||
for (const auto& it: sessions)
|
||||
{
|
||||
auto endpoint = it.second->GetRemoteEndpoint ();
|
||||
|
@ -652,12 +689,12 @@ namespace http {
|
|||
s << " [itag:" << it.second->GetRelayTag () << "]";
|
||||
s << "<br>\r\n" << std::endl;
|
||||
}
|
||||
s << "</p>\r\n</div>\r\n";
|
||||
s << "</div>\r\n</div>\r\n";
|
||||
}
|
||||
auto sessions6 = ssuServer->GetSessionsV6 ();
|
||||
if (!sessions6.empty ())
|
||||
{
|
||||
s << "<div class='slide'><label for='slide_ssuv6'><b>SSUv6</b> ( " << (int) sessions6.size() << " )</label>\r\n<input type='checkbox' id='slide_ssuv6'/>\r\n<p class='content'>";
|
||||
s << "<div class='slide'><label for='slide_ssuv6'><b>SSUv6</b> ( " << (int) sessions6.size() << " )</label>\r\n<input type='checkbox' id='slide_ssuv6'/>\r\n<div class='content'>";
|
||||
for (const auto& it: sessions6)
|
||||
{
|
||||
auto endpoint = it.second->GetRemoteEndpoint ();
|
||||
|
@ -669,7 +706,7 @@ namespace http {
|
|||
s << " [itag:" << it.second->GetRelayTag () << "]";
|
||||
s << "<br>\r\n" << std::endl;
|
||||
}
|
||||
s << "</p>\r\n</div>\r\n";
|
||||
s << "</div>\r\n</div>\r\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -678,17 +715,24 @@ namespace http {
|
|||
{
|
||||
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
||||
auto sam = i2p::client::context.GetSAMBridge ();
|
||||
if (!sam) {
|
||||
if (!sam)
|
||||
{
|
||||
ShowError(s, "SAM disabled");
|
||||
return;
|
||||
}
|
||||
s << "<b>SAM Sessions:</b><br>\r\n<br>\r\n";
|
||||
for (auto& it: sam->GetSessions ())
|
||||
|
||||
if(sam->GetSessions ().size ())
|
||||
{
|
||||
auto& name = it.second->localDestination->GetNickname ();
|
||||
s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_SAM_SESSION << "&sam_id=" << it.first << "\">";
|
||||
s << name << " (" << it.first << ")</a><br>\r\n" << std::endl;
|
||||
s << "<b>SAM Sessions:</b><br>\r\n<br>\r\n";
|
||||
for (auto& it: sam->GetSessions ())
|
||||
{
|
||||
auto& name = it.second->localDestination->GetNickname ();
|
||||
s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_SAM_SESSION << "&sam_id=" << it.first << "\">";
|
||||
s << name << " (" << it.first << ")</a><br>\r\n" << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
s << "<b>SAM Sessions:</b> no sessions currently running.<br>\r\n";
|
||||
}
|
||||
|
||||
static void ShowSAMSession (std::stringstream& s, const std::string& id)
|
||||
|
@ -858,7 +902,8 @@ namespace http {
|
|||
m_Socket->close ();
|
||||
}
|
||||
|
||||
bool HTTPConnection::CheckAuth (const HTTPReq & req) {
|
||||
bool HTTPConnection::CheckAuth (const HTTPReq & req)
|
||||
{
|
||||
/* method #1: http://user:pass@127.0.0.1:7070/ */
|
||||
if (req.uri.find('@') != std::string::npos) {
|
||||
URL url;
|
||||
|
@ -920,7 +965,7 @@ namespace http {
|
|||
} else if (req.uri.find("cmd=") != std::string::npos) {
|
||||
HandleCommand (req, res, s);
|
||||
} else {
|
||||
ShowStatus (s, true, i2p::http::OutputFormatEnum::forWebConsole);
|
||||
ShowStatus (s, true, i2p::http::OutputFormatEnum::forWebConsole);
|
||||
res.add_header("Refresh", "10");
|
||||
}
|
||||
ShowPageTail (s);
|
||||
|
@ -930,7 +975,23 @@ namespace http {
|
|||
SendReply (res, content);
|
||||
}
|
||||
|
||||
std::map<uint32_t, uint32_t> HTTPConnection::m_Tokens;
|
||||
uint32_t HTTPConnection::CreateToken ()
|
||||
{
|
||||
uint32_t token;
|
||||
RAND_bytes ((uint8_t *)&token, 4);
|
||||
token &= 0x7FFFFFFF; // clear first bit
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
for (auto it = m_Tokens.begin (); it != m_Tokens.end (); )
|
||||
{
|
||||
if (ts > it->second + TOKEN_EXPIRATION_TIMEOUT)
|
||||
it = m_Tokens.erase (it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
m_Tokens[token] = ts;
|
||||
return token;
|
||||
}
|
||||
|
||||
void HTTPConnection::HandlePage (const HTTPReq& req, HTTPRes& res, std::stringstream& s)
|
||||
{
|
||||
std::map<std::string, std::string> params;
|
||||
|
@ -947,18 +1008,7 @@ namespace http {
|
|||
ShowTunnels (s);
|
||||
else if (page == HTTP_PAGE_COMMANDS)
|
||||
{
|
||||
uint32_t token;
|
||||
RAND_bytes ((uint8_t *)&token, 4);
|
||||
token &= 0x7FFFFFFF; // clear first bit
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
for (auto it = m_Tokens.begin (); it != m_Tokens.end (); )
|
||||
{
|
||||
if (ts > it->second + TOKEN_EXPIRATION_TIMEOUT)
|
||||
it = m_Tokens.erase (it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
m_Tokens[token] = ts;
|
||||
uint32_t token = CreateToken ();
|
||||
ShowCommands (s, token);
|
||||
}
|
||||
else if (page == HTTP_PAGE_TRANSIT_TUNNELS)
|
||||
|
@ -966,7 +1016,10 @@ namespace http {
|
|||
else if (page == HTTP_PAGE_LOCAL_DESTINATIONS)
|
||||
ShowLocalDestinations (s);
|
||||
else if (page == HTTP_PAGE_LOCAL_DESTINATION)
|
||||
ShowLocalDestination (s, params["b32"]);
|
||||
{
|
||||
uint32_t token = CreateToken ();
|
||||
ShowLocalDestination (s, params["b32"], token);
|
||||
}
|
||||
else if (page == HTTP_PAGE_I2CP_LOCAL_DESTINATION)
|
||||
ShowI2CPLocalDestination (s, params["i2cp_id"]);
|
||||
else if (page == HTTP_PAGE_SAM_SESSIONS)
|
||||
|
@ -992,7 +1045,10 @@ namespace http {
|
|||
url.parse(req.uri);
|
||||
url.parse_query(params);
|
||||
|
||||
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
||||
std::string redirect = "5; url=" + webroot + "?page=commands";
|
||||
std::string token = params["token"];
|
||||
|
||||
if (token.empty () || m_Tokens.find (std::stoi (token)) == m_Tokens.end ())
|
||||
{
|
||||
ShowError(s, "Invalid token");
|
||||
|
@ -1008,36 +1064,74 @@ namespace http {
|
|||
i2p::context.SetAcceptsTunnels (true);
|
||||
else if (cmd == HTTP_COMMAND_DISABLE_TRANSIT)
|
||||
i2p::context.SetAcceptsTunnels (false);
|
||||
else if (cmd == HTTP_COMMAND_SHUTDOWN_START) {
|
||||
else if (cmd == HTTP_COMMAND_SHUTDOWN_START)
|
||||
{
|
||||
i2p::context.SetAcceptsTunnels (false);
|
||||
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
|
||||
Daemon.gracefulShutdownInterval = 10*60;
|
||||
#elif defined(WIN32_APP)
|
||||
i2p::win32::GracefulShutdown ();
|
||||
#endif
|
||||
} else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) {
|
||||
}
|
||||
else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL)
|
||||
{
|
||||
i2p::context.SetAcceptsTunnels (true);
|
||||
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
|
||||
Daemon.gracefulShutdownInterval = 0;
|
||||
#elif defined(WIN32_APP)
|
||||
i2p::win32::StopGracefulShutdown ();
|
||||
#endif
|
||||
} else if (cmd == HTTP_COMMAND_SHUTDOWN_NOW) {
|
||||
}
|
||||
else if (cmd == HTTP_COMMAND_SHUTDOWN_NOW)
|
||||
{
|
||||
#ifndef WIN32_APP
|
||||
Daemon.running = false;
|
||||
#else
|
||||
i2p::win32::StopWin32App ();
|
||||
#endif
|
||||
} else if (cmd == HTTP_COMMAND_LOGLEVEL){
|
||||
}
|
||||
else if (cmd == HTTP_COMMAND_LOGLEVEL)
|
||||
{
|
||||
std::string level = params["level"];
|
||||
SetLogLevel (level);
|
||||
} else {
|
||||
}
|
||||
else if (cmd == HTTP_COMMAND_KILLSTREAM)
|
||||
{
|
||||
std::string b32 = params["b32"];
|
||||
uint32_t streamID = std::stoul(params["streamID"], nullptr);
|
||||
|
||||
i2p::data::IdentHash ident;
|
||||
ident.FromBase32 (b32);
|
||||
auto dest = i2p::client::context.FindLocalDestination (ident);
|
||||
|
||||
if (streamID)
|
||||
{
|
||||
if (dest)
|
||||
{
|
||||
if(dest->DeleteStream (streamID))
|
||||
s << "<b>SUCCESS</b>: Stream closed<br><br>\r\n";
|
||||
else
|
||||
s << "<b>ERROR</b>: Stream not found or already was closed<br><br>\r\n";
|
||||
}
|
||||
else
|
||||
s << "<b>ERROR</b>: Destination not found<br><br>\r\n";
|
||||
}
|
||||
else
|
||||
s << "<b>ERROR</b>: StreamID can be null<br><br>\r\n";
|
||||
|
||||
s << "<a href=\"" << webroot << "?page=local_destination&b32=" << b32 << "\">Return to destination page</a><br>\r\n";
|
||||
s << "<p>You will be redirected back in 5 seconds</b>";
|
||||
redirect = "5; url=" + webroot + "?page=local_destination&b32=" + b32;
|
||||
res.add_header("Refresh", redirect.c_str());
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
res.code = 400;
|
||||
ShowError(s, "Unknown command: " + cmd);
|
||||
return;
|
||||
}
|
||||
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
||||
std::string redirect = "5; url=" + webroot + "?page=commands";
|
||||
|
||||
s << "<b>SUCCESS</b>: Command accepted<br><br>\r\n";
|
||||
s << "<a href=\"" << webroot << "?page=commands\">Back to commands list</a><br>\r\n";
|
||||
s << "<p>You will be redirected in 5 seconds</b>";
|
||||
|
|
|
@ -35,6 +35,7 @@ namespace http
|
|||
void HandlePage (const HTTPReq & req, HTTPRes & res, std::stringstream& data);
|
||||
void HandleCommand (const HTTPReq & req, HTTPRes & res, std::stringstream& data);
|
||||
void SendReply (HTTPRes & res, std::string & content);
|
||||
uint32_t CreateToken ();
|
||||
|
||||
private:
|
||||
|
||||
|
@ -88,7 +89,7 @@ namespace http
|
|||
void ShowTransports (std::stringstream& s);
|
||||
void ShowSAMSessions (std::stringstream& s);
|
||||
void ShowI2PTunnels (std::stringstream& s);
|
||||
void ShowLocalDestination (std::stringstream& s, const std::string& b32);
|
||||
void ShowLocalDestination (std::stringstream& s, const std::string& b32, uint32_t token);
|
||||
} // http
|
||||
} // i2p
|
||||
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
# SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \
|
||||
# Transports.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelPool.cpp TunnelGateway.cpp \
|
||||
# Destination.cpp Base.cpp I2PEndian.cpp FS.cpp Config.cpp Family.cpp \
|
||||
# Config.cpp HTTP.cpp Timestamp.cpp util.cpp api.cpp Event.cpp Gost.cpp
|
||||
# Config.cpp HTTP.cpp Timestamp.cpp util.cpp api.cpp Gost.cpp
|
||||
|
||||
LIB_SRC = $(wildcard $(LIB_SRC_DIR)/*.cpp)
|
||||
|
||||
#LIB_CLIENT_SRC = \
|
||||
# AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp MatchedDestination.cpp \
|
||||
# SAM.cpp SOCKS.cpp HTTPProxy.cpp I2CP.cpp WebSocks.cpp
|
||||
# SAM.cpp SOCKS.cpp HTTPProxy.cpp I2CP.cpp
|
||||
|
||||
LIB_CLIENT_SRC = $(wildcard $(LIB_CLIENT_SRC_DIR)/*.cpp)
|
||||
|
||||
|
|
|
@ -218,13 +218,6 @@ namespace config {
|
|||
("trust.hidden", value<bool>()->default_value(false), "Should we hide our router from other routers?")
|
||||
;
|
||||
|
||||
options_description websocket("Websocket Options");
|
||||
websocket.add_options()
|
||||
("websockets.enabled", value<bool>()->default_value(false), "Enable websocket server")
|
||||
("websockets.address", value<std::string>()->default_value("127.0.0.1"), "Address to bind websocket server on")
|
||||
("websockets.port", value<uint16_t>()->default_value(7666), "Port to bind websocket server on")
|
||||
;
|
||||
|
||||
options_description exploratory("Exploratory Options");
|
||||
exploratory.add_options()
|
||||
("exploratory.inbound.length", value<int>()->default_value(2), "Exploratory inbound tunnel length")
|
||||
|
@ -239,6 +232,7 @@ namespace config {
|
|||
("ntcp2.published", value<bool>()->default_value(true), "Publish NTCP2 (default: enabled)")
|
||||
("ntcp2.port", value<uint16_t>()->default_value(0), "Port to listen for incoming NTCP2 connections (default: auto)")
|
||||
("ntcp2.addressv6", value<std::string>()->default_value("::"), "Address to bind NTCP2 on")
|
||||
("ntcp2.proxy", value<std::string>()->default_value(""), "Proxy URL for NTCP2 transport")
|
||||
;
|
||||
|
||||
options_description nettime("Time sync options");
|
||||
|
@ -274,7 +268,6 @@ namespace config {
|
|||
.add(reseed)
|
||||
.add(addressbook)
|
||||
.add(trust)
|
||||
.add(websocket)
|
||||
.add(exploratory)
|
||||
.add(ntcp2)
|
||||
.add(nettime)
|
||||
|
|
|
@ -388,7 +388,7 @@ namespace client
|
|||
if (buf[DATABASE_STORE_TYPE_OFFSET] == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
||||
leaseSet = std::make_shared<i2p::data::LeaseSet> (buf + offset, len - offset); // LeaseSet
|
||||
else
|
||||
leaseSet = std::make_shared<i2p::data::LeaseSet2> (buf[DATABASE_STORE_TYPE_OFFSET], buf + offset, len - offset, true, GetEncryptionType ()); // LeaseSet2
|
||||
leaseSet = std::make_shared<i2p::data::LeaseSet2> (buf[DATABASE_STORE_TYPE_OFFSET], buf + offset, len - offset, true, GetPreferredCryptoType () ); // LeaseSet2
|
||||
if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key)
|
||||
{
|
||||
if (leaseSet->GetIdentHash () != GetIdentHash ())
|
||||
|
@ -412,7 +412,7 @@ namespace client
|
|||
auto it2 = m_LeaseSetRequests.find (key);
|
||||
if (it2 != m_LeaseSetRequests.end () && it2->second->requestedBlindedKey)
|
||||
{
|
||||
auto ls2 = std::make_shared<i2p::data::LeaseSet2> (buf + offset, len - offset, it2->second->requestedBlindedKey, m_LeaseSetPrivKey ? *m_LeaseSetPrivKey : nullptr, GetEncryptionType ());
|
||||
auto ls2 = std::make_shared<i2p::data::LeaseSet2> (buf + offset, len - offset, it2->second->requestedBlindedKey, m_LeaseSetPrivKey ? *m_LeaseSetPrivKey : nullptr, GetPreferredCryptoType ());
|
||||
if (ls2->IsValid ())
|
||||
{
|
||||
m_RemoteLeaseSets[ls2->GetIdentHash ()] = ls2; // ident is not key
|
||||
|
@ -822,6 +822,13 @@ namespace client
|
|||
}
|
||||
}
|
||||
|
||||
i2p::data::CryptoKeyType LeaseSetDestination::GetPreferredCryptoType () const
|
||||
{
|
||||
if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET))
|
||||
return i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET;
|
||||
return i2p::data::CRYPTO_KEY_TYPE_ELGAMAL;
|
||||
}
|
||||
|
||||
ClientDestination::ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys,
|
||||
bool isPublic, const std::map<std::string, std::string> * params):
|
||||
LeaseSetDestination (service, isPublic, params),
|
||||
|
@ -1149,10 +1156,11 @@ namespace client
|
|||
else
|
||||
{
|
||||
// standard LS2 (type 3) first
|
||||
auto keyLen = m_Decryptor ? m_Decryptor->GetPublicKeyLen () : 256;
|
||||
uint16_t keyLen = m_Decryptor ? m_Decryptor->GetPublicKeyLen () : 256;
|
||||
bool isPublishedEncrypted = GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2;
|
||||
auto ls2 = std::make_shared<i2p::data::LocalLeaseSet2> (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2,
|
||||
m_Keys, m_EncryptionKeyType, keyLen, m_EncryptionPublicKey, tunnels, IsPublic (), isPublishedEncrypted);
|
||||
m_Keys, i2p::data::LocalLeaseSet2::KeySections { {m_EncryptionKeyType, keyLen, m_EncryptionPublicKey} },
|
||||
tunnels, IsPublic (), isPublishedEncrypted);
|
||||
if (isPublishedEncrypted) // encrypt if type 5
|
||||
ls2 = std::make_shared<i2p::data::LocalEncryptedLeaseSet2> (ls2, m_Keys, GetAuthType (), m_AuthKeys);
|
||||
leaseSet = ls2;
|
||||
|
@ -1191,6 +1199,16 @@ namespace client
|
|||
}
|
||||
}
|
||||
|
||||
bool ClientDestination::DeleteStream (uint32_t recvStreamID)
|
||||
{
|
||||
if (m_StreamingDestination->DeleteStream (recvStreamID))
|
||||
return true;
|
||||
for (auto it: m_StreamingDestinationsByPorts)
|
||||
if (it.second->DeleteStream (recvStreamID))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
RunnableClientDestination::RunnableClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params):
|
||||
RunnableService ("Destination"),
|
||||
ClientDestination (GetIOService (), keys, isPublic, params)
|
||||
|
|
|
@ -161,6 +161,7 @@ namespace client
|
|||
void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest);
|
||||
void HandleCleanupTimer (const boost::system::error_code& ecode);
|
||||
void CleanupRemoteLeaseSets ();
|
||||
i2p::data::CryptoKeyType GetPreferredCryptoType () const;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -232,14 +233,14 @@ namespace client
|
|||
int GetStreamingAckDelay () const { return m_StreamingAckDelay; }
|
||||
|
||||
// datagram
|
||||
i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; };
|
||||
i2p::datagram::DatagramDestination * CreateDatagramDestination ();
|
||||
i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; };
|
||||
i2p::datagram::DatagramDestination * CreateDatagramDestination ();
|
||||
|
||||
// implements LocalDestination
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const;
|
||||
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };
|
||||
i2p::data::CryptoKeyType GetEncryptionType () const { return m_EncryptionKeyType; };
|
||||
const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; };
|
||||
bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const { return m_EncryptionKeyType == keyType; };
|
||||
const uint8_t * GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const { return m_EncryptionPublicKey; };
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -281,6 +282,7 @@ namespace client
|
|||
|
||||
// for HTTP only
|
||||
std::vector<std::shared_ptr<const i2p::stream::Stream> > GetAllStreams () const;
|
||||
bool DeleteStream (uint32_t recvStreamID);
|
||||
};
|
||||
|
||||
class RunnableClientDestination: private i2p::util::RunnableService, public ClientDestination
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include "Tag.h"
|
||||
#include "I2PEndian.h"
|
||||
#include "Timestamp.h"
|
||||
#include "Tunnel.h"
|
||||
#include "TunnelPool.h"
|
||||
#include "ECIESX25519AEADRatchetSession.h"
|
||||
|
||||
namespace i2p
|
||||
|
@ -36,28 +38,32 @@ namespace garlic
|
|||
{
|
||||
i2p::crypto::HKDF (m_KeyData.GetSessTagCK (), m_SessTagConstant, 32, "SessionTagKeyGen", m_KeyData.buf); // [sessTag_ck, tag] = HKDF(sessTag_chainkey, SESSTAG_CONSTANT, "SessionTagKeyGen", 64)
|
||||
m_NextIndex++;
|
||||
if (m_NextIndex >= 65535) m_NextIndex = 0; // TODO: dirty hack, should create new tagset
|
||||
return m_KeyData.GetTag ();
|
||||
}
|
||||
|
||||
const uint8_t * RatchetTagSet::GetSymmKey (int index)
|
||||
void RatchetTagSet::GetSymmKey (int index, uint8_t * key)
|
||||
{
|
||||
// TODO: store intermediate keys
|
||||
if (m_NextSymmKeyIndex > 0 && index == m_NextSymmKeyIndex)
|
||||
if (m_NextSymmKeyIndex > 0 && index >= m_NextSymmKeyIndex)
|
||||
{
|
||||
i2p::crypto::HKDF (m_CurrentSymmKeyCK, nullptr, 0, "SymmetricRatchet", m_CurrentSymmKeyCK);
|
||||
m_NextSymmKeyIndex++;
|
||||
auto num = index + 1 - m_NextSymmKeyIndex;
|
||||
for (int i = 0; i < num; i++)
|
||||
i2p::crypto::HKDF (m_CurrentSymmKeyCK, nullptr, 0, "SymmetricRatchet", m_CurrentSymmKeyCK);
|
||||
m_NextSymmKeyIndex += num;
|
||||
memcpy (key, m_CurrentSymmKeyCK + 32, 32);
|
||||
}
|
||||
else
|
||||
CalculateSymmKeyCK (index);
|
||||
return m_CurrentSymmKeyCK + 32;
|
||||
CalculateSymmKeyCK (index, key);
|
||||
}
|
||||
|
||||
void RatchetTagSet::CalculateSymmKeyCK (int index)
|
||||
void RatchetTagSet::CalculateSymmKeyCK (int index, uint8_t * key)
|
||||
{
|
||||
i2p::crypto::HKDF (m_SymmKeyCK, nullptr, 0, "SymmetricRatchet", m_CurrentSymmKeyCK); // keydata_0 = HKDF(symmKey_ck, SYMMKEY_CONSTANT, "SymmetricRatchet", 64)
|
||||
// TODO: store intermediate keys
|
||||
uint8_t currentSymmKeyCK[64];
|
||||
i2p::crypto::HKDF (m_SymmKeyCK, nullptr, 0, "SymmetricRatchet", currentSymmKeyCK); // keydata_0 = HKDF(symmKey_ck, SYMMKEY_CONSTANT, "SymmetricRatchet", 64)
|
||||
for (int i = 0; i < index; i++)
|
||||
i2p::crypto::HKDF (m_CurrentSymmKeyCK, nullptr, 0, "SymmetricRatchet", m_CurrentSymmKeyCK); // keydata_n = HKDF(symmKey_chainKey_(n-1), SYMMKEY_CONSTANT, "SymmetricRatchet", 64)
|
||||
m_NextSymmKeyIndex = index + 1;
|
||||
i2p::crypto::HKDF (currentSymmKeyCK, nullptr, 0, "SymmetricRatchet", currentSymmKeyCK); // keydata_n = HKDF(symmKey_chainKey_(n-1), SYMMKEY_CONSTANT, "SymmetricRatchet", 64)
|
||||
memcpy (key, currentSymmKeyCK + 32, 32);
|
||||
}
|
||||
|
||||
ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner):
|
||||
|
@ -121,7 +127,7 @@ namespace garlic
|
|||
if (!GetOwner ()) return false;
|
||||
// we are Bob
|
||||
// KDF1
|
||||
MixHash (GetOwner ()->GetEncryptionPublicKey (), 32); // h = SHA256(h || bpk)
|
||||
MixHash (GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET), 32); // h = SHA256(h || bpk)
|
||||
|
||||
if (!i2p::crypto::GetElligator ()->Decode (buf, m_Aepk))
|
||||
{
|
||||
|
@ -173,7 +179,7 @@ namespace garlic
|
|||
return true;
|
||||
}
|
||||
|
||||
void ECIESX25519AEADRatchetSession::HandlePayload (const uint8_t * buf, size_t len)
|
||||
void ECIESX25519AEADRatchetSession::HandlePayload (const uint8_t * buf, size_t len, int index)
|
||||
{
|
||||
size_t offset = 0;
|
||||
while (offset < len)
|
||||
|
@ -202,6 +208,12 @@ namespace garlic
|
|||
case eECIESx25519BlkPadding:
|
||||
LogPrint (eLogDebug, "Garlic: padding");
|
||||
break;
|
||||
case eECIESx25519BlkAckRequest:
|
||||
{
|
||||
LogPrint (eLogDebug, "Garlic: ack request");
|
||||
m_AckRequests.push_back ( {bufbe16toh (buf + offset), index});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogPrint (eLogWarning, "Garlic: Unknown block type ", (int)blk);
|
||||
}
|
||||
|
@ -230,7 +242,7 @@ namespace garlic
|
|||
// encrypt static key section
|
||||
uint8_t nonce[12];
|
||||
CreateNonce (0, nonce);
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (GetOwner ()->GetEncryptionPublicKey (), 32, m_H, 32, m_CK + 32, nonce, out + offset, 48, true)) // encrypt
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET), 32, m_H, 32, m_CK + 32, nonce, out + offset, 48, true)) // encrypt
|
||||
{
|
||||
LogPrint (eLogWarning, "Garlic: Static section AEAD encryption failed ");
|
||||
return false;
|
||||
|
@ -373,7 +385,9 @@ namespace garlic
|
|||
memcpy (out, &tag, 8);
|
||||
// ad = The session tag, 8 bytes
|
||||
// ciphertext = ENCRYPT(k, n, payload, ad)
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, out, 8, m_SendTagset.GetSymmKey (index), nonce, out + 8, outLen - 8, true)) // encrypt
|
||||
uint8_t key[32];
|
||||
m_SendTagset.GetSymmKey (index, key);
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, out, 8, key, nonce, out + 8, outLen - 8, true)) // encrypt
|
||||
{
|
||||
LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed");
|
||||
return false;
|
||||
|
@ -387,14 +401,15 @@ namespace garlic
|
|||
CreateNonce (index, nonce); // tag's index
|
||||
len -= 8; // tag
|
||||
std::vector<uint8_t> payload (len - 16);
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (buf + 8, len - 16, buf, 8, m_ReceiveTagset.GetSymmKey (index), nonce, payload.data (), len - 16, false)) // decrypt
|
||||
uint8_t key[32];
|
||||
m_ReceiveTagset.GetSymmKey (index, key);
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (buf + 8, len - 16, buf, 8, key, nonce, payload.data (), len - 16, false)) // decrypt
|
||||
{
|
||||
LogPrint (eLogWarning, "Garlic: Payload section AEAD decryption failed");
|
||||
return false;
|
||||
}
|
||||
HandlePayload (payload.data (), len - 16);
|
||||
if (m_NumReceiveTags > 0)m_NumReceiveTags--;
|
||||
if (m_NumReceiveTags <= GetOwner ()->GetNumTags ()*2/3)
|
||||
HandlePayload (payload.data (), len - 16, index);
|
||||
if (m_ReceiveTagset.GetNextIndex () - index <= GetOwner ()->GetNumTags ()*2/3)
|
||||
GenerateMoreReceiveTags (GetOwner ()->GetNumTags ());
|
||||
return true;
|
||||
}
|
||||
|
@ -453,12 +468,25 @@ namespace garlic
|
|||
|
||||
std::vector<uint8_t> ECIESX25519AEADRatchetSession::CreatePayload (std::shared_ptr<const I2NPMessage> msg)
|
||||
{
|
||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
size_t payloadLen = 7; // datatime
|
||||
if (msg && m_Destination)
|
||||
payloadLen += msg->GetPayloadLength () + 13 + 32;
|
||||
auto leaseSet = CreateDatabaseStoreMsg (GetOwner ()->GetLeaseSet ());
|
||||
if (leaseSet)
|
||||
auto leaseSet = (GetLeaseSetUpdateStatus () == eLeaseSetUpdated) ? CreateDatabaseStoreMsg (GetOwner ()->GetLeaseSet ()) : nullptr;
|
||||
std::shared_ptr<I2NPMessage> deliveryStatus;
|
||||
if (leaseSet)
|
||||
{
|
||||
payloadLen += leaseSet->GetPayloadLength () + 13;
|
||||
deliveryStatus = CreateEncryptedDeliveryStatusMsg (leaseSet->GetMsgID ());
|
||||
payloadLen += deliveryStatus->GetPayloadLength () + 49;
|
||||
if (GetLeaseSetUpdateMsgID ()) GetOwner ()->RemoveDeliveryStatusSession (GetLeaseSetUpdateMsgID ()); // remove previous
|
||||
SetLeaseSetUpdateStatus (eLeaseSetSubmitted);
|
||||
SetLeaseSetUpdateMsgID (leaseSet->GetMsgID ());
|
||||
SetLeaseSetSubmissionTime (ts);
|
||||
GetOwner ()->DeliveryStatusSent (shared_from_this (), leaseSet->GetMsgID ());
|
||||
}
|
||||
if (m_AckRequests.size () > 0)
|
||||
payloadLen += m_AckRequests.size ()*4 + 3;
|
||||
uint8_t paddingSize;
|
||||
RAND_bytes (&paddingSize, 1);
|
||||
paddingSize &= 0x0F; paddingSize++; // 1 - 16
|
||||
|
@ -468,13 +496,28 @@ namespace garlic
|
|||
// DateTime
|
||||
v[offset] = eECIESx25519BlkDateTime; offset++;
|
||||
htobe16buf (v.data () + offset, 4); offset += 2;
|
||||
htobe32buf (v.data () + offset, i2p::util::GetSecondsSinceEpoch ()); offset += 4;
|
||||
htobe32buf (v.data () + offset, ts/1000); offset += 4; // in seconds
|
||||
// LeaseSet
|
||||
if (leaseSet)
|
||||
offset += CreateGarlicClove (leaseSet, v.data () + offset, payloadLen - offset);
|
||||
// DeliveryStatus
|
||||
if (deliveryStatus)
|
||||
offset += CreateDeliveryStatusClove (deliveryStatus, v.data () + offset, payloadLen - offset);
|
||||
// msg
|
||||
if (msg && m_Destination)
|
||||
offset += CreateGarlicClove (msg, v.data () + offset, payloadLen - offset, true);
|
||||
// ack
|
||||
if (m_AckRequests.size () > 0)
|
||||
{
|
||||
v[offset] = eECIESx25519BlkAck; offset++;
|
||||
htobe16buf (v.data () + offset, m_AckRequests.size ()*4); offset += 2;
|
||||
for (auto& it: m_AckRequests)
|
||||
{
|
||||
htobe16buf (v.data () + offset, it.first); offset += 2;
|
||||
htobe16buf (v.data () + offset, it.second); offset += 2;
|
||||
}
|
||||
m_AckRequests.clear ();
|
||||
}
|
||||
// padding
|
||||
v[offset] = eECIESx25519BlkPadding; offset++;
|
||||
htobe16buf (v.data () + offset, paddingSize); offset += 2;
|
||||
|
@ -506,6 +549,39 @@ namespace garlic
|
|||
return cloveSize + 3;
|
||||
}
|
||||
|
||||
size_t ECIESX25519AEADRatchetSession::CreateDeliveryStatusClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len)
|
||||
{
|
||||
uint16_t cloveSize = msg->GetPayloadLength () + 9 + 37 /* delivery instruction */;
|
||||
if ((int)len < cloveSize + 3) return 0;
|
||||
buf[0] = eECIESx25519BlkGalicClove; // clove type
|
||||
htobe16buf (buf + 1, cloveSize); // size
|
||||
buf += 3;
|
||||
if (GetOwner ())
|
||||
{
|
||||
auto inboundTunnel = GetOwner ()->GetTunnelPool ()->GetNextInboundTunnel ();
|
||||
if (inboundTunnel)
|
||||
{
|
||||
// delivery instructions
|
||||
*buf = eGarlicDeliveryTypeTunnel << 5; buf++; // delivery instructions flag tunnel
|
||||
// hash and tunnelID sequence is reversed for Garlic
|
||||
memcpy (buf, inboundTunnel->GetNextIdentHash (), 32); buf += 32;// To Hash
|
||||
htobe32buf (buf, inboundTunnel->GetNextTunnelID ()); buf += 4;// tunnelID
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: No inbound tunnels in the pool for DeliveryStatus");
|
||||
return 0;
|
||||
}
|
||||
*buf = msg->GetTypeID (); // I2NP msg type
|
||||
htobe32buf (buf + 1, msg->GetMsgID ()); // msgID
|
||||
htobe32buf (buf + 5, msg->GetExpiration ()/1000); // expiration in seconds
|
||||
memcpy (buf + 9, msg->GetPayload (), msg->GetPayloadLength ());
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
return cloveSize + 3;
|
||||
}
|
||||
|
||||
void ECIESX25519AEADRatchetSession::GenerateMoreReceiveTags (int numTags)
|
||||
{
|
||||
for (int i = 0; i < numTags; i++)
|
||||
|
@ -514,7 +590,12 @@ namespace garlic
|
|||
uint64_t tag = m_ReceiveTagset.GetNextSessionTag ();
|
||||
GetOwner ()->AddECIESx25519SessionTag (index, tag, shared_from_this ());
|
||||
}
|
||||
m_NumReceiveTags += numTags;
|
||||
}
|
||||
|
||||
bool ECIESX25519AEADRatchetSession::CheckExpired (uint64_t ts)
|
||||
{
|
||||
CleanupUnconfirmedLeaseSet (ts);
|
||||
return ts > m_LastActivityTimestamp + ECIESX25519_EXPIRATION_TIMEOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include "Identity.h"
|
||||
#include "Crypto.h"
|
||||
#include "Garlic.h"
|
||||
|
@ -22,11 +23,11 @@ namespace garlic
|
|||
void NextSessionTagRatchet ();
|
||||
uint64_t GetNextSessionTag ();
|
||||
int GetNextIndex () const { return m_NextIndex; };
|
||||
const uint8_t * GetSymmKey (int index);
|
||||
void GetSymmKey (int index, uint8_t * key);
|
||||
|
||||
private:
|
||||
|
||||
void CalculateSymmKeyCK (int index);
|
||||
void CalculateSymmKeyCK (int index, uint8_t * key);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -51,6 +52,8 @@ namespace garlic
|
|||
eECIESx25519BlkTermination = 4,
|
||||
eECIESx25519BlkOptions = 5,
|
||||
eECIESx25519BlkNextSessionKey = 7,
|
||||
eECIESx25519BlkAck = 8,
|
||||
eECIESx25519BlkAckRequest = 9,
|
||||
eECIESx25519BlkGalicClove = 11,
|
||||
eECIESx25519BlkPadding = 254
|
||||
};
|
||||
|
@ -85,7 +88,7 @@ namespace garlic
|
|||
if (!m_Destination) m_Destination.reset (new i2p::data::IdentHash (dest));
|
||||
}
|
||||
|
||||
bool IsExpired (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_EXPIRATION_TIMEOUT; }
|
||||
bool CheckExpired (uint64_t ts); // true is expired
|
||||
bool CanBeRestarted (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_RESTART_TIMEOUT; }
|
||||
|
||||
private:
|
||||
|
@ -99,7 +102,7 @@ namespace garlic
|
|||
bool HandleNewIncomingSession (const uint8_t * buf, size_t len);
|
||||
bool HandleNewOutgoingSessionReply (const uint8_t * buf, size_t len);
|
||||
bool HandleExistingSessionMessage (const uint8_t * buf, size_t len, int index);
|
||||
void HandlePayload (const uint8_t * buf, size_t len);
|
||||
void HandlePayload (const uint8_t * buf, size_t len, int index = 0);
|
||||
|
||||
bool NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
|
||||
bool NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
|
||||
|
@ -107,6 +110,7 @@ namespace garlic
|
|||
|
||||
std::vector<uint8_t> CreatePayload (std::shared_ptr<const I2NPMessage> msg);
|
||||
size_t CreateGarlicClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len, bool isDestination = false);
|
||||
size_t CreateDeliveryStatusClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len);
|
||||
|
||||
void GenerateMoreReceiveTags (int numTags);
|
||||
|
||||
|
@ -118,8 +122,8 @@ namespace garlic
|
|||
SessionState m_State = eSessionStateNew;
|
||||
uint64_t m_LastActivityTimestamp = 0; // incoming
|
||||
RatchetTagSet m_SendTagset, m_ReceiveTagset;
|
||||
int m_NumReceiveTags = 0;
|
||||
std::unique_ptr<i2p::data::IdentHash> m_Destination;// TODO: might not need it
|
||||
std::list<std::pair<uint16_t, int> > m_AckRequests; // (key_id, indeX)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
#include "Event.h"
|
||||
#include "Log.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace event
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
EventCore core;
|
||||
#endif
|
||||
|
||||
void EventCore::SetListener(EventListener * l)
|
||||
{
|
||||
m_listener = l;
|
||||
LogPrint(eLogInfo, "Event: listener set");
|
||||
}
|
||||
|
||||
void EventCore::QueueEvent(const EventType & ev)
|
||||
{
|
||||
if(m_listener) m_listener->HandleEvent(ev);
|
||||
}
|
||||
|
||||
void EventCore::CollectEvent(const std::string & type, const std::string & ident, uint64_t val)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_collect_mutex);
|
||||
std::string key = type + "." + ident;
|
||||
if (m_collected.find(key) == m_collected.end())
|
||||
{
|
||||
m_collected[key] = {type, key, 0};
|
||||
}
|
||||
m_collected[key].Val += val;
|
||||
}
|
||||
|
||||
void EventCore::PumpCollected(EventListener * listener)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_collect_mutex);
|
||||
if(listener)
|
||||
{
|
||||
for(const auto & ev : m_collected) {
|
||||
listener->HandlePumpEvent({{"type", ev.second.Key}, {"ident", ev.second.Ident}}, ev.second.Val);
|
||||
}
|
||||
}
|
||||
m_collected.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QueueIntEvent(const std::string & type, const std::string & ident, uint64_t val)
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
i2p::event::core.CollectEvent(type, ident, val);
|
||||
#endif
|
||||
}
|
||||
|
||||
void EmitEvent(const EventType & e)
|
||||
{
|
||||
#if WITH_EVENTS
|
||||
i2p::event::core.QueueEvent(e);
|
||||
#endif
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
#ifndef EVENT_H__
|
||||
#define EVENT_H__
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <tuple>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
typedef std::map<std::string, std::string> EventType;
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace event
|
||||
{
|
||||
class EventListener {
|
||||
public:
|
||||
virtual ~EventListener() {};
|
||||
virtual void HandleEvent(const EventType & ev) = 0;
|
||||
/** @brief handle collected event when pumped */
|
||||
virtual void HandlePumpEvent(const EventType & ev, const uint64_t & val) = 0;
|
||||
};
|
||||
|
||||
class EventCore
|
||||
{
|
||||
public:
|
||||
void QueueEvent(const EventType & ev);
|
||||
void CollectEvent(const std::string & type, const std::string & ident, uint64_t val);
|
||||
void SetListener(EventListener * l);
|
||||
void PumpCollected(EventListener * l);
|
||||
|
||||
private:
|
||||
std::mutex m_collect_mutex;
|
||||
struct CollectedEvent
|
||||
{
|
||||
std::string Key;
|
||||
std::string Ident;
|
||||
uint64_t Val;
|
||||
};
|
||||
std::map<std::string, CollectedEvent> m_collected;
|
||||
EventListener * m_listener = nullptr;
|
||||
};
|
||||
#ifdef WITH_EVENTS
|
||||
extern EventCore core;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void QueueIntEvent(const std::string & type, const std::string & ident, uint64_t val);
|
||||
void EmitEvent(const EventType & ev);
|
||||
|
||||
#endif
|
|
@ -58,6 +58,44 @@ namespace garlic
|
|||
m_SharedRoutingPath = path;
|
||||
}
|
||||
|
||||
bool GarlicRoutingSession::MessageConfirmed (uint32_t msgID)
|
||||
{
|
||||
if (msgID == GetLeaseSetUpdateMsgID ())
|
||||
{
|
||||
SetLeaseSetUpdateStatus (eLeaseSetUpToDate);
|
||||
SetLeaseSetUpdateMsgID (0);
|
||||
LogPrint (eLogInfo, "Garlic: LeaseSet update confirmed");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GarlicRoutingSession::CleanupUnconfirmedLeaseSet (uint64_t ts)
|
||||
{
|
||||
if (m_LeaseSetUpdateMsgID && ts*1000LL > m_LeaseSetSubmissionTime + LEASET_CONFIRMATION_TIMEOUT)
|
||||
{
|
||||
if (GetOwner ())
|
||||
GetOwner ()->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID);
|
||||
m_LeaseSetUpdateMsgID = 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> GarlicRoutingSession::CreateEncryptedDeliveryStatusMsg (uint32_t msgID)
|
||||
{
|
||||
auto msg = CreateDeliveryStatusMsg (msgID);
|
||||
if (GetOwner ())
|
||||
{
|
||||
//encrypt
|
||||
uint8_t key[32], tag[32];
|
||||
RAND_bytes (key, 32); // random session key
|
||||
RAND_bytes (tag, 32); // random session tag
|
||||
GetOwner ()->SubmitSessionKey (key, tag);
|
||||
ElGamalAESSession garlic (key, tag);
|
||||
msg = garlic.WrapSingleMessage (msg);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
ElGamalAESSession::ElGamalAESSession (GarlicDestination * owner,
|
||||
std::shared_ptr<const i2p::data::RoutingDestination> destination, int numTags, bool attachLeaseSet):
|
||||
GarlicRoutingSession (owner, attachLeaseSet),
|
||||
|
@ -289,19 +327,12 @@ namespace garlic
|
|||
htobe32buf (buf + size, inboundTunnel->GetNextTunnelID ()); // tunnelID
|
||||
size += 4;
|
||||
// create msg
|
||||
auto msg = CreateDeliveryStatusMsg (msgID);
|
||||
if (GetOwner ())
|
||||
auto msg = CreateEncryptedDeliveryStatusMsg (msgID);
|
||||
if (msg)
|
||||
{
|
||||
//encrypt
|
||||
uint8_t key[32], tag[32];
|
||||
RAND_bytes (key, 32); // random session key
|
||||
RAND_bytes (tag, 32); // random session tag
|
||||
GetOwner ()->SubmitSessionKey (key, tag);
|
||||
ElGamalAESSession garlic (key, tag);
|
||||
msg = garlic.WrapSingleMessage (msg);
|
||||
memcpy (buf + size, msg->GetBuffer (), msg->GetLength ());
|
||||
size += msg->GetLength ();
|
||||
}
|
||||
memcpy (buf + size, msg->GetBuffer (), msg->GetLength ());
|
||||
size += msg->GetLength ();
|
||||
// fill clove
|
||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 8000; // 8 sec
|
||||
uint32_t cloveID;
|
||||
|
@ -334,17 +365,12 @@ namespace garlic
|
|||
return tags;
|
||||
}
|
||||
|
||||
void ElGamalAESSession::MessageConfirmed (uint32_t msgID)
|
||||
bool ElGamalAESSession::MessageConfirmed (uint32_t msgID)
|
||||
{
|
||||
TagsConfirmed (msgID);
|
||||
if (msgID == GetLeaseSetUpdateMsgID ())
|
||||
{
|
||||
SetLeaseSetUpdateStatus (eLeaseSetUpToDate);
|
||||
SetLeaseSetUpdateMsgID (0);
|
||||
LogPrint (eLogInfo, "Garlic: LeaseSet update confirmed");
|
||||
}
|
||||
else
|
||||
if (!GarlicRoutingSession::MessageConfirmed (msgID))
|
||||
CleanupExpiredTags ();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ElGamalAESSession::TagsConfirmed (uint32_t msgID)
|
||||
|
@ -374,12 +400,7 @@ namespace garlic
|
|||
++it;
|
||||
}
|
||||
CleanupUnconfirmedTags ();
|
||||
if (GetLeaseSetUpdateMsgID () && ts*1000LL > GetLeaseSetSubmissionTime () + LEASET_CONFIRMATION_TIMEOUT)
|
||||
{
|
||||
if (GetOwner ())
|
||||
GetOwner ()->RemoveDeliveryStatusSession (GetLeaseSetUpdateMsgID ());
|
||||
SetLeaseSetUpdateMsgID (0);
|
||||
}
|
||||
CleanupUnconfirmedLeaseSet (ts);
|
||||
return !m_SessionTags.empty () || !m_UnconfirmedTagsMsgs.empty ();
|
||||
}
|
||||
|
||||
|
@ -467,7 +488,7 @@ namespace garlic
|
|||
else
|
||||
{
|
||||
// tag not found. Handle depending on encryption type
|
||||
if (GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET)
|
||||
if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET))
|
||||
{
|
||||
HandleECIESx25519 (buf, length);
|
||||
return;
|
||||
|
@ -659,7 +680,7 @@ namespace garlic
|
|||
std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet)
|
||||
{
|
||||
if (destination->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET &&
|
||||
GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET)
|
||||
SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET))
|
||||
{
|
||||
ECIESX25519AEADRatchetSessionPtr session;
|
||||
uint8_t staticKey[32];
|
||||
|
@ -751,7 +772,7 @@ namespace garlic
|
|||
|
||||
for (auto it = m_ECIESx25519Sessions.begin (); it != m_ECIESx25519Sessions.end ();)
|
||||
{
|
||||
if (it->second->IsExpired (ts))
|
||||
if (it->second->CheckExpired (ts))
|
||||
{
|
||||
it->second->SetOwner (nullptr);
|
||||
it = m_ECIESx25519Sessions.erase (it);
|
||||
|
@ -767,7 +788,7 @@ namespace garlic
|
|||
m_DeliveryStatusSessions.erase (msgID);
|
||||
}
|
||||
|
||||
void GarlicDestination::DeliveryStatusSent (ElGamalAESSessionPtr session, uint32_t msgID)
|
||||
void GarlicDestination::DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_DeliveryStatusSessionsMutex);
|
||||
m_DeliveryStatusSessions[msgID] = session;
|
||||
|
@ -775,7 +796,7 @@ namespace garlic
|
|||
|
||||
void GarlicDestination::HandleDeliveryStatusMessage (uint32_t msgID)
|
||||
{
|
||||
ElGamalAESSessionPtr session;
|
||||
GarlicRoutingSessionPtr session;
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_DeliveryStatusSessionsMutex);
|
||||
auto it = m_DeliveryStatusSessions.find (msgID);
|
||||
|
@ -794,8 +815,12 @@ namespace garlic
|
|||
|
||||
void GarlicDestination::SetLeaseSetUpdated ()
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
||||
for (auto& it: m_Sessions)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
||||
for (auto& it: m_Sessions)
|
||||
it.second->SetLeaseSetUpdated ();
|
||||
}
|
||||
for (auto& it: m_ECIESx25519Sessions)
|
||||
it.second->SetLeaseSetUpdated ();
|
||||
}
|
||||
|
||||
|
@ -865,7 +890,7 @@ namespace garlic
|
|||
m_Tags.insert (std::make_pair (SessionTag (tag, ts), decryption));
|
||||
}
|
||||
if (!m_Tags.empty ())
|
||||
LogPrint (eLogInfo, m_Tags.size (), " loaded for ", ident);
|
||||
LogPrint (eLogInfo, "Garlic: ", m_Tags.size (), " tags loaded for ", ident);
|
||||
}
|
||||
}
|
||||
i2p::fs::Remove (path);
|
||||
|
@ -911,7 +936,10 @@ namespace garlic
|
|||
case eGarlicDeliveryTypeDestination:
|
||||
LogPrint (eLogDebug, "Garlic: type destination");
|
||||
buf += 32; // TODO: check destination
|
||||
// no break here
|
||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
[[fallthrough]];
|
||||
#endif
|
||||
// no break here
|
||||
case eGarlicDeliveryTypeLocal:
|
||||
{
|
||||
LogPrint (eLogDebug, "Garlic: type local");
|
||||
|
|
|
@ -104,6 +104,7 @@ namespace garlic
|
|||
virtual ~GarlicRoutingSession ();
|
||||
virtual std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg) = 0;
|
||||
virtual bool CleanupUnconfirmedTags () { return false; }; // for I2CP, override in ElGamalAESSession
|
||||
virtual bool MessageConfirmed (uint32_t msgID);
|
||||
|
||||
void SetLeaseSetUpdated ()
|
||||
{
|
||||
|
@ -112,6 +113,7 @@ namespace garlic
|
|||
bool IsLeaseSetNonConfirmed () const { return m_LeaseSetUpdateStatus == eLeaseSetSubmitted; };
|
||||
bool IsLeaseSetUpdated () const { return m_LeaseSetUpdateStatus == eLeaseSetUpdated; };
|
||||
uint64_t GetLeaseSetSubmissionTime () const { return m_LeaseSetSubmissionTime; }
|
||||
void CleanupUnconfirmedLeaseSet (uint64_t ts);
|
||||
|
||||
std::shared_ptr<GarlicRoutingPath> GetSharedRoutingPath ();
|
||||
void SetSharedRoutingPath (std::shared_ptr<GarlicRoutingPath> path);
|
||||
|
@ -127,6 +129,8 @@ namespace garlic
|
|||
void SetLeaseSetUpdateMsgID (uint32_t msgID) { m_LeaseSetUpdateMsgID = msgID; }
|
||||
void SetLeaseSetSubmissionTime (uint64_t ts) { m_LeaseSetSubmissionTime = ts; }
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateEncryptedDeliveryStatusMsg (uint32_t msgID);
|
||||
|
||||
private:
|
||||
|
||||
GarlicDestination * m_Owner;
|
||||
|
@ -165,7 +169,7 @@ namespace garlic
|
|||
|
||||
std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg);
|
||||
|
||||
void MessageConfirmed (uint32_t msgID);
|
||||
bool MessageConfirmed (uint32_t msgID);
|
||||
bool CleanupExpiredTags (); // returns true if something left
|
||||
bool CleanupUnconfirmedTags (); // returns true if something has been deleted
|
||||
|
||||
|
@ -223,7 +227,7 @@ namespace garlic
|
|||
|
||||
void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag
|
||||
virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread
|
||||
void DeliveryStatusSent (ElGamalAESSessionPtr session, uint32_t msgID);
|
||||
void DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID);
|
||||
void AddECIESx25519SessionTag (int index, uint64_t tag, ECIESX25519AEADRatchetSessionPtr session);
|
||||
void AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session);
|
||||
void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len);
|
||||
|
@ -267,7 +271,7 @@ namespace garlic
|
|||
std::unordered_map<uint64_t, ECIESX25519AEADRatchetIndexSession> m_ECIESx25519Tags; // session tag -> session
|
||||
// DeliveryStatus
|
||||
std::mutex m_DeliveryStatusSessionsMutex;
|
||||
std::unordered_map<uint32_t, ElGamalAESSessionPtr> m_DeliveryStatusSessions; // msgID -> session
|
||||
std::unordered_map<uint32_t, GarlicRoutingSessionPtr> m_DeliveryStatusSessions; // msgID -> session
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
@ -723,7 +723,10 @@ namespace data
|
|||
case SIGNING_KEY_TYPE_RSA_SHA384_3072:
|
||||
case SIGNING_KEY_TYPE_RSA_SHA512_4096:
|
||||
LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Creating EdDSA");
|
||||
// no break here
|
||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
[[fallthrough]];
|
||||
#endif
|
||||
// no break here
|
||||
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
|
||||
i2p::crypto::CreateEDDSA25519RandomKeys (priv, pub);
|
||||
break;
|
||||
|
|
|
@ -228,8 +228,8 @@ namespace data
|
|||
virtual std::shared_ptr<const IdentityEx> GetIdentity () const = 0;
|
||||
|
||||
const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); };
|
||||
virtual CryptoKeyType GetEncryptionType () const { return GetIdentity ()->GetCryptoKeyType (); }; // override for LeaseSet
|
||||
virtual const uint8_t * GetEncryptionPublicKey () const { return GetIdentity ()->GetEncryptionPublicKey (); }; // override for LeaseSet
|
||||
virtual bool SupportsEncryptionType (CryptoKeyType keyType) const { return GetIdentity ()->GetCryptoKeyType () == keyType; }; // override for LeaseSet
|
||||
virtual const uint8_t * GetEncryptionPublicKey (CryptoKeyType keyType) const { return GetIdentity ()->GetEncryptionPublicKey (); }; // override for LeaseSet
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -159,7 +159,7 @@ namespace data
|
|||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "LeaseSet: Lease is expired already ");
|
||||
LogPrint (eLogWarning, "LeaseSet: Lease is expired already");
|
||||
}
|
||||
|
||||
uint64_t LeaseSet::ExtractTimestamp (const uint8_t * buf, size_t len) const
|
||||
|
@ -251,6 +251,13 @@ namespace data
|
|||
memcpy (m_Buffer, buf, len);
|
||||
}
|
||||
|
||||
void LeaseSet::SetBufferLen (size_t len)
|
||||
{
|
||||
if (len <= m_BufferLen) m_BufferLen = len;
|
||||
else
|
||||
LogPrint (eLogError, "LeaseSet2: actual buffer size ", len , " exceeds full buffer size ", m_BufferLen);
|
||||
}
|
||||
|
||||
LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases, CryptoKeyType preferredCrypto):
|
||||
LeaseSet (storeLeases), m_StoreType (storeType), m_EncryptionType (preferredCrypto)
|
||||
{
|
||||
|
@ -331,6 +338,8 @@ namespace data
|
|||
VerifySignature (identity, buf, len, offset);
|
||||
SetIsValid (verified);
|
||||
}
|
||||
offset += m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : identity->GetSignatureLen ();
|
||||
SetBufferLen (offset);
|
||||
}
|
||||
|
||||
template<typename Verifier>
|
||||
|
@ -537,6 +546,12 @@ namespace data
|
|||
else
|
||||
LogPrint (eLogError, "LeaseSet2: unexpected LeaseSet type ", (int)innerPlainText[0], " inside encrypted LeaseSet");
|
||||
}
|
||||
else
|
||||
{
|
||||
// we set actual length of encrypted buffer
|
||||
offset += m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : blindedVerifier->GetSignatureLen ();
|
||||
SetBufferLen (offset);
|
||||
}
|
||||
}
|
||||
|
||||
// helper for ExtractClientAuthData
|
||||
|
@ -748,7 +763,7 @@ namespace data
|
|||
}
|
||||
|
||||
LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
|
||||
uint16_t keyType, uint16_t keyLen, const uint8_t * encryptionPublicKey,
|
||||
const KeySections& encryptionKeys,
|
||||
std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels,
|
||||
bool isPublic, bool isPublishedEncrypted):
|
||||
LocalLeaseSet (keys.GetPublic (), nullptr, 0)
|
||||
|
@ -757,8 +772,11 @@ namespace data
|
|||
// assume standard LS2
|
||||
int num = tunnels.size ();
|
||||
if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES;
|
||||
size_t keySectionsLen = 0;
|
||||
for (const auto& it: encryptionKeys)
|
||||
keySectionsLen += 2/*key type*/ + 2/*key len*/ + it.keyLen/*key*/;
|
||||
m_BufferLen = identity->GetFullLen () + 4/*published*/ + 2/*expires*/ + 2/*flag*/ + 2/*properties len*/ +
|
||||
1/*num keys*/ + 2/*key type*/ + 2/*key len*/ + keyLen/*key*/ + 1/*num leases*/ + num*LEASE2_SIZE + keys.GetSignatureLen ();
|
||||
1/*num keys*/ + keySectionsLen + 1/*num leases*/ + num*LEASE2_SIZE + keys.GetSignatureLen ();
|
||||
uint16_t flags = 0;
|
||||
if (keys.IsOfflineSignature ())
|
||||
{
|
||||
|
@ -789,10 +807,13 @@ namespace data
|
|||
}
|
||||
htobe16buf (m_Buffer + offset, 0); offset += 2; // properties len
|
||||
// keys
|
||||
m_Buffer[offset] = 1; offset++; // 1 key
|
||||
htobe16buf (m_Buffer + offset, keyType); offset += 2; // key type
|
||||
htobe16buf (m_Buffer + offset, keyLen); offset += 2; // key len
|
||||
memcpy (m_Buffer + offset, encryptionPublicKey, keyLen); offset += keyLen; // key
|
||||
m_Buffer[offset] = encryptionKeys.size (); offset++; // 1 key
|
||||
for (const auto& it: encryptionKeys)
|
||||
{
|
||||
htobe16buf (m_Buffer + offset, it.keyType); offset += 2; // key type
|
||||
htobe16buf (m_Buffer + offset, it.keyLen); offset += 2; // key len
|
||||
memcpy (m_Buffer + offset, it.encryptionPublicKey, it.keyLen); offset += it.keyLen; // key
|
||||
}
|
||||
// leases
|
||||
uint32_t expirationTime = 0; // in seconds
|
||||
m_Buffer[offset] = num; offset++; // num leases
|
||||
|
|
|
@ -97,6 +97,7 @@ namespace data
|
|||
// called from LeaseSet2
|
||||
LeaseSet (bool storeLeases);
|
||||
void SetBuffer (const uint8_t * buf, size_t len);
|
||||
void SetBufferLen (size_t len);
|
||||
void SetIdentity (std::shared_ptr<const IdentityEx> identity) { m_Identity = identity; };
|
||||
void SetExpirationTime (uint64_t t) { m_ExpirationTime = t; };
|
||||
void SetIsValid (bool isValid) { m_IsValid = isValid; };
|
||||
|
@ -231,8 +232,15 @@ namespace data
|
|||
{
|
||||
public:
|
||||
|
||||
struct KeySection
|
||||
{
|
||||
uint16_t keyType, keyLen;
|
||||
const uint8_t * encryptionPublicKey;
|
||||
};
|
||||
typedef std::vector<KeySection> KeySections;
|
||||
|
||||
LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
|
||||
uint16_t keyType, uint16_t keyLen, const uint8_t * encryptionPublicKey,
|
||||
const KeySections& encryptionKeys,
|
||||
std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels,
|
||||
bool isPublic, bool isPublishedEncrypted = false);
|
||||
LocalLeaseSet2 (uint8_t storeType, std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len); // from I2CP
|
||||
|
|
|
@ -161,6 +161,7 @@ void LogPrint (std::stringstream& s, TValue&& arg) noexcept
|
|||
s << std::forward<TValue>(arg);
|
||||
}
|
||||
|
||||
#if (__cplusplus < 201703L) // below C++ 17
|
||||
/** internal usage only -- folding args array to single string */
|
||||
template<typename TValue, typename... TArgs>
|
||||
void LogPrint (std::stringstream& s, TValue&& arg, TArgs&&... args) noexcept
|
||||
|
@ -168,6 +169,7 @@ void LogPrint (std::stringstream& s, TValue&& arg, TArgs&&... args) noexcept
|
|||
LogPrint (s, std::forward<TValue>(arg));
|
||||
LogPrint (s, std::forward<TArgs>(args)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Create log message and send it to queue
|
||||
|
@ -184,7 +186,11 @@ void LogPrint (LogLevel level, TArgs&&... args) noexcept
|
|||
// fold message to single string
|
||||
std::stringstream ss("");
|
||||
|
||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
(LogPrint (ss, std::forward<TArgs>(args)), ...);
|
||||
#else
|
||||
LogPrint (ss, std::forward<TArgs>(args)...);
|
||||
#endif
|
||||
|
||||
auto msg = std::make_shared<i2p::log::LogMsg>(level, std::time(nullptr), ss.str());
|
||||
msg->tid = std::this_thread::get_id();
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include "Transports.h"
|
||||
#include "NetDb.hpp"
|
||||
#include "NTCP2.h"
|
||||
#include "HTTP.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
|
@ -1141,8 +1143,8 @@ namespace transport
|
|||
}
|
||||
|
||||
NTCP2Server::NTCP2Server ():
|
||||
RunnableServiceWithWork ("NTCP2"),
|
||||
m_TerminationTimer (GetService ())
|
||||
RunnableServiceWithWork ("NTCP2"), m_TerminationTimer (GetService ()),
|
||||
m_Resolver(GetService ())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1156,45 +1158,67 @@ namespace transport
|
|||
if (!IsRunning ())
|
||||
{
|
||||
StartIOService ();
|
||||
auto& addresses = context.GetRouterInfo ().GetAddresses ();
|
||||
for (const auto& address: addresses)
|
||||
if(UsingProxy())
|
||||
{
|
||||
if (!address) continue;
|
||||
if (address->IsPublishedNTCP2 ())
|
||||
LogPrint(eLogError, "NTCP2: USING PROXY ");
|
||||
// TODO: resolve proxy until it is resolved
|
||||
boost::asio::ip::tcp::resolver::query q(m_ProxyAddress, std::to_string(m_ProxyPort));
|
||||
boost::system::error_code e;
|
||||
auto itr = m_Resolver.resolve(q, e);
|
||||
if(e)
|
||||
{
|
||||
if (address->host.is_v4())
|
||||
LogPrint(eLogError, "NTCP2: Failed to resolve proxy ", e.message());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ProxyEndpoint.reset (new boost::asio::ip::tcp::endpoint(*itr));
|
||||
if (m_ProxyEndpoint)
|
||||
LogPrint(eLogError, "NTCP2: m_ProxyEndpoint ", *m_ProxyEndpoint);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint(eLogError, "NTCP2: NOTUSING PROXY ");
|
||||
auto& addresses = context.GetRouterInfo ().GetAddresses ();
|
||||
for (const auto& address: addresses)
|
||||
{
|
||||
if (!address) continue;
|
||||
if (address->IsPublishedNTCP2 ())
|
||||
{
|
||||
try
|
||||
if (address->host.is_v4())
|
||||
{
|
||||
m_NTCP2Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port)));
|
||||
}
|
||||
catch ( std::exception & ex )
|
||||
{
|
||||
LogPrint(eLogError, "NTCP2: Failed to bind to ip4 port ",address->port, ex.what());
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
m_NTCP2Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port)));
|
||||
}
|
||||
catch ( std::exception & ex )
|
||||
{
|
||||
LogPrint(eLogError, "NTCP2: Failed to bind to ip4 port ",address->port, ex.what());
|
||||
continue;
|
||||
}
|
||||
|
||||
LogPrint (eLogInfo, "NTCP2: Start listening TCP port ", address->port);
|
||||
auto conn = std::make_shared<NTCP2Session>(*this);
|
||||
m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this, conn, std::placeholders::_1));
|
||||
}
|
||||
else if (address->host.is_v6() && context.SupportsV6 ())
|
||||
{
|
||||
m_NTCP2V6Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService ()));
|
||||
try
|
||||
LogPrint (eLogInfo, "NTCP2: Start listening TCP port ", address->port);
|
||||
auto conn = std::make_shared<NTCP2Session>(*this);
|
||||
m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this, conn, std::placeholders::_1));
|
||||
}
|
||||
else if (address->host.is_v6() && context.SupportsV6 ())
|
||||
{
|
||||
m_NTCP2V6Acceptor->open (boost::asio::ip::tcp::v6());
|
||||
m_NTCP2V6Acceptor->set_option (boost::asio::ip::v6_only (true));
|
||||
m_NTCP2V6Acceptor->set_option (boost::asio::socket_base::reuse_address (true));
|
||||
m_NTCP2V6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port));
|
||||
m_NTCP2V6Acceptor->listen ();
|
||||
m_NTCP2V6Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService ()));
|
||||
try
|
||||
{
|
||||
m_NTCP2V6Acceptor->open (boost::asio::ip::tcp::v6());
|
||||
m_NTCP2V6Acceptor->set_option (boost::asio::ip::v6_only (true));
|
||||
m_NTCP2V6Acceptor->set_option (boost::asio::socket_base::reuse_address (true));
|
||||
m_NTCP2V6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port));
|
||||
m_NTCP2V6Acceptor->listen ();
|
||||
|
||||
LogPrint (eLogInfo, "NTCP2: Start listening V6 TCP port ", address->port);
|
||||
auto conn = std::make_shared<NTCP2Session> (*this);
|
||||
m_NTCP2V6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAcceptV6, this, conn, std::placeholders::_1));
|
||||
} catch ( std::exception & ex ) {
|
||||
LogPrint(eLogError, "NTCP2: failed to bind to ip6 port ", address->port);
|
||||
continue;
|
||||
LogPrint (eLogInfo, "NTCP2: Start listening V6 TCP port ", address->port);
|
||||
auto conn = std::make_shared<NTCP2Session> (*this);
|
||||
m_NTCP2V6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAcceptV6, this, conn, std::placeholders::_1));
|
||||
} catch ( std::exception & ex ) {
|
||||
LogPrint(eLogError, "NTCP2: failed to bind to ip6 port ", address->port);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1216,7 +1240,10 @@ namespace transport
|
|||
m_NTCP2Sessions.clear ();
|
||||
|
||||
if (IsRunning ())
|
||||
{
|
||||
m_TerminationTimer.cancel ();
|
||||
m_ProxyEndpoint = nullptr;
|
||||
}
|
||||
StopIOService ();
|
||||
}
|
||||
|
||||
|
@ -1389,6 +1416,231 @@ namespace transport
|
|||
ScheduleTermination ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NTCP2Server::UseProxy(ProxyType proxytype, const std::string & addr, uint16_t port)
|
||||
{
|
||||
m_ProxyType = proxytype;
|
||||
m_ProxyAddress = addr;
|
||||
m_ProxyPort = port;
|
||||
}
|
||||
|
||||
void NTCP2Server::HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer, const std::string & host, uint16_t port, RemoteAddressType addrtype)
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint(eLogWarning, "NTCP2: failed to connect to proxy ", ecode.message());
|
||||
timer->cancel();
|
||||
conn->Terminate();
|
||||
return;
|
||||
}
|
||||
switch (m_ProxyType)
|
||||
{
|
||||
case eSocksProxy:
|
||||
{
|
||||
// TODO: support username/password auth etc
|
||||
static const uint8_t buff[3] = {0x05, 0x01, 0x00};
|
||||
boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, 3), boost::asio::transfer_all(),
|
||||
[] (const boost::system::error_code & ec, std::size_t transferred)
|
||||
{
|
||||
(void) transferred;
|
||||
if(ec)
|
||||
{
|
||||
LogPrint(eLogWarning, "NTCP2: socks5 write error ", ec.message());
|
||||
}
|
||||
});
|
||||
auto readbuff = std::make_shared<std::vector<uint8_t> >(2);
|
||||
boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), 2),
|
||||
[this, readbuff, timer, conn, host, port, addrtype](const boost::system::error_code & ec, std::size_t transferred)
|
||||
{
|
||||
if(ec)
|
||||
{
|
||||
LogPrint(eLogError, "NTCP2: socks5 read error ", ec.message());
|
||||
timer->cancel();
|
||||
conn->Terminate();
|
||||
return;
|
||||
}
|
||||
else if(transferred == 2)
|
||||
{
|
||||
if((*readbuff)[1] == 0x00)
|
||||
{
|
||||
AfterSocksHandshake(conn, timer, host, port, addrtype);
|
||||
return;
|
||||
}
|
||||
else if ((*readbuff)[1] == 0xff)
|
||||
{
|
||||
LogPrint(eLogError, "NTCP2: socks5 proxy rejected authentication");
|
||||
timer->cancel();
|
||||
conn->Terminate();
|
||||
return;
|
||||
}
|
||||
LogPrint(eLogError, "NTCP2:", (int)(*readbuff)[1]);
|
||||
}
|
||||
LogPrint(eLogError, "NTCP2: socks5 server gave invalid response");
|
||||
timer->cancel();
|
||||
conn->Terminate();
|
||||
});
|
||||
break;
|
||||
}
|
||||
case eHTTPProxy:
|
||||
{
|
||||
i2p::http::HTTPReq req;
|
||||
req.method = "CONNECT";
|
||||
req.version ="HTTP/1.1";
|
||||
if(addrtype == eIP6Address)
|
||||
req.uri = "[" + host + "]:" + std::to_string(port);
|
||||
else
|
||||
req.uri = host + ":" + std::to_string(port);
|
||||
|
||||
boost::asio::streambuf writebuff;
|
||||
std::ostream out(&writebuff);
|
||||
out << req.to_string();
|
||||
|
||||
boost::asio::async_write(conn->GetSocket(), writebuff.data(), boost::asio::transfer_all(),
|
||||
[](const boost::system::error_code & ec, std::size_t transferred)
|
||||
{
|
||||
(void) transferred;
|
||||
if(ec)
|
||||
LogPrint(eLogError, "NTCP2: http proxy write error ", ec.message());
|
||||
});
|
||||
|
||||
boost::asio::streambuf * readbuff = new boost::asio::streambuf;
|
||||
boost::asio::async_read_until(conn->GetSocket(), *readbuff, "\r\n\r\n",
|
||||
[this, readbuff, timer, conn] (const boost::system::error_code & ec, std::size_t transferred)
|
||||
{
|
||||
if(ec)
|
||||
{
|
||||
LogPrint(eLogError, "NTCP2: http proxy read error ", ec.message());
|
||||
timer->cancel();
|
||||
conn->Terminate();
|
||||
}
|
||||
else
|
||||
{
|
||||
readbuff->commit(transferred);
|
||||
i2p::http::HTTPRes res;
|
||||
if(res.parse(boost::asio::buffer_cast<const char*>(readbuff->data()), readbuff->size()) > 0)
|
||||
{
|
||||
if(res.code == 200)
|
||||
{
|
||||
timer->cancel();
|
||||
conn->ClientLogin();
|
||||
delete readbuff;
|
||||
return;
|
||||
}
|
||||
else
|
||||
LogPrint(eLogError, "NTCP2: http proxy rejected request ", res.code);
|
||||
}
|
||||
else
|
||||
LogPrint(eLogError, "NTCP2: http proxy gave malformed response");
|
||||
timer->cancel();
|
||||
conn->Terminate();
|
||||
delete readbuff;
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogPrint(eLogError, "NTCP2: unknown proxy type, invalid state");
|
||||
}
|
||||
}
|
||||
|
||||
void NTCP2Server::ConnectWithProxy (const std::string& host, uint16_t port, RemoteAddressType addrtype, std::shared_ptr<NTCP2Session> conn)
|
||||
{
|
||||
if(!m_ProxyEndpoint) return;
|
||||
GetService().post([this, host, port, addrtype, conn]() {
|
||||
if (this->AddNTCP2Session (conn))
|
||||
{
|
||||
|
||||
auto timer = std::make_shared<boost::asio::deadline_timer>(GetService());
|
||||
auto timeout = NTCP_CONNECT_TIMEOUT * 5;
|
||||
conn->SetTerminationTimeout(timeout * 2);
|
||||
timer->expires_from_now (boost::posix_time::seconds(timeout));
|
||||
timer->async_wait ([conn, timeout](const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds");
|
||||
i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true);
|
||||
conn->Terminate ();
|
||||
}
|
||||
});
|
||||
conn->GetSocket ().async_connect (*m_ProxyEndpoint, std::bind (&NTCP2Server::HandleProxyConnect, this, std::placeholders::_1, conn, timer, host, port, addrtype));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NTCP2Server::AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer, const std::string & host, uint16_t port, RemoteAddressType addrtype)
|
||||
{
|
||||
// build request
|
||||
size_t sz = 0;
|
||||
auto buff = std::make_shared<std::vector<int8_t> >(256);
|
||||
auto readbuff = std::make_shared<std::vector<int8_t> >(256);
|
||||
(*buff)[0] = 0x05;
|
||||
(*buff)[1] = 0x01;
|
||||
(*buff)[2] = 0x00;
|
||||
|
||||
if(addrtype == eIP4Address)
|
||||
{
|
||||
(*buff)[3] = 0x01;
|
||||
auto addr = boost::asio::ip::address::from_string(host).to_v4();
|
||||
auto addrbytes = addr.to_bytes();
|
||||
auto addrsize = addrbytes.size();
|
||||
memcpy(buff->data () + 4, addrbytes.data(), addrsize);
|
||||
}
|
||||
else if (addrtype == eIP6Address)
|
||||
{
|
||||
(*buff)[3] = 0x04;
|
||||
auto addr = boost::asio::ip::address::from_string(host).to_v6();
|
||||
auto addrbytes = addr.to_bytes();
|
||||
auto addrsize = addrbytes.size();
|
||||
memcpy(buff->data () + 4, addrbytes.data(), addrsize);
|
||||
}
|
||||
else if (addrtype == eHostname)
|
||||
{
|
||||
(*buff)[3] = 0x03;
|
||||
size_t addrsize = host.size();
|
||||
sz = addrsize + 1 + 4;
|
||||
if (2 + sz > buff->size ())
|
||||
{
|
||||
// too big
|
||||
return;
|
||||
}
|
||||
(*buff)[4] = (uint8_t) addrsize;
|
||||
memcpy(buff->data() + 5, host.c_str(), addrsize);
|
||||
}
|
||||
htobe16buf(buff->data () + sz, port);
|
||||
sz += 2;
|
||||
boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff->data (), sz), boost::asio::transfer_all(),
|
||||
[](const boost::system::error_code & ec, std::size_t written)
|
||||
{
|
||||
if(ec)
|
||||
{
|
||||
LogPrint(eLogError, "NTCP2: failed to write handshake to socks proxy ", ec.message());
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), 10),
|
||||
[timer, conn, sz, readbuff](const boost::system::error_code & e, std::size_t transferred)
|
||||
{
|
||||
if(e)
|
||||
{
|
||||
LogPrint(eLogError, "NTCP2: socks proxy read error ", e.message());
|
||||
}
|
||||
else if(transferred == sz)
|
||||
{
|
||||
if((*readbuff)[1] == 0x00)
|
||||
{
|
||||
timer->cancel();
|
||||
conn->ClientLogin();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!e)
|
||||
i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true);
|
||||
timer->cancel();
|
||||
conn->Terminate();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,6 +126,7 @@ namespace transport
|
|||
{
|
||||
public:
|
||||
|
||||
|
||||
NTCP2Session (NTCP2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr);
|
||||
~NTCP2Session ();
|
||||
void Terminate ();
|
||||
|
@ -220,6 +221,20 @@ namespace transport
|
|||
{
|
||||
public:
|
||||
|
||||
enum RemoteAddressType
|
||||
{
|
||||
eIP4Address,
|
||||
eIP6Address,
|
||||
eHostname
|
||||
};
|
||||
|
||||
enum ProxyType
|
||||
{
|
||||
eNoProxy,
|
||||
eSocksProxy,
|
||||
eHTTPProxy
|
||||
};
|
||||
|
||||
NTCP2Server ();
|
||||
~NTCP2Server ();
|
||||
|
||||
|
@ -231,14 +246,22 @@ namespace transport
|
|||
void RemoveNTCP2Session (std::shared_ptr<NTCP2Session> session);
|
||||
std::shared_ptr<NTCP2Session> FindNTCP2Session (const i2p::data::IdentHash& ident);
|
||||
|
||||
void ConnectWithProxy (const std::string& addr, uint16_t port, RemoteAddressType addrtype, std::shared_ptr<NTCP2Session> conn);
|
||||
void Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr<NTCP2Session> conn);
|
||||
|
||||
void AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer, const std::string & host, uint16_t port, RemoteAddressType addrtype);
|
||||
|
||||
|
||||
bool UsingProxy() const { return m_ProxyType != eNoProxy; };
|
||||
void UseProxy(ProxyType proxy, const std::string & address, uint16_t port);
|
||||
|
||||
private:
|
||||
|
||||
void HandleAccept (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error);
|
||||
void HandleAcceptV6 (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error);
|
||||
|
||||
void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
|
||||
void HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer, const std::string & host, uint16_t port, RemoteAddressType adddrtype);
|
||||
|
||||
// timer
|
||||
void ScheduleTermination ();
|
||||
|
@ -251,6 +274,12 @@ namespace transport
|
|||
std::map<i2p::data::IdentHash, std::shared_ptr<NTCP2Session> > m_NTCP2Sessions;
|
||||
std::list<std::shared_ptr<NTCP2Session> > m_PendingIncomingSessions;
|
||||
|
||||
ProxyType m_ProxyType =eNoProxy;
|
||||
std::string m_ProxyAddress;
|
||||
uint16_t m_ProxyPort;
|
||||
boost::asio::ip::tcp::resolver m_Resolver;
|
||||
std::unique_ptr<boost::asio::ip::tcp::endpoint> m_ProxyEndpoint;
|
||||
|
||||
public:
|
||||
|
||||
// for HTTP/I2PControl
|
||||
|
|
|
@ -14,9 +14,6 @@
|
|||
#include "NTCPSession.h"
|
||||
#include "HTTP.h"
|
||||
#include "util.h"
|
||||
#ifdef WITH_EVENTS
|
||||
#include "Event.h"
|
||||
#endif
|
||||
|
||||
using namespace i2p::crypto;
|
||||
|
||||
|
@ -649,9 +646,6 @@ namespace transport
|
|||
{
|
||||
if (!m_NextMessage->IsExpired ())
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
QueueIntEvent("transport.recvmsg", GetIdentHashBase64(), 1);
|
||||
#endif
|
||||
m_Handler.PutNextMessage (m_NextMessage);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -338,7 +338,11 @@ namespace i2p
|
|||
{
|
||||
case low : /* not set */; break;
|
||||
case extra : caps |= i2p::data::RouterInfo::eExtraBandwidth; break; // 'P'
|
||||
case unlim : caps |= i2p::data::RouterInfo::eExtraBandwidth; // no break here, extra + high means 'X'
|
||||
case unlim : caps |= i2p::data::RouterInfo::eExtraBandwidth;
|
||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
[[fallthrough]];
|
||||
#endif
|
||||
// no break here, extra + high means 'X'
|
||||
case high : caps |= i2p::data::RouterInfo::eHighBandwidth; break;
|
||||
}
|
||||
m_RouterInfo.SetCaps (caps);
|
||||
|
|
|
@ -160,6 +160,13 @@ namespace transport
|
|||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "SSU: receivers runtime exception: ", ex.what ());
|
||||
if (m_IsRunning)
|
||||
{
|
||||
// restart socket
|
||||
m_Socket.close ();
|
||||
OpenSocket ();
|
||||
Receive ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -175,6 +182,12 @@ namespace transport
|
|||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "SSU: v6 receivers runtime exception: ", ex.what ());
|
||||
if (m_IsRunning)
|
||||
{
|
||||
m_SocketV6.close ();
|
||||
OpenSocketV6 ();
|
||||
ReceiveV6 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,6 @@
|
|||
#include "NetDb.hpp"
|
||||
#include "SSU.h"
|
||||
#include "SSUData.h"
|
||||
#ifdef WITH_EVENTS
|
||||
#include "Event.h"
|
||||
#endif
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
|
@ -241,9 +238,6 @@ namespace transport
|
|||
m_LastMessageReceivedTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (!msg->IsExpired ())
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
QueueIntEvent("transport.recvmsg", m_Session.GetIdentHashBase64(), 1);
|
||||
#endif
|
||||
m_Handler.PutNextMessage (msg);
|
||||
}
|
||||
else
|
||||
|
@ -448,7 +442,7 @@ namespace transport
|
|||
}
|
||||
catch (boost::system::system_error& ec)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: Can't resend data fragment ", ec.what ());
|
||||
LogPrint (eLogWarning, "SSU: Can't resend message ", it->first, " data fragment: ", ec.what ());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -458,7 +452,7 @@ namespace transport
|
|||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "SSU: message has not been ACKed after ", MAX_NUM_RESENDS, " attempts, deleted");
|
||||
LogPrint (eLogInfo, "SSU: message ", it->first, " has not been ACKed after ", MAX_NUM_RESENDS, " attempts, deleted");
|
||||
it = m_SentMessages.erase (it);
|
||||
}
|
||||
}
|
||||
|
@ -494,7 +488,7 @@ namespace transport
|
|||
{
|
||||
if (ts > it->second->lastFragmentInsertTime + INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: message ", it->first, " was not completed in ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds, deleted");
|
||||
LogPrint (eLogWarning, "SSU: message ", it->first, " was not completed in ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds, deleted");
|
||||
it = m_IncompleteMessages.erase (it);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -86,13 +86,14 @@ namespace stream
|
|||
LogPrint (eLogDebug, "Streaming: Stream deleted");
|
||||
}
|
||||
|
||||
void Stream::Terminate () // shoudl be called from StreamingDestination::Stop only
|
||||
void Stream::Terminate (bool deleteFromDestination) // shoudl be called from StreamingDestination::Stop only
|
||||
{
|
||||
m_AckSendTimer.cancel ();
|
||||
m_ReceiveTimer.cancel ();
|
||||
m_ResendTimer.cancel ();
|
||||
//CleanUp (); /* Need to recheck - broke working on windows */
|
||||
//m_LocalDestination.DeleteStream (shared_from_this ());
|
||||
if (deleteFromDestination)
|
||||
m_LocalDestination.DeleteStream (shared_from_this ());
|
||||
}
|
||||
|
||||
void Stream::CleanUp ()
|
||||
|
@ -847,6 +848,9 @@ namespace stream
|
|||
break;
|
||||
case 2:
|
||||
m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change first time
|
||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
[[fallthrough]];
|
||||
#endif
|
||||
// no break here
|
||||
case 4:
|
||||
if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr);
|
||||
|
@ -990,7 +994,7 @@ namespace stream
|
|||
{
|
||||
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
||||
for (auto it: m_Streams)
|
||||
it.second->Terminate ();
|
||||
it.second->Terminate (false); // we delete here
|
||||
m_Streams.clear ();
|
||||
m_IncomingStreams.clear ();
|
||||
}
|
||||
|
@ -1125,6 +1129,15 @@ namespace stream
|
|||
}
|
||||
}
|
||||
|
||||
bool StreamingDestination::DeleteStream (uint32_t recvStreamID)
|
||||
{
|
||||
auto it = m_Streams.find (recvStreamID);
|
||||
if (it == m_Streams.end ())
|
||||
return false;
|
||||
DeleteStream (it->second);
|
||||
return true;
|
||||
}
|
||||
|
||||
void StreamingDestination::SetAcceptor (const Acceptor& acceptor)
|
||||
{
|
||||
m_Acceptor = acceptor; // we must set it immediately for IsAcceptorSet
|
||||
|
|
|
@ -180,7 +180,7 @@ namespace stream
|
|||
int GetWindowSize () const { return m_WindowSize; };
|
||||
int GetRTT () const { return m_RTT; };
|
||||
|
||||
void Terminate ();
|
||||
void Terminate (bool deleteFromDestination = true);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -250,6 +250,7 @@ namespace stream
|
|||
|
||||
std::shared_ptr<Stream> CreateNewOutgoingStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
|
||||
void DeleteStream (std::shared_ptr<Stream> stream);
|
||||
bool DeleteStream (uint32_t recvStreamID);
|
||||
void SetAcceptor (const Acceptor& acceptor);
|
||||
void ResetAcceptor ();
|
||||
bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
|
||||
|
|
|
@ -6,10 +6,6 @@
|
|||
#include "Transports.h"
|
||||
#include "Config.h"
|
||||
#include "HTTP.h"
|
||||
#ifdef WITH_EVENTS
|
||||
#include "Event.h"
|
||||
#include "util.h"
|
||||
#endif
|
||||
|
||||
using namespace i2p::data;
|
||||
|
||||
|
@ -157,6 +153,7 @@ namespace transport
|
|||
m_IsRunning = true;
|
||||
m_Thread = new std::thread (std::bind (&Transports::Run, this));
|
||||
std::string ntcpproxy; i2p::config::GetOption("ntcpproxy", ntcpproxy);
|
||||
std::string ntcp2proxy; i2p::config::GetOption("ntcp2.proxy", ntcp2proxy);
|
||||
i2p::http::URL proxyurl;
|
||||
uint16_t softLimit, hardLimit, threads;
|
||||
i2p::config::GetOption("limits.ntcpsoft", softLimit);
|
||||
|
@ -200,8 +197,33 @@ namespace transport
|
|||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||
if (ntcp2)
|
||||
{
|
||||
m_NTCP2Server = new NTCP2Server ();
|
||||
m_NTCP2Server->Start ();
|
||||
if(!ntcp2proxy.empty())
|
||||
{
|
||||
if(proxyurl.parse(ntcp2proxy))
|
||||
{
|
||||
if(proxyurl.schema == "socks" || proxyurl.schema == "http")
|
||||
{
|
||||
m_NTCP2Server = new NTCP2Server ();
|
||||
NTCP2Server::ProxyType proxytype = NTCP2Server::eSocksProxy;
|
||||
|
||||
if (proxyurl.schema == "http")
|
||||
proxytype = NTCP2Server::eHTTPProxy;
|
||||
|
||||
m_NTCP2Server->UseProxy(proxytype, proxyurl.host, proxyurl.port) ;
|
||||
m_NTCP2Server->Start();
|
||||
}
|
||||
else
|
||||
LogPrint(eLogError, "Transports: unsupported NTCP2 proxy URL ", ntcp2proxy);
|
||||
}
|
||||
else
|
||||
LogPrint(eLogError, "Transports: invalid NTCP2 proxy url ", ntcp2proxy);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_NTCP2Server = new NTCP2Server ();
|
||||
m_NTCP2Server->Start ();
|
||||
}
|
||||
}
|
||||
|
||||
// create acceptors
|
||||
|
@ -249,11 +271,11 @@ namespace transport
|
|||
m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
|
||||
m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
|
||||
|
||||
if (m_IsNAT)
|
||||
{
|
||||
m_PeerTestTimer->expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL));
|
||||
m_PeerTestTimer->async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1));
|
||||
}
|
||||
if (m_IsNAT)
|
||||
{
|
||||
m_PeerTestTimer->expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL));
|
||||
m_PeerTestTimer->async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
|
||||
void Transports::Stop ()
|
||||
|
@ -346,9 +368,6 @@ namespace transport
|
|||
|
||||
void Transports::SendMessages (const i2p::data::IdentHash& ident, const std::vector<std::shared_ptr<i2p::I2NPMessage> >& msgs)
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
QueueIntEvent("transport.send", ident.ToBase64(), msgs.size());
|
||||
#endif
|
||||
m_Service->post (std::bind (&Transports::PostMessages, this, ident, msgs));
|
||||
}
|
||||
|
||||
|
@ -405,21 +424,33 @@ namespace transport
|
|||
{
|
||||
if (peer.router) // we have RI already
|
||||
{
|
||||
if (!peer.numAttempts) // NTCP2
|
||||
{
|
||||
peer.numAttempts++;
|
||||
if (m_NTCP2Server) // we support NTCP2
|
||||
{
|
||||
// NTCP2 have priority over NTCP
|
||||
auto address = peer.router->GetNTCP2Address (true, !context.SupportsV6 ()); // published only
|
||||
if (address)
|
||||
{
|
||||
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router);
|
||||
m_NTCP2Server->Connect (address->host, address->port, s);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!peer.numAttempts) // NTCP2
|
||||
{
|
||||
peer.numAttempts++;
|
||||
if (m_NTCP2Server) // we support NTCP2
|
||||
{
|
||||
// NTCP2 have priority over NTCP
|
||||
auto address = peer.router->GetNTCP2Address (true, !context.SupportsV6 ()); // published only
|
||||
if (address)
|
||||
{
|
||||
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router);
|
||||
|
||||
if(m_NTCP2Server->UsingProxy())
|
||||
{
|
||||
NTCP2Server::RemoteAddressType remote = NTCP2Server::eIP4Address;
|
||||
std::string addr = address->host.to_string();
|
||||
|
||||
if(address->host.is_v6())
|
||||
remote = NTCP2Server::eIP6Address;
|
||||
|
||||
m_NTCP2Server->ConnectWithProxy(addr, address->port, remote, s);
|
||||
}
|
||||
else
|
||||
m_NTCP2Server->Connect (address->host, address->port, s);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (peer.numAttempts == 1) // NTCP1
|
||||
{
|
||||
peer.numAttempts++;
|
||||
|
@ -558,6 +589,7 @@ namespace transport
|
|||
if (RoutesRestricted() || !i2p::context.SupportsV4 ()) return;
|
||||
if (m_SSUServer)
|
||||
{
|
||||
LogPrint (eLogInfo, "Transports: Started peer test");
|
||||
bool statusChanged = false;
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
|
@ -573,7 +605,7 @@ namespace transport
|
|||
}
|
||||
}
|
||||
if (!statusChanged)
|
||||
LogPrint (eLogWarning, "Can't find routers for peer test");
|
||||
LogPrint (eLogWarning, "Transports: Can't find routers for peer test");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -597,9 +629,6 @@ namespace transport
|
|||
auto it = m_Peers.find (ident);
|
||||
if (it != m_Peers.end ())
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
EmitEvent({{"type" , "transport.connected"}, {"ident", ident.ToBase64()}, {"inbound", "false"}});
|
||||
#endif
|
||||
bool sendDatabaseStore = true;
|
||||
if (it->second.delayedMessages.size () > 0)
|
||||
{
|
||||
|
@ -625,9 +654,6 @@ namespace transport
|
|||
session->Done();
|
||||
return;
|
||||
}
|
||||
#ifdef WITH_EVENTS
|
||||
EmitEvent({{"type" , "transport.connected"}, {"ident", ident.ToBase64()}, {"inbound", "true"}});
|
||||
#endif
|
||||
session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); // send DatabaseStore
|
||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||
m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, i2p::util::GetSecondsSinceEpoch (), {} }));
|
||||
|
@ -642,9 +668,6 @@ namespace transport
|
|||
auto remoteIdentity = session->GetRemoteIdentity ();
|
||||
if (!remoteIdentity) return;
|
||||
auto ident = remoteIdentity->GetIdentHash ();
|
||||
#ifdef WITH_EVENTS
|
||||
EmitEvent({{"type" , "transport.disconnected"}, {"ident", ident.ToBase64()}});
|
||||
#endif
|
||||
auto it = m_Peers.find (ident);
|
||||
if (it != m_Peers.end ())
|
||||
{
|
||||
|
|
|
@ -14,9 +14,6 @@
|
|||
#include "Config.h"
|
||||
#include "Tunnel.h"
|
||||
#include "TunnelPool.h"
|
||||
#ifdef WITH_EVENTS
|
||||
#include "Event.h"
|
||||
#endif
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
|
@ -35,9 +32,6 @@ namespace tunnel
|
|||
|
||||
void Tunnel::Build (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> outboundTunnel)
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
std::string peers = i2p::context.GetIdentity()->GetIdentHash().ToBase64();
|
||||
#endif
|
||||
auto numHops = m_Config->GetNumHops ();
|
||||
int numRecords = numHops <= STANDARD_NUM_RECORDS ? STANDARD_NUM_RECORDS : numHops;
|
||||
auto msg = NewI2NPShortMessage ();
|
||||
|
@ -64,15 +58,9 @@ namespace tunnel
|
|||
hop->CreateBuildRequestRecord (records + idx*TUNNEL_BUILD_RECORD_SIZE, msgID, ctx);
|
||||
hop->recordIndex = idx;
|
||||
i++;
|
||||
#ifdef WITH_EVENTS
|
||||
peers += ":" + hop->ident->GetIdentHash().ToBase64();
|
||||
#endif
|
||||
hop = hop->next;
|
||||
}
|
||||
BN_CTX_free (ctx);
|
||||
#ifdef WITH_EVENTS
|
||||
EmitTunnelEvent("tunnel.build", this, peers);
|
||||
#endif
|
||||
// fill up fake records with random data
|
||||
for (int i = numHops; i < numRecords; i++)
|
||||
{
|
||||
|
@ -207,9 +195,6 @@ namespace tunnel
|
|||
void Tunnel::SetState(TunnelState state)
|
||||
{
|
||||
m_State = state;
|
||||
#ifdef WITH_EVENTS
|
||||
EmitTunnelEvent("tunnel.state", this, state);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -614,9 +599,6 @@ namespace tunnel
|
|||
hop = hop->next;
|
||||
}
|
||||
}
|
||||
#ifdef WITH_EVENTS
|
||||
EmitTunnelEvent("tunnel.state", tunnel.get(), eTunnelStateBuildFailed);
|
||||
#endif
|
||||
// for i2lua
|
||||
if(pool) pool->OnTunnelBuildResult(tunnel, eBuildResultTimeout);
|
||||
// delete
|
||||
|
@ -628,9 +610,6 @@ namespace tunnel
|
|||
break;
|
||||
case eTunnelStateBuildFailed:
|
||||
LogPrint (eLogDebug, "Tunnel: pending build request ", it->first, " failed, deleted");
|
||||
#ifdef WITH_EVENTS
|
||||
EmitTunnelEvent("tunnel.state", tunnel.get(), eTunnelStateBuildFailed);
|
||||
#endif
|
||||
// for i2lua
|
||||
if(pool) pool->OnTunnelBuildResult(tunnel, eBuildResultRejected);
|
||||
|
||||
|
|
|
@ -19,49 +19,11 @@
|
|||
#include "TunnelGateway.h"
|
||||
#include "TunnelBase.h"
|
||||
#include "I2NPProtocol.h"
|
||||
#include "Event.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace tunnel
|
||||
{
|
||||
|
||||
template<typename TunnelT>
|
||||
static void EmitTunnelEvent(const std::string & ev, const TunnelT & t)
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
EmitEvent({{"type", ev}, {"tid", std::to_string(t->GetTunnelID())}});
|
||||
#else
|
||||
(void) ev;
|
||||
(void) t;
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename TunnelT, typename T>
|
||||
static void EmitTunnelEvent(const std::string & ev, TunnelT * t, const T & val)
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
EmitEvent({{"type", ev}, {"tid", std::to_string(t->GetTunnelID())}, {"value", std::to_string(val)}, {"inbound", std::to_string(t->IsInbound())}});
|
||||
#else
|
||||
(void) ev;
|
||||
(void) t;
|
||||
(void) val;
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename TunnelT>
|
||||
static void EmitTunnelEvent(const std::string & ev, TunnelT * t, const std::string & val)
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
EmitEvent({{"type", ev}, {"tid", std::to_string(t->GetTunnelID())}, {"value", val}, {"inbound", std::to_string(t->IsInbound())}});
|
||||
#else
|
||||
(void) ev;
|
||||
(void) t;
|
||||
(void) val;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes
|
||||
const int TUNNEL_EXPIRATION_THRESHOLD = 60; // 1 minute
|
||||
const int TUNNEL_RECREATION_THRESHOLD = 90; // 1.5 minutes
|
||||
|
|
|
@ -11,9 +11,6 @@
|
|||
#include "Tunnel.h"
|
||||
#include "TunnelPool.h"
|
||||
#include "Destination.h"
|
||||
#ifdef WITH_EVENTS
|
||||
#include "Event.h"
|
||||
#endif
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
|
@ -86,9 +83,6 @@ namespace tunnel
|
|||
{
|
||||
if (!m_IsActive) return;
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
EmitTunnelEvent("tunnels.created", createdTunnel);
|
||||
#endif
|
||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||
m_InboundTunnels.insert (createdTunnel);
|
||||
}
|
||||
|
@ -102,9 +96,6 @@ namespace tunnel
|
|||
{
|
||||
if (expiredTunnel)
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
EmitTunnelEvent("tunnels.expired", expiredTunnel);
|
||||
#endif
|
||||
expiredTunnel->SetTunnelPool (nullptr);
|
||||
for (auto& it: m_Tests)
|
||||
if (it.second.second == expiredTunnel) it.second.second = nullptr;
|
||||
|
@ -118,9 +109,6 @@ namespace tunnel
|
|||
{
|
||||
if (!m_IsActive) return;
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
EmitTunnelEvent("tunnels.created", createdTunnel);
|
||||
#endif
|
||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||
m_OutboundTunnels.insert (createdTunnel);
|
||||
}
|
||||
|
@ -133,9 +121,6 @@ namespace tunnel
|
|||
{
|
||||
if (expiredTunnel)
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
EmitTunnelEvent("tunnels.expired", expiredTunnel);
|
||||
#endif
|
||||
expiredTunnel->SetTunnelPool (nullptr);
|
||||
for (auto& it: m_Tests)
|
||||
if (it.second.first == expiredTunnel) it.second.first = nullptr;
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include "util.h"
|
||||
#include "ClientContext.h"
|
||||
#include "SOCKS.h"
|
||||
#include "WebSocks.h"
|
||||
#include "MatchedDestination.h"
|
||||
|
||||
namespace i2p
|
||||
|
@ -598,10 +597,8 @@ namespace client
|
|||
}
|
||||
else if (type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS)
|
||||
{
|
||||
// websocks proxy
|
||||
auto tun = std::make_shared<WebSocks>(address, port, localDestination);
|
||||
clientTunnel = tun;
|
||||
clientEndpoint = tun->GetLocalEndpoint();
|
||||
LogPrint(eLogError, "Clients: I2P Client tunnel websocks is deprecated");
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace client
|
|||
const char I2P_CLIENT_TUNNEL_CRYPTO_TYPE[] = "cryptotype";
|
||||
const char I2P_CLIENT_TUNNEL_DESTINATION_PORT[] = "destinationport";
|
||||
const char I2P_CLIENT_TUNNEL_MATCH_TUNNELS[] = "matchtunnels";
|
||||
const char I2P_CLIENT_TUNNEL_CONNECT_TIMEOUT[] = "connecttimeout";
|
||||
const char I2P_CLIENT_TUNNEL_CONNECT_TIMEOUT[] = "connecttimeout";
|
||||
const char I2P_SERVER_TUNNEL_HOST[] = "host";
|
||||
const char I2P_SERVER_TUNNEL_HOST_OVERRIDE[] = "hostoverride";
|
||||
const char I2P_SERVER_TUNNEL_PORT[] = "port";
|
||||
|
|
|
@ -246,8 +246,16 @@ namespace client
|
|||
m_PayloadLen = bufbe32toh (m_Header + I2CP_HEADER_LENGTH_OFFSET);
|
||||
if (m_PayloadLen > 0)
|
||||
{
|
||||
m_Payload = new uint8_t[m_PayloadLen];
|
||||
ReceivePayload ();
|
||||
if (m_PayloadLen <= I2CP_MAX_MESSAGE_LENGTH)
|
||||
{
|
||||
m_Payload = new uint8_t[m_PayloadLen];
|
||||
ReceivePayload ();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "I2CP: Unexpected payload length ", m_PayloadLen);
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
else // no following payload
|
||||
{
|
||||
|
@ -572,7 +580,7 @@ namespace client
|
|||
uint16_t keyType = bufbe16toh (buf + offset); offset += 2; // encryption type
|
||||
uint16_t keyLen = bufbe16toh (buf + offset); offset += 2; // private key length
|
||||
if (offset + keyLen > len) return;
|
||||
if (keyType > currentKeyType)
|
||||
if (!currentKey || keyType > currentKeyType)
|
||||
{
|
||||
currentKeyType = keyType;
|
||||
currentKey = buf + offset;
|
||||
|
@ -814,8 +822,11 @@ namespace client
|
|||
{
|
||||
m_IsRunning = false;
|
||||
m_Acceptor.cancel ();
|
||||
for (auto& it: m_Sessions)
|
||||
it.second->Stop ();
|
||||
{
|
||||
auto sessions = m_Sessions;
|
||||
for (auto& it: sessions)
|
||||
it.second->Stop ();
|
||||
}
|
||||
m_Sessions.clear ();
|
||||
m_Service.stop ();
|
||||
if (m_Thread)
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace client
|
|||
{
|
||||
const uint8_t I2CP_PROTOCOL_BYTE = 0x2A;
|
||||
const size_t I2CP_SESSION_BUFFER_SIZE = 4096;
|
||||
const size_t I2CP_MAX_MESSAGE_LENGTH = 65535;
|
||||
|
||||
const size_t I2CP_HEADER_LENGTH_OFFSET = 0;
|
||||
const size_t I2CP_HEADER_TYPE_OFFSET = I2CP_HEADER_LENGTH_OFFSET + 4;
|
||||
|
@ -80,7 +81,8 @@ namespace client
|
|||
|
||||
// implements LocalDestination
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const;
|
||||
i2p::data::CryptoKeyType GetEncryptionType () const { return m_EncryptionKeyType; };
|
||||
bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const { return m_EncryptionKeyType == keyType; };
|
||||
// TODO: implement GetEncryptionPublicKey
|
||||
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Identity; };
|
||||
|
||||
protected:
|
||||
|
|
|
@ -433,6 +433,9 @@ namespace proxy
|
|||
break;
|
||||
case CMD_UDP:
|
||||
if (m_socksv == SOCKS5) break;
|
||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
[[fallthrough]];
|
||||
#endif
|
||||
default:
|
||||
LogPrint(eLogError, "SOCKS: invalid command: ", ((int)*sock_buff));
|
||||
SocksRequestFailed(SOCKS5_GEN_FAIL);
|
||||
|
|
|
@ -1,559 +0,0 @@
|
|||
#include "WebSocks.h"
|
||||
#include "Log.h"
|
||||
#include <string>
|
||||
|
||||
#ifdef WITH_EVENTS
|
||||
#include "ClientContext.h"
|
||||
#include "Identity.h"
|
||||
#include "Destination.h"
|
||||
#include "Streaming.h"
|
||||
#include <functional>
|
||||
|
||||
#include <websocketpp/config/asio_no_tls.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
#include <boost/property_tree/ini_parser.hpp>
|
||||
#define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7))
|
||||
#if !GCC47_BOOST149
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#endif
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
typedef websocketpp::server<websocketpp::config::asio> WebSocksServerImpl;
|
||||
|
||||
typedef std::function<void(std::shared_ptr<i2p::stream::Stream>)> StreamConnectFunc;
|
||||
|
||||
|
||||
struct IWebSocksConn : public I2PServiceHandler
|
||||
{
|
||||
IWebSocksConn(I2PService * parent) : I2PServiceHandler(parent) {}
|
||||
virtual void Close() = 0;
|
||||
virtual void GotMessage(const websocketpp::connection_hdl & conn, WebSocksServerImpl::message_ptr msg) = 0;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<IWebSocksConn> WebSocksConn_ptr;
|
||||
|
||||
WebSocksConn_ptr CreateWebSocksConn(const websocketpp::connection_hdl & conn, WebSocksImpl * parent);
|
||||
|
||||
class WebSocksImpl
|
||||
{
|
||||
|
||||
typedef std::mutex mutex_t;
|
||||
typedef std::unique_lock<mutex_t> lock_t;
|
||||
|
||||
typedef std::shared_ptr<ClientDestination> Destination_t;
|
||||
public:
|
||||
|
||||
typedef WebSocksServerImpl ServerImpl;
|
||||
typedef ServerImpl::message_ptr MessagePtr;
|
||||
|
||||
WebSocksImpl(const std::string & addr, int port) :
|
||||
Parent(nullptr),
|
||||
m_Run(false),
|
||||
m_Addr(addr),
|
||||
m_Port(port),
|
||||
m_Thread(nullptr)
|
||||
{
|
||||
m_Server.init_asio();
|
||||
m_Server.set_open_handler(std::bind(&WebSocksImpl::ConnOpened, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
void InitializeDestination(WebSocks * parent)
|
||||
{
|
||||
Parent = parent;
|
||||
m_Dest = Parent->GetLocalDestination();
|
||||
}
|
||||
|
||||
ServerImpl::connection_ptr GetConn(const websocketpp::connection_hdl & conn)
|
||||
{
|
||||
return m_Server.get_con_from_hdl(conn);
|
||||
}
|
||||
|
||||
void CloseConn(const websocketpp::connection_hdl & conn)
|
||||
{
|
||||
auto c = GetConn(conn);
|
||||
if(c) c->close(websocketpp::close::status::normal, "closed");
|
||||
}
|
||||
|
||||
void CreateStreamTo(const std::string & addr, int port, StreamConnectFunc complete)
|
||||
{
|
||||
auto & addressbook = i2p::client::context.GetAddressBook();
|
||||
auto a = addressbook.GetAddress (addr);
|
||||
if (a && a->IsIdentHash ())
|
||||
{
|
||||
// address found
|
||||
m_Dest->CreateStream(complete, a->identHash, port);
|
||||
}
|
||||
else
|
||||
{
|
||||
// not found
|
||||
complete(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnOpened(websocketpp::connection_hdl conn)
|
||||
{
|
||||
auto ptr = CreateWebSocksConn(conn, this);
|
||||
Parent->AddHandler(ptr);
|
||||
m_Conns.push_back(ptr);
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
if(m_Run) return; // already started
|
||||
m_Server.listen(boost::asio::ip::address::from_string(m_Addr), m_Port);
|
||||
m_Server.start_accept();
|
||||
m_Run = true;
|
||||
m_Thread = new std::thread([&] (){
|
||||
while(m_Run) {
|
||||
try {
|
||||
m_Server.run();
|
||||
} catch( std::exception & ex) {
|
||||
LogPrint(eLogError, "Websocks runtime exception: ", ex.what());
|
||||
}
|
||||
}
|
||||
});
|
||||
m_Dest->Start();
|
||||
}
|
||||
|
||||
void Stop()
|
||||
{
|
||||
for(const auto & conn : m_Conns)
|
||||
conn->Close();
|
||||
|
||||
m_Dest->Stop();
|
||||
m_Run = false;
|
||||
m_Server.stop();
|
||||
if(m_Thread) {
|
||||
m_Thread->join();
|
||||
delete m_Thread;
|
||||
}
|
||||
m_Thread = nullptr;
|
||||
}
|
||||
|
||||
boost::asio::ip::tcp::endpoint GetLocalEndpoint()
|
||||
{
|
||||
return boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(m_Addr), m_Port);
|
||||
}
|
||||
|
||||
i2p::datagram::DatagramDestination * GetDatagramDest() const
|
||||
{
|
||||
auto dgram = m_Dest->GetDatagramDestination();
|
||||
if(!dgram) dgram = m_Dest->CreateDatagramDestination();
|
||||
return dgram;
|
||||
}
|
||||
|
||||
WebSocks * Parent;
|
||||
|
||||
private:
|
||||
std::vector<WebSocksConn_ptr> m_Conns;
|
||||
bool m_Run;
|
||||
ServerImpl m_Server;
|
||||
std::string m_Addr;
|
||||
int m_Port;
|
||||
std::thread * m_Thread;
|
||||
Destination_t m_Dest;
|
||||
};
|
||||
|
||||
struct WebSocksConn : public IWebSocksConn , public std::enable_shared_from_this<WebSocksConn>
|
||||
{
|
||||
enum ConnState
|
||||
{
|
||||
eWSCInitial,
|
||||
eWSCTryConnect,
|
||||
eWSCFailConnect,
|
||||
eWSCOkayConnect,
|
||||
eWSCDatagram,
|
||||
eWSCClose,
|
||||
eWSCEnd
|
||||
};
|
||||
|
||||
typedef WebSocksServerImpl ServerImpl;
|
||||
typedef ServerImpl::message_ptr Message_t;
|
||||
typedef websocketpp::connection_hdl ServerConn;
|
||||
typedef std::shared_ptr<ClientDestination> Destination_t;
|
||||
typedef std::shared_ptr<i2p::stream::StreamingDestination> StreamDest_t;
|
||||
typedef std::shared_ptr<i2p::stream::Stream> Stream_t;
|
||||
|
||||
ServerConn m_Conn;
|
||||
Stream_t m_Stream;
|
||||
ConnState m_State;
|
||||
WebSocksImpl * m_Parent;
|
||||
std::string m_RemoteAddr;
|
||||
int m_RemotePort;
|
||||
uint8_t m_RecvBuf[2048];
|
||||
bool m_IsDatagram;
|
||||
i2p::datagram::DatagramDestination * m_Datagram;
|
||||
|
||||
WebSocksConn(const ServerConn & conn, WebSocksImpl * parent) :
|
||||
IWebSocksConn(parent->Parent),
|
||||
m_Conn(conn),
|
||||
m_Stream(nullptr),
|
||||
m_State(eWSCInitial),
|
||||
m_Parent(parent),
|
||||
m_IsDatagram(false),
|
||||
m_Datagram(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~WebSocksConn()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void HandleDatagram(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
||||
{
|
||||
auto conn = m_Parent->GetConn(m_Conn);
|
||||
if(conn)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << from.GetIdentHash().ToBase32();
|
||||
ss << ".b32.i2p:";
|
||||
ss << std::to_string(fromPort);
|
||||
ss << "\n";
|
||||
ss.write((char *)buf, len);
|
||||
conn->send(ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
void BeginDatagram()
|
||||
{
|
||||
m_Datagram = m_Parent->GetDatagramDest();
|
||||
m_Datagram->SetReceiver(
|
||||
std::bind(
|
||||
&WebSocksConn::HandleDatagram,
|
||||
this,
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2,
|
||||
std::placeholders::_3,
|
||||
std::placeholders::_4,
|
||||
std::placeholders::_5), m_RemotePort);
|
||||
}
|
||||
|
||||
void EnterState(ConnState state)
|
||||
{
|
||||
LogPrint(eLogDebug, "websocks: state ", m_State, " -> ", state);
|
||||
switch(m_State)
|
||||
{
|
||||
case eWSCInitial:
|
||||
if (state == eWSCClose) {
|
||||
m_State = eWSCClose;
|
||||
// connection was opened but never used
|
||||
LogPrint(eLogInfo, "websocks: connection closed but never used");
|
||||
Close();
|
||||
return;
|
||||
} else if (state == eWSCTryConnect) {
|
||||
// we will try to connect
|
||||
m_State = eWSCTryConnect;
|
||||
m_Parent->CreateStreamTo(m_RemoteAddr, m_RemotePort, std::bind(&WebSocksConn::ConnectResult, this, std::placeholders::_1));
|
||||
} else if (state == eWSCDatagram) {
|
||||
if (m_RemotePort >= 0 && m_RemotePort <= 65535)
|
||||
{
|
||||
LogPrint(eLogDebug, "websocks: datagram mode initiated");
|
||||
m_State = eWSCDatagram;
|
||||
BeginDatagram();
|
||||
SendResponse("");
|
||||
}
|
||||
else
|
||||
SendResponse("invalid port");
|
||||
} else {
|
||||
LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
|
||||
}
|
||||
return;
|
||||
case eWSCTryConnect:
|
||||
if(state == eWSCOkayConnect) {
|
||||
// we connected okay
|
||||
LogPrint(eLogDebug, "websocks: connected to ", m_RemoteAddr, ":", m_RemotePort);
|
||||
SendResponse("");
|
||||
m_State = eWSCOkayConnect;
|
||||
} else if(state == eWSCFailConnect) {
|
||||
// we did not connect okay
|
||||
LogPrint(eLogDebug, "websocks: failed to connect to ", m_RemoteAddr, ":", m_RemotePort);
|
||||
SendResponse("failed to connect");
|
||||
m_State = eWSCFailConnect;
|
||||
EnterState(eWSCInitial);
|
||||
} else if(state == eWSCClose) {
|
||||
// premature close
|
||||
LogPrint(eLogWarning, "websocks: websocket connection closed prematurely");
|
||||
m_State = eWSCClose;
|
||||
} else {
|
||||
LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
|
||||
}
|
||||
return;
|
||||
case eWSCFailConnect:
|
||||
if (state == eWSCInitial) {
|
||||
// reset to initial state so we can try connecting again
|
||||
m_RemoteAddr = "";
|
||||
m_RemotePort = 0;
|
||||
LogPrint(eLogDebug, "websocks: reset websocket conn to initial state");
|
||||
m_State = eWSCInitial;
|
||||
} else if (state == eWSCClose) {
|
||||
// we are going to close the connection
|
||||
m_State = eWSCClose;
|
||||
Close();
|
||||
} else {
|
||||
LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
|
||||
}
|
||||
return;
|
||||
case eWSCDatagram:
|
||||
if(state != eWSCClose) {
|
||||
LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
|
||||
}
|
||||
m_State = eWSCClose;
|
||||
Close();
|
||||
return;
|
||||
case eWSCOkayConnect:
|
||||
if(state == eWSCClose) {
|
||||
// graceful close
|
||||
m_State = eWSCClose;
|
||||
Close();
|
||||
} else {
|
||||
LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
|
||||
}
|
||||
return;
|
||||
case eWSCClose:
|
||||
if(state == eWSCEnd) {
|
||||
LogPrint(eLogDebug, "websocks: socket ended");
|
||||
Kill();
|
||||
auto me = shared_from_this();
|
||||
Done(me);
|
||||
} else {
|
||||
LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
LogPrint(eLogError, "websocks: bad state ", m_State);
|
||||
}
|
||||
}
|
||||
|
||||
void StartForwarding()
|
||||
{
|
||||
LogPrint(eLogDebug, "websocks: begin forwarding data");
|
||||
uint8_t b[1];
|
||||
m_Stream->Send(b, 0);
|
||||
AsyncRecv();
|
||||
}
|
||||
|
||||
void HandleAsyncRecv(const boost::system::error_code &ec, std::size_t n)
|
||||
{
|
||||
if(ec) {
|
||||
// error
|
||||
LogPrint(eLogWarning, "websocks: connection error ", ec.message());
|
||||
EnterState(eWSCClose);
|
||||
} else {
|
||||
// forward data
|
||||
LogPrint(eLogDebug, "websocks recv ", n);
|
||||
|
||||
std::string str((char*)m_RecvBuf, n);
|
||||
auto conn = m_Parent->GetConn(m_Conn);
|
||||
if(!conn) {
|
||||
LogPrint(eLogWarning, "websocks: connection is gone");
|
||||
EnterState(eWSCClose);
|
||||
return;
|
||||
}
|
||||
conn->send(str);
|
||||
AsyncRecv();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncRecv()
|
||||
{
|
||||
m_Stream->AsyncReceive(
|
||||
boost::asio::buffer(m_RecvBuf, sizeof(m_RecvBuf)),
|
||||
std::bind(&WebSocksConn::HandleAsyncRecv, this, std::placeholders::_1, std::placeholders::_2), 60);
|
||||
}
|
||||
|
||||
/** @brief send error message or empty string for success */
|
||||
void SendResponse(const std::string & errormsg)
|
||||
{
|
||||
boost::property_tree::ptree resp;
|
||||
if(errormsg.size()) {
|
||||
resp.put("error", errormsg);
|
||||
resp.put("success", 0);
|
||||
} else {
|
||||
resp.put("success", 1);
|
||||
}
|
||||
std::ostringstream ss;
|
||||
write_json(ss, resp);
|
||||
auto conn = m_Parent->GetConn(m_Conn);
|
||||
if(conn) conn->send(ss.str());
|
||||
}
|
||||
|
||||
void ConnectResult(Stream_t stream)
|
||||
{
|
||||
m_Stream = stream;
|
||||
if(m_State == eWSCClose) {
|
||||
// premature close of websocket
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
if(m_Stream) {
|
||||
// connect good
|
||||
EnterState(eWSCOkayConnect);
|
||||
StartForwarding();
|
||||
} else {
|
||||
// connect failed
|
||||
EnterState(eWSCFailConnect);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void GotMessage(const websocketpp::connection_hdl & conn, WebSocksServerImpl::message_ptr msg)
|
||||
{
|
||||
(void) conn;
|
||||
std::string payload = msg->get_payload();
|
||||
if(m_State == eWSCOkayConnect)
|
||||
{
|
||||
// forward to server
|
||||
LogPrint(eLogDebug, "websocks: forward ", payload.size());
|
||||
m_Stream->Send((uint8_t*)payload.c_str(), payload.size());
|
||||
} else if (m_State == eWSCInitial) {
|
||||
// recv connect request
|
||||
auto itr = payload.find(":");
|
||||
if(itr == std::string::npos) {
|
||||
// no port
|
||||
m_RemotePort = 0;
|
||||
m_RemoteAddr = payload;
|
||||
} else {
|
||||
// includes port
|
||||
m_RemotePort = std::stoi(payload.substr(itr+1));
|
||||
m_RemoteAddr = payload.substr(0, itr);
|
||||
}
|
||||
m_IsDatagram = m_RemoteAddr == "DATAGRAM";
|
||||
if(m_IsDatagram)
|
||||
EnterState(eWSCDatagram);
|
||||
else
|
||||
EnterState(eWSCTryConnect);
|
||||
} else if (m_State == eWSCDatagram) {
|
||||
// send datagram
|
||||
// format is "host:port\npayload"
|
||||
auto idx = payload.find("\n");
|
||||
std::string line = payload.substr(0, idx);
|
||||
auto itr = line.find(":");
|
||||
auto & addressbook = i2p::client::context.GetAddressBook();
|
||||
std::string addr;
|
||||
int port = 0;
|
||||
if (itr == std::string::npos)
|
||||
{
|
||||
addr = line;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = line.substr(0, itr);
|
||||
port = std::atoi(line.substr(itr+1).c_str());
|
||||
}
|
||||
auto a = addressbook.GetAddress (addr);
|
||||
if (a && a->IsIdentHash ())
|
||||
{
|
||||
const char * data = payload.c_str() + idx + 1;
|
||||
size_t len = payload.size() - (1 + line.size());
|
||||
m_Datagram->SendDatagramTo((const uint8_t*)data, len, a->identHash, m_RemotePort, port);
|
||||
}
|
||||
} else {
|
||||
// wtf?
|
||||
LogPrint(eLogWarning, "websocks: got message in invalid state ", m_State);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Close()
|
||||
{
|
||||
if(m_State == eWSCClose) {
|
||||
LogPrint(eLogDebug, "websocks: closing connection");
|
||||
if(m_Stream) m_Stream->Close();
|
||||
if(m_Datagram) m_Datagram->ResetReceiver(m_RemotePort);
|
||||
m_Parent->CloseConn(m_Conn);
|
||||
EnterState(eWSCEnd);
|
||||
} else {
|
||||
EnterState(eWSCClose);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
WebSocksConn_ptr CreateWebSocksConn(const websocketpp::connection_hdl & conn, WebSocksImpl * parent)
|
||||
{
|
||||
auto ptr = std::make_shared<WebSocksConn>(conn, parent);
|
||||
auto c = parent->GetConn(conn);
|
||||
c->set_message_handler(std::bind(&WebSocksConn::GotMessage, ptr.get(), std::placeholders::_1, std::placeholders::_2));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
// no websocket support
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
class WebSocksImpl
|
||||
{
|
||||
public:
|
||||
WebSocksImpl(const std::string & addr, int port) : m_Addr(addr), m_Port(port)
|
||||
{
|
||||
}
|
||||
|
||||
~WebSocksImpl()
|
||||
{
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
LogPrint(eLogInfo, "WebSockets not enabled on compile time");
|
||||
}
|
||||
|
||||
void Stop()
|
||||
{
|
||||
}
|
||||
|
||||
void InitializeDestination(WebSocks * parent)
|
||||
{
|
||||
}
|
||||
|
||||
boost::asio::ip::tcp::endpoint GetLocalEndpoint()
|
||||
{
|
||||
return boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(m_Addr), m_Port);
|
||||
}
|
||||
|
||||
std::string m_Addr;
|
||||
int m_Port;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
WebSocks::WebSocks(const std::string & addr, int port, std::shared_ptr<ClientDestination> localDestination) : m_Impl(new WebSocksImpl(addr, port))
|
||||
{
|
||||
m_Impl->InitializeDestination(this);
|
||||
}
|
||||
WebSocks::~WebSocks() { delete m_Impl; }
|
||||
|
||||
void WebSocks::Start()
|
||||
{
|
||||
m_Impl->Start();
|
||||
GetLocalDestination()->Start();
|
||||
}
|
||||
|
||||
boost::asio::ip::tcp::endpoint WebSocks::GetLocalEndpoint() const
|
||||
{
|
||||
return m_Impl->GetLocalEndpoint();
|
||||
}
|
||||
|
||||
void WebSocks::Stop()
|
||||
{
|
||||
m_Impl->Stop();
|
||||
GetLocalDestination()->Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
#ifndef WEBSOCKS_H_
|
||||
#define WEBSOCKS_H_
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "I2PService.h"
|
||||
#include "Destination.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
|
||||
class WebSocksImpl;
|
||||
|
||||
/** @brief websocket socks proxy server */
|
||||
class WebSocks : public i2p::client::I2PService
|
||||
{
|
||||
public:
|
||||
WebSocks(const std::string & addr, int port, std::shared_ptr<ClientDestination> localDestination);
|
||||
~WebSocks();
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
|
||||
boost::asio::ip::tcp::endpoint GetLocalEndpoint() const;
|
||||
|
||||
const char * GetName() { return "WebSOCKS Proxy"; }
|
||||
|
||||
private:
|
||||
WebSocksImpl * m_Impl;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,195 +0,0 @@
|
|||
#ifdef WITH_EVENTS
|
||||
#include "Websocket.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <set>
|
||||
#include <functional>
|
||||
|
||||
#include <websocketpp/config/asio_no_tls.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
#include <boost/property_tree/ini_parser.hpp>
|
||||
#define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7))
|
||||
#if !GCC47_BOOST149
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#endif
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace event
|
||||
{
|
||||
|
||||
typedef websocketpp::server<websocketpp::config::asio> ServerImpl;
|
||||
typedef websocketpp::connection_hdl ServerConn;
|
||||
|
||||
class WebsocketServerImpl : public EventListener
|
||||
{
|
||||
private:
|
||||
typedef ServerImpl::message_ptr MessagePtr;
|
||||
public:
|
||||
|
||||
WebsocketServerImpl(const std::string & addr, int port) :
|
||||
m_run(false),
|
||||
m_ws_thread(nullptr),
|
||||
m_ev_thread(nullptr),
|
||||
m_WebsocketTicker(m_Service)
|
||||
{
|
||||
m_server.init_asio();
|
||||
m_server.set_open_handler(std::bind(&WebsocketServerImpl::ConnOpened, this, std::placeholders::_1));
|
||||
m_server.set_close_handler(std::bind(&WebsocketServerImpl::ConnClosed, this, std::placeholders::_1));
|
||||
m_server.set_message_handler(std::bind(&WebsocketServerImpl::OnConnMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
m_server.listen(boost::asio::ip::address::from_string(addr), port);
|
||||
}
|
||||
|
||||
~WebsocketServerImpl()
|
||||
{
|
||||
}
|
||||
|
||||
void Start() {
|
||||
m_run = true;
|
||||
m_server.start_accept();
|
||||
m_ws_thread = new std::thread([&] () {
|
||||
while(m_run) {
|
||||
try {
|
||||
m_server.run();
|
||||
} catch (std::exception & e ) {
|
||||
LogPrint(eLogError, "Websocket server: ", e.what());
|
||||
}
|
||||
}
|
||||
});
|
||||
m_ev_thread = new std::thread([&] () {
|
||||
while(m_run) {
|
||||
try {
|
||||
m_Service.run();
|
||||
break;
|
||||
} catch (std::exception & e ) {
|
||||
LogPrint(eLogError, "Websocket service: ", e.what());
|
||||
}
|
||||
}
|
||||
});
|
||||
ScheduleTick();
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
m_run = false;
|
||||
m_Service.stop();
|
||||
m_server.stop();
|
||||
|
||||
if(m_ev_thread) {
|
||||
m_ev_thread->join();
|
||||
delete m_ev_thread;
|
||||
}
|
||||
m_ev_thread = nullptr;
|
||||
|
||||
if(m_ws_thread) {
|
||||
m_ws_thread->join();
|
||||
delete m_ws_thread;
|
||||
}
|
||||
m_ws_thread = nullptr;
|
||||
}
|
||||
|
||||
void ConnOpened(ServerConn c)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_connsMutex);
|
||||
m_conns.insert(c);
|
||||
}
|
||||
|
||||
void ConnClosed(ServerConn c)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_connsMutex);
|
||||
m_conns.erase(c);
|
||||
}
|
||||
|
||||
void OnConnMessage(ServerConn conn, ServerImpl::message_ptr msg)
|
||||
{
|
||||
(void) conn;
|
||||
(void) msg;
|
||||
}
|
||||
|
||||
void HandleTick(const boost::system::error_code & ec)
|
||||
{
|
||||
|
||||
if(ec != boost::asio::error::operation_aborted)
|
||||
LogPrint(eLogError, "Websocket ticker: ", ec.message());
|
||||
// pump collected events to us
|
||||
i2p::event::core.PumpCollected(this);
|
||||
ScheduleTick();
|
||||
}
|
||||
|
||||
void ScheduleTick()
|
||||
{
|
||||
LogPrint(eLogDebug, "Websocket schedule tick");
|
||||
boost::posix_time::seconds dlt(1);
|
||||
m_WebsocketTicker.expires_from_now(dlt);
|
||||
m_WebsocketTicker.async_wait(std::bind(&WebsocketServerImpl::HandleTick, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
/** @brief called from m_ev_thread */
|
||||
void HandlePumpEvent(const EventType & ev, const uint64_t & val)
|
||||
{
|
||||
EventType e;
|
||||
for (const auto & i : ev)
|
||||
e[i.first] = i.second;
|
||||
|
||||
e["number"] = std::to_string(val);
|
||||
HandleEvent(e);
|
||||
}
|
||||
|
||||
/** @brief called from m_ws_thread */
|
||||
void HandleEvent(const EventType & ev)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_connsMutex);
|
||||
boost::property_tree::ptree event;
|
||||
for (const auto & item : ev) {
|
||||
event.put(item.first, item.second);
|
||||
}
|
||||
std::ostringstream ss;
|
||||
write_json(ss, event);
|
||||
std::string s = ss.str();
|
||||
|
||||
ConnList::iterator it;
|
||||
for (it = m_conns.begin(); it != m_conns.end(); ++it) {
|
||||
ServerImpl::connection_ptr con = m_server.get_con_from_hdl(*it);
|
||||
con->send(s);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::set<ServerConn, std::owner_less<ServerConn> > ConnList;
|
||||
bool m_run;
|
||||
std::thread * m_ws_thread;
|
||||
std::thread * m_ev_thread;
|
||||
std::mutex m_connsMutex;
|
||||
ConnList m_conns;
|
||||
ServerImpl m_server;
|
||||
boost::asio::io_service m_Service;
|
||||
boost::asio::deadline_timer m_WebsocketTicker;
|
||||
};
|
||||
|
||||
|
||||
WebsocketServer::WebsocketServer(const std::string & addr, int port) : m_impl(new WebsocketServerImpl(addr, port)) {}
|
||||
WebsocketServer::~WebsocketServer()
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
|
||||
|
||||
void WebsocketServer::Start()
|
||||
{
|
||||
m_impl->Start();
|
||||
}
|
||||
|
||||
void WebsocketServer::Stop()
|
||||
{
|
||||
m_impl->Stop();
|
||||
}
|
||||
|
||||
EventListener * WebsocketServer::ToListener()
|
||||
{
|
||||
return m_impl;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,28 +0,0 @@
|
|||
#ifndef WEBSOCKET_H__
|
||||
#define WEBSOCKET_H__
|
||||
#include "Event.h"
|
||||
namespace i2p
|
||||
{
|
||||
namespace event
|
||||
{
|
||||
|
||||
class WebsocketServerImpl;
|
||||
|
||||
class WebsocketServer
|
||||
{
|
||||
public:
|
||||
WebsocketServer(const std::string & addr, int port);
|
||||
~WebsocketServer();
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
|
||||
EventListener * ToListener();
|
||||
|
||||
private:
|
||||
WebsocketServerImpl * m_impl;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
3
qt/i2pd_qt/DelayedSaveManager.cpp
Normal file
3
qt/i2pd_qt/DelayedSaveManager.cpp
Normal file
|
@ -0,0 +1,3 @@
|
|||
#include "DelayedSaveManager.h"
|
||||
|
||||
DelayedSaveManager::DelayedSaveManager(){}
|
24
qt/i2pd_qt/DelayedSaveManager.h
Normal file
24
qt/i2pd_qt/DelayedSaveManager.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef DELAYEDSAVEMANAGER_H
|
||||
#define DELAYEDSAVEMANAGER_H
|
||||
|
||||
#include "Saver.h"
|
||||
|
||||
class DelayedSaveManager
|
||||
{
|
||||
public:
|
||||
DelayedSaveManager();
|
||||
|
||||
virtual void setSaver(Saver* saver)=0;
|
||||
|
||||
typedef unsigned int DATA_SERIAL_TYPE;
|
||||
|
||||
virtual void delayedSave(DATA_SERIAL_TYPE dataSerial, bool needsTunnelFocus, std::string tunnelNameToFocus)=0;
|
||||
|
||||
//returns false iff save failed
|
||||
virtual bool appExiting()=0;
|
||||
|
||||
virtual bool needsFocusOnTunnel()=0;
|
||||
virtual std::string& getTunnelNameToFocus()=0;
|
||||
};
|
||||
|
||||
#endif // DELAYEDSAVEMANAGER_H
|
140
qt/i2pd_qt/DelayedSaveManagerImpl.cpp
Normal file
140
qt/i2pd_qt/DelayedSaveManagerImpl.cpp
Normal file
|
@ -0,0 +1,140 @@
|
|||
#include "DelayedSaveManagerImpl.h"
|
||||
|
||||
DelayedSaveManagerImpl::DelayedSaveManagerImpl() :
|
||||
saver(nullptr),
|
||||
lastDataSerialSeen(DelayedSaveManagerImpl::INITIAL_DATA_SERIAL),
|
||||
lastSaveStartedTimestamp(A_VERY_OBSOLETE_TIMESTAMP),
|
||||
exiting(false),
|
||||
thread(new DelayedSaveThread(this))
|
||||
{
|
||||
}
|
||||
|
||||
void DelayedSaveManagerImpl::setSaver(Saver* saver) {
|
||||
this->saver = saver;
|
||||
}
|
||||
|
||||
void DelayedSaveManagerImpl::start() {
|
||||
thread->start();
|
||||
}
|
||||
|
||||
bool DelayedSaveManagerImpl::isSaverValid() {
|
||||
return saver != nullptr;
|
||||
}
|
||||
|
||||
void DelayedSaveManagerImpl::delayedSave(DATA_SERIAL_TYPE dataSerial, bool focusOnTunnel, std::string tunnelNameToFocus_) {
|
||||
if(lastDataSerialSeen==dataSerial)return;
|
||||
this->focusOnTunnel = focusOnTunnel;
|
||||
tunnelNameToFocus = tunnelNameToFocus_;
|
||||
lastDataSerialSeen=dataSerial;
|
||||
assert(isSaverValid());
|
||||
TIMESTAMP_TYPE now = getTime();
|
||||
TIMESTAMP_TYPE wakeTime = lastSaveStartedTimestamp + DelayedSaveThread::WAIT_TIME_MILLIS;
|
||||
if(now < wakeTime) {
|
||||
//defer save until lastSaveStartedTimestamp + DelayedSaveThread::WAIT_TIME_MILLIS
|
||||
thread->deferSaveUntil(wakeTime);
|
||||
return;
|
||||
}
|
||||
lastSaveStartedTimestamp = now;
|
||||
thread->startSavingNow();
|
||||
}
|
||||
|
||||
bool DelayedSaveManagerImpl::appExiting() {
|
||||
exiting=true;
|
||||
thread->wakeThreadAndJoinThread();
|
||||
assert(isSaverValid());
|
||||
saver->save(false, "");
|
||||
return true;
|
||||
}
|
||||
|
||||
DelayedSaveThread::DelayedSaveThread(DelayedSaveManagerImpl* delayedSaveManagerImpl_):
|
||||
delayedSaveManagerImpl(delayedSaveManagerImpl_),
|
||||
mutex(new QMutex()),
|
||||
waitCondition(new QWaitCondition()),
|
||||
saveNow(false),
|
||||
defer(false)
|
||||
{
|
||||
mutex->lock();
|
||||
}
|
||||
|
||||
DelayedSaveThread::~DelayedSaveThread(){
|
||||
mutex->unlock();
|
||||
delete mutex;
|
||||
delete waitCondition;
|
||||
}
|
||||
|
||||
void DelayedSaveThread::run() {
|
||||
forever {
|
||||
if(delayedSaveManagerImpl->isExiting())return;
|
||||
waitCondition->wait(mutex, WAIT_TIME_MILLIS);
|
||||
if(delayedSaveManagerImpl->isExiting())return;
|
||||
Saver* saver = delayedSaveManagerImpl->getSaver();
|
||||
assert(saver!=nullptr);
|
||||
if(saveNow) {
|
||||
saveNow = false;
|
||||
const bool focusOnTunnel = delayedSaveManagerImpl->needsFocusOnTunnel();
|
||||
const std::string tunnelNameToFocus = delayedSaveManagerImpl->getTunnelNameToFocus();
|
||||
saver->save(focusOnTunnel, tunnelNameToFocus);
|
||||
continue;
|
||||
}
|
||||
if(defer) {
|
||||
defer=false;
|
||||
#define max(a,b) (((a)>(b))?(a):(b))
|
||||
forever {
|
||||
TIMESTAMP_TYPE now = DelayedSaveManagerImpl::getTime();
|
||||
TIMESTAMP_TYPE millisToWait = max(wakeTime-now, 0);
|
||||
if(millisToWait>0) {
|
||||
waitCondition->wait(mutex, millisToWait);
|
||||
if(delayedSaveManagerImpl->isExiting())return;
|
||||
continue;
|
||||
}
|
||||
const bool focusOnTunnel = delayedSaveManagerImpl->needsFocusOnTunnel();
|
||||
const std::string tunnelNameToFocus = delayedSaveManagerImpl->getTunnelNameToFocus();
|
||||
saver->save(focusOnTunnel, tunnelNameToFocus);
|
||||
break; //break inner loop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DelayedSaveThread::wakeThreadAndJoinThread() {
|
||||
waitCondition->wakeAll();
|
||||
quit();
|
||||
wait();//join //"similar to the POSIX pthread_join()"
|
||||
}
|
||||
|
||||
DelayedSaveManagerImpl::TIMESTAMP_TYPE DelayedSaveManagerImpl::getTime() {
|
||||
return QDateTime::currentMSecsSinceEpoch();
|
||||
}
|
||||
|
||||
void DelayedSaveThread::deferSaveUntil(TIMESTAMP_TYPE wakeTime_) {
|
||||
wakeTime = wakeTime_;
|
||||
defer = true;
|
||||
waitCondition->wakeAll();
|
||||
}
|
||||
|
||||
void DelayedSaveThread::startSavingNow() {
|
||||
//mutex->lock();
|
||||
saveNow=true;
|
||||
waitCondition->wakeAll();
|
||||
//mutex->unlock();
|
||||
}
|
||||
|
||||
DelayedSaveManagerImpl::~DelayedSaveManagerImpl() {
|
||||
thread->wakeThreadAndJoinThread();
|
||||
delete thread;
|
||||
}
|
||||
|
||||
bool DelayedSaveManagerImpl::isExiting() {
|
||||
return exiting;
|
||||
}
|
||||
Saver* DelayedSaveManagerImpl::getSaver() {
|
||||
return saver;
|
||||
}
|
||||
|
||||
bool DelayedSaveManagerImpl::needsFocusOnTunnel() {
|
||||
return focusOnTunnel;
|
||||
}
|
||||
|
||||
std::string& DelayedSaveManagerImpl::getTunnelNameToFocus() {
|
||||
return tunnelNameToFocus;
|
||||
}
|
82
qt/i2pd_qt/DelayedSaveManagerImpl.h
Normal file
82
qt/i2pd_qt/DelayedSaveManagerImpl.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
#ifndef DELAYEDSAVEMANAGERIMPL_H
|
||||
#define DELAYEDSAVEMANAGERIMPL_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QWaitCondition>
|
||||
#include <QMutex>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "DelayedSaveManager.h"
|
||||
#include "Saver.h"
|
||||
|
||||
class DelayedSaveManagerImpl;
|
||||
|
||||
class DelayedSaveThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static constexpr unsigned long WAIT_TIME_MILLIS = 1000L;
|
||||
|
||||
typedef qint64 TIMESTAMP_TYPE;
|
||||
static constexpr TIMESTAMP_TYPE A_VERY_OBSOLETE_TIMESTAMP=0;
|
||||
|
||||
DelayedSaveThread(DelayedSaveManagerImpl* delayedSaveManagerImpl);
|
||||
virtual ~DelayedSaveThread();
|
||||
|
||||
void run() override;
|
||||
|
||||
void deferSaveUntil(TIMESTAMP_TYPE wakeTime);
|
||||
void startSavingNow();
|
||||
|
||||
void wakeThreadAndJoinThread();
|
||||
|
||||
private:
|
||||
DelayedSaveManagerImpl* delayedSaveManagerImpl;
|
||||
QMutex* mutex;
|
||||
QWaitCondition* waitCondition;
|
||||
volatile bool saveNow;
|
||||
volatile bool defer;
|
||||
volatile TIMESTAMP_TYPE wakeTime;
|
||||
};
|
||||
|
||||
class DelayedSaveManagerImpl : public DelayedSaveManager
|
||||
{
|
||||
public:
|
||||
DelayedSaveManagerImpl();
|
||||
virtual ~DelayedSaveManagerImpl();
|
||||
virtual void setSaver(Saver* saver);
|
||||
virtual void start();
|
||||
virtual void delayedSave(DATA_SERIAL_TYPE dataSerial, bool focusOnTunnel, std::string tunnelNameToFocus);
|
||||
virtual bool appExiting();
|
||||
|
||||
typedef DelayedSaveThread::TIMESTAMP_TYPE TIMESTAMP_TYPE;
|
||||
|
||||
static constexpr DATA_SERIAL_TYPE INITIAL_DATA_SERIAL=0;
|
||||
bool isExiting();
|
||||
Saver* getSaver();
|
||||
static TIMESTAMP_TYPE getTime();
|
||||
|
||||
bool needsFocusOnTunnel();
|
||||
std::string& getTunnelNameToFocus();
|
||||
|
||||
private:
|
||||
Saver* saver;
|
||||
bool isSaverValid();
|
||||
|
||||
DATA_SERIAL_TYPE lastDataSerialSeen;
|
||||
|
||||
static constexpr TIMESTAMP_TYPE A_VERY_OBSOLETE_TIMESTAMP=DelayedSaveThread::A_VERY_OBSOLETE_TIMESTAMP;
|
||||
TIMESTAMP_TYPE lastSaveStartedTimestamp;
|
||||
|
||||
bool exiting;
|
||||
DelayedSaveThread* thread;
|
||||
void wakeThreadAndJoinThread();
|
||||
|
||||
bool focusOnTunnel;
|
||||
std::string tunnelNameToFocus;
|
||||
};
|
||||
|
||||
#endif // DELAYEDSAVEMANAGERIMPL_H
|
6
qt/i2pd_qt/Saver.cpp
Normal file
6
qt/i2pd_qt/Saver.cpp
Normal file
|
@ -0,0 +1,6 @@
|
|||
#include "Saver.h"
|
||||
|
||||
Saver::Saver()
|
||||
{
|
||||
|
||||
}
|
22
qt/i2pd_qt/Saver.h
Normal file
22
qt/i2pd_qt/Saver.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef SAVER_H
|
||||
#define SAVER_H
|
||||
|
||||
#include <string>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
class Saver : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Saver();
|
||||
//false iff failures
|
||||
virtual bool save(const bool focusOnTunnel, const std::string& tunnelNameToFocus)=0;
|
||||
|
||||
signals:
|
||||
void reloadTunnelsConfigAndUISignal(const QString);
|
||||
|
||||
};
|
||||
|
||||
#endif // SAVER_H
|
79
qt/i2pd_qt/SaverImpl.cpp
Normal file
79
qt/i2pd_qt/SaverImpl.cpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
#include "SaverImpl.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <assert.h>
|
||||
#include <sstream>
|
||||
|
||||
#include "QList"
|
||||
#include "QString"
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
SaverImpl::SaverImpl(MainWindow *mainWindowPtr_, QList<MainWindowItem*> * configItems_, std::map<std::string,TunnelConfig*>* tunnelConfigs_) :
|
||||
configItems(configItems_), tunnelConfigs(tunnelConfigs_), confpath(), tunconfpath(), mainWindowPtr(mainWindowPtr_)
|
||||
{}
|
||||
|
||||
SaverImpl::~SaverImpl() {}
|
||||
|
||||
bool SaverImpl::save(const bool focusOnTunnel, const std::string& tunnelNameToFocus) {
|
||||
//save main config
|
||||
{
|
||||
std::stringstream out;
|
||||
for(QList<MainWindowItem*>::iterator it = configItems->begin(); it!= configItems->end(); ++it) {
|
||||
MainWindowItem* item = *it;
|
||||
item->saveToStringStream(out);
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
QString backup=confpath+"~";
|
||||
if(QFile::exists(backup)) QFile::remove(backup);//TODO handle errors
|
||||
if(QFile::exists(confpath)) QFile::rename(confpath, backup);//TODO handle errors
|
||||
ofstream outfile;
|
||||
outfile.open(confpath.toStdString());//TODO handle errors
|
||||
outfile << out.str().c_str();
|
||||
outfile.close();
|
||||
}
|
||||
|
||||
//save tunnels config
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
for (std::map<std::string,TunnelConfig*>::iterator it=tunnelConfigs->begin(); it!=tunnelConfigs->end(); ++it) {
|
||||
//const std::string& name = it->first;
|
||||
TunnelConfig* tunconf = it->second;
|
||||
tunconf->saveHeaderToStringStream(out);
|
||||
tunconf->saveToStringStream(out);
|
||||
tunconf->saveI2CPParametersToStringStream(out);
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
QString backup=tunconfpath+"~";
|
||||
if(QFile::exists(backup)) QFile::remove(backup);//TODO handle errors
|
||||
if(QFile::exists(tunconfpath)) QFile::rename(tunconfpath, backup);//TODO handle errors
|
||||
ofstream outfile;
|
||||
outfile.open(tunconfpath.toStdString());//TODO handle errors
|
||||
outfile << out.str().c_str();
|
||||
outfile.close();
|
||||
}
|
||||
|
||||
//reload saved configs
|
||||
#if 0
|
||||
i2p::client::context.ReloadConfig();
|
||||
#endif
|
||||
|
||||
if(focusOnTunnel) emit reloadTunnelsConfigAndUISignal(QString::fromStdString(tunnelNameToFocus));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SaverImpl::setConfPath(QString& confpath_) { confpath = confpath_; }
|
||||
|
||||
void SaverImpl::setTunnelsConfPath(QString& tunconfpath_) { tunconfpath = tunconfpath_; }
|
||||
|
||||
/*void SaverImpl::setTunnelFocus(bool focusOnTunnel, std::string tunnelNameToFocus) {
|
||||
this->focusOnTunnel=focusOnTunnel;
|
||||
this->tunnelNameToFocus=tunnelNameToFocus;
|
||||
}*/
|
33
qt/i2pd_qt/SaverImpl.h
Normal file
33
qt/i2pd_qt/SaverImpl.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#ifndef SAVERIMPL_H
|
||||
#define SAVERIMPL_H
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include <QObject>
|
||||
#include "QList"
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "TunnelConfig.h"
|
||||
#include "Saver.h"
|
||||
|
||||
class MainWindowItem;
|
||||
class TunnelConfig;
|
||||
|
||||
class SaverImpl : public Saver
|
||||
{
|
||||
public:
|
||||
SaverImpl(MainWindow *mainWindowPtr_, QList<MainWindowItem*> * configItems_, std::map<std::string,TunnelConfig*>* tunnelConfigs_);
|
||||
virtual ~SaverImpl();
|
||||
virtual bool save(const bool focusOnTunnel, const std::string& tunnelNameToFocus);
|
||||
void setConfPath(QString& confpath_);
|
||||
void setTunnelsConfPath(QString& tunconfpath_);
|
||||
private:
|
||||
QList<MainWindowItem*> * configItems;
|
||||
std::map<std::string,TunnelConfig*>* tunnelConfigs;
|
||||
QString confpath;
|
||||
QString tunconfpath;
|
||||
MainWindow* mainWindowPtr;
|
||||
};
|
||||
|
||||
#endif // SAVERIMPL_H
|
|
@ -40,6 +40,9 @@ public:
|
|||
|
||||
class ClientTunnelConfig;
|
||||
class ServerTunnelConfig;
|
||||
|
||||
class TunnelPane;
|
||||
|
||||
class TunnelConfig {
|
||||
/*
|
||||
const char I2P_TUNNELS_SECTION_TYPE_CLIENT[] = "client";
|
||||
|
@ -54,6 +57,7 @@ class TunnelConfig {
|
|||
*/
|
||||
QString type;
|
||||
std::string name;
|
||||
TunnelPane* tunnelPane;
|
||||
public:
|
||||
TunnelConfig(std::string name_, QString& type_, I2CPParameters& i2cpParameters_):
|
||||
type(type_), name(name_), i2cpParameters(i2cpParameters_) {}
|
||||
|
@ -68,7 +72,8 @@ public:
|
|||
virtual void saveToStringStream(std::stringstream& out)=0;
|
||||
virtual ClientTunnelConfig* asClientTunnelConfig()=0;
|
||||
virtual ServerTunnelConfig* asServerTunnelConfig()=0;
|
||||
|
||||
void setTunnelPane(TunnelPane* tp){this->tunnelPane = tp;}
|
||||
TunnelPane* getTunnelPane() {return tunnelPane;}
|
||||
private:
|
||||
I2CPParameters i2cpParameters;
|
||||
};
|
||||
|
|
|
@ -64,7 +64,7 @@ void TunnelPane::setupTunnelPane(
|
|||
|
||||
//type
|
||||
{
|
||||
const QString& type = tunnelConfig->getType();
|
||||
//const QString& type = tunnelConfig->getType();
|
||||
QHBoxLayout * horizontalLayout_ = new QHBoxLayout();
|
||||
horizontalLayout_->setObjectName(QStringLiteral("horizontalLayout_"));
|
||||
typeLabel = new QLabel(gridLayoutWidget_2);
|
||||
|
@ -83,6 +83,11 @@ void TunnelPane::setupTunnelPane(
|
|||
retranslateTunnelForm(*this);
|
||||
}
|
||||
|
||||
void TunnelPane::deleteWidget() {
|
||||
//gridLayoutWidget_2->deleteLater();
|
||||
tunnelGroupBox->deleteLater();
|
||||
}
|
||||
|
||||
void TunnelPane::appendControlsForI2CPParameters(I2CPParameters& i2cpParameters, int& gridIndex) {
|
||||
{
|
||||
//number of hops of an inbound tunnel
|
||||
|
|
|
@ -41,6 +41,8 @@ public:
|
|||
virtual ServerTunnelPane* asServerTunnelPane()=0;
|
||||
virtual ClientTunnelPane* asClientTunnelPane()=0;
|
||||
|
||||
void deleteWidget();
|
||||
|
||||
protected:
|
||||
MainWindow* mainWindow;
|
||||
QWidget * wrongInputPane;
|
||||
|
|
|
@ -2135,121 +2135,6 @@ Comma separated list of base64 identities:</string>
|
|||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="25" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_websock">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>105</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>105</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Websockets server</string>
|
||||
</property>
|
||||
<widget class="QCheckBox" name="checkBoxWebsocketsEnable">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>20</y>
|
||||
<width>85</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QWidget" name="horizontalLayoutWidget_32">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>40</y>
|
||||
<width>661</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_38">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_40">
|
||||
<property name="text">
|
||||
<string>Address to bind websocket server on:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit_webSock_addr"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_26">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="horizontalLayoutWidget_33">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>70</y>
|
||||
<width>661</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_39">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_41">
|
||||
<property name="text">
|
||||
<string>Port to bind websocket server on:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit_webSock_port">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_27">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<widget class="QGroupBox" name="webconsoleGroupBox">
|
||||
<property name="minimumSize">
|
||||
|
|
|
@ -28,7 +28,6 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \
|
|||
../../libi2pd/Datagram.cpp \
|
||||
../../libi2pd/Destination.cpp \
|
||||
../../libi2pd/Ed25519.cpp \
|
||||
../../libi2pd/Event.cpp \
|
||||
../../libi2pd/Family.cpp \
|
||||
../../libi2pd/FS.cpp \
|
||||
../../libi2pd/Garlic.cpp \
|
||||
|
@ -74,8 +73,6 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \
|
|||
../../libi2pd_client/MatchedDestination.cpp \
|
||||
../../libi2pd_client/SAM.cpp \
|
||||
../../libi2pd_client/SOCKS.cpp \
|
||||
../../libi2pd_client/Websocket.cpp \
|
||||
../../libi2pd_client/WebSocks.cpp \
|
||||
../../daemon/Daemon.cpp \
|
||||
../../daemon/HTTPServer.cpp \
|
||||
../../daemon/I2PControl.cpp \
|
||||
|
@ -91,7 +88,11 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \
|
|||
pagewithbackbutton.cpp \
|
||||
widgetlock.cpp \
|
||||
widgetlockregistry.cpp \
|
||||
logviewermanager.cpp
|
||||
logviewermanager.cpp \
|
||||
DelayedSaveManager.cpp \
|
||||
Saver.cpp \
|
||||
DelayedSaveManagerImpl.cpp \
|
||||
SaverImpl.cpp
|
||||
|
||||
HEADERS += DaemonQT.h mainwindow.h \
|
||||
../../libi2pd/api.h \
|
||||
|
@ -107,7 +108,6 @@ HEADERS += DaemonQT.h mainwindow.h \
|
|||
../../libi2pd/Datagram.h \
|
||||
../../libi2pd/Destination.h \
|
||||
../../libi2pd/Ed25519.h \
|
||||
../../libi2pd/Event.h \
|
||||
../../libi2pd/Family.h \
|
||||
../../libi2pd/FS.h \
|
||||
../../libi2pd/Garlic.h \
|
||||
|
@ -161,8 +161,6 @@ HEADERS += DaemonQT.h mainwindow.h \
|
|||
../../libi2pd_client/MatchedDestination.h \
|
||||
../../libi2pd_client/SAM.h \
|
||||
../../libi2pd_client/SOCKS.h \
|
||||
../../libi2pd_client/Websocket.h \
|
||||
../../libi2pd_client/WebSocks.h \
|
||||
../../daemon/Daemon.h \
|
||||
../../daemon/HTTPServer.h \
|
||||
../../daemon/I2PControl.h \
|
||||
|
@ -179,7 +177,11 @@ HEADERS += DaemonQT.h mainwindow.h \
|
|||
widgetlock.h \
|
||||
widgetlockregistry.h \
|
||||
i2pd.rc \
|
||||
logviewermanager.h
|
||||
logviewermanager.h \
|
||||
DelayedSaveManager.h \
|
||||
Saver.h \
|
||||
DelayedSaveManagerImpl.h \
|
||||
SaverImpl.h
|
||||
|
||||
INCLUDEPATH += ../../libi2pd
|
||||
INCLUDEPATH += ../../libi2pd_client
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
#include <fstream>
|
||||
#include <assert.h>
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
#include "ui_statusbuttons.h"
|
||||
#include "ui_routercommandswidget.h"
|
||||
#include "ui_generalsettingswidget.h"
|
||||
#include <sstream>
|
||||
#include <QScrollBar>
|
||||
#include <QMessageBox>
|
||||
#include <QTimer>
|
||||
|
@ -29,17 +26,22 @@
|
|||
|
||||
#include "logviewermanager.h"
|
||||
|
||||
#include "DelayedSaveManagerImpl.h"
|
||||
#include "SaverImpl.h"
|
||||
|
||||
std::string programOptionsWriterCurrentSection;
|
||||
|
||||
MainWindow::MainWindow(std::shared_ptr<std::iostream> logStream_, QWidget *parent) :
|
||||
QMainWindow(parent)
|
||||
,logStream(logStream_)
|
||||
#ifndef ANDROID
|
||||
,quitting(false)
|
||||
#endif
|
||||
,delayedSaveManagerPtr(new DelayedSaveManagerImpl())
|
||||
,dataSerial(DelayedSaveManagerImpl::INITIAL_DATA_SERIAL)
|
||||
,wasSelectingAtStatusMainPage(false)
|
||||
,showHiddenInfoStatusMainPage(false)
|
||||
,logViewerManagerPtr(nullptr)
|
||||
#ifndef ANDROID
|
||||
,quitting(false)
|
||||
#endif
|
||||
,ui(new Ui::MainWindow)
|
||||
,statusButtonsUI(new Ui::StatusButtonsForm)
|
||||
,routerCommandsUI(new Ui::routerCommandsWidget)
|
||||
|
@ -51,9 +53,14 @@ MainWindow::MainWindow(std::shared_ptr<std::iostream> logStream_, QWidget *paren
|
|||
,datadir()
|
||||
,confpath()
|
||||
,tunconfpath()
|
||||
,tunnelConfigs()
|
||||
,tunnelsPageUpdateListener(this)
|
||||
,saverPtr(new SaverImpl(this, &configItems, &tunnelConfigs))
|
||||
|
||||
{
|
||||
assert(delayedSaveManagerPtr!=nullptr);
|
||||
assert(saverPtr!=nullptr);
|
||||
|
||||
ui->setupUi(this);
|
||||
statusButtonsUI->setupUi(ui->statusButtonsPane);
|
||||
routerCommandsUI->setupUi(routerCommandsParent);
|
||||
|
@ -75,7 +82,7 @@ MainWindow::MainWindow(std::shared_ptr<std::iostream> logStream_, QWidget *paren
|
|||
|
||||
ui->stackedWidget->setCurrentIndex(0);
|
||||
ui->settingsScrollArea->resize(uiSettings->settingsContentsGridLayout->sizeHint().width()+10,380);
|
||||
QScrollBar* const barSett = ui->settingsScrollArea->verticalScrollBar();
|
||||
//QScrollBar* const barSett = ui->settingsScrollArea->verticalScrollBar();
|
||||
int w = 683;
|
||||
int h = 3060;
|
||||
ui->settingsContents->setFixedSize(w, h);
|
||||
|
@ -258,10 +265,6 @@ MainWindow::MainWindow(std::shared_ptr<std::iostream> logStream_, QWidget *paren
|
|||
initStringBox( OPTION("trust","routers",[]{return "";}), uiSettings->lineEditTrustRouters);
|
||||
initCheckBox( OPTION("trust","hidden",[]{return "false";}), uiSettings->checkBoxTrustHidden);
|
||||
|
||||
initCheckBox( OPTION("websockets","enabled",[]{return "false";}), uiSettings->checkBoxWebsocketsEnable);
|
||||
initIPAddressBox( OPTION("websockets","address",[]{return "127.0.0.1";}), uiSettings->lineEdit_webSock_addr, tr("Websocket server -> IP address"));
|
||||
initTCPPortBox( OPTION("websockets","port",[]{return "7666";}), uiSettings->lineEdit_webSock_port, tr("Websocket server -> Port"));
|
||||
|
||||
# undef OPTION
|
||||
|
||||
//widgetlocks.add(new widgetlock(widget,lockbtn));
|
||||
|
@ -270,7 +273,13 @@ MainWindow::MainWindow(std::shared_ptr<std::iostream> logStream_, QWidget *paren
|
|||
widgetlocks.add(new widgetlock(uiSettings->comboBox_httpPorxySignatureType,uiSettings->httpProxySignTypeComboEditPushButton));
|
||||
widgetlocks.add(new widgetlock(uiSettings->comboBox_socksProxySignatureType,uiSettings->socksProxySignTypeComboEditPushButton));
|
||||
|
||||
loadAllConfigs();
|
||||
loadAllConfigs(saverPtr);
|
||||
|
||||
QObject::connect(saverPtr, SIGNAL(reloadTunnelsConfigAndUISignal(const QString)),
|
||||
this, SLOT(reloadTunnelsConfigAndUI_QString(const QString)));
|
||||
|
||||
delayedSaveManagerPtr->setSaver(saverPtr);
|
||||
delayedSaveManagerPtr->start();
|
||||
|
||||
QObject::connect(uiSettings->logDestinationComboBox, SIGNAL(currentIndexChanged(const QString &)),
|
||||
this, SLOT(logDestinationComboBoxValueChanged(const QString &)));
|
||||
|
@ -292,7 +301,6 @@ MainWindow::MainWindow(std::shared_ptr<std::iostream> logStream_, QWidget *paren
|
|||
|
||||
QObject::connect(uiSettings->tunnelsConfigFileLineEdit, SIGNAL(textChanged(const QString &)),
|
||||
this, SLOT(reloadTunnelsConfigAndUI()));
|
||||
|
||||
QObject::connect(ui->addServerTunnelPushButton, SIGNAL(released()), this, SLOT(addServerTunnelPushButtonReleased()));
|
||||
QObject::connect(ui->addClientTunnelPushButton, SIGNAL(released()), this, SLOT(addClientTunnelPushButtonReleased()));
|
||||
|
||||
|
@ -307,7 +315,7 @@ MainWindow::MainWindow(std::shared_ptr<std::iostream> logStream_, QWidget *paren
|
|||
|
||||
logViewerManagerPtr=new LogViewerManager(logStream_,ui->logViewerTextEdit,this);
|
||||
assert(logViewerManagerPtr!=nullptr);
|
||||
onLoggingOptionsChange();
|
||||
//onLoggingOptionsChange();
|
||||
//QMetaObject::connectSlotsByName(this);
|
||||
}
|
||||
|
||||
|
@ -500,6 +508,8 @@ void MainWindow::handleQuitButton() {
|
|||
quitting=true;
|
||||
#endif
|
||||
close();
|
||||
delayedSaveManagerPtr->appExiting();
|
||||
qDebug("Performing quit");
|
||||
QApplication::instance()->quit();
|
||||
}
|
||||
|
||||
|
@ -526,6 +536,7 @@ void MainWindow::handleGracefulQuitTimerEvent() {
|
|||
quitting=true;
|
||||
#endif
|
||||
close();
|
||||
delayedSaveManagerPtr->appExiting();
|
||||
qDebug("Performing quit");
|
||||
QApplication::instance()->quit();
|
||||
}
|
||||
|
@ -534,6 +545,8 @@ MainWindow::~MainWindow()
|
|||
{
|
||||
qDebug("Destroying main window");
|
||||
delete statusPageUpdateTimer;
|
||||
delete delayedSaveManagerPtr;
|
||||
delete saverPtr;
|
||||
for(QList<MainWindowItem*>::iterator it = configItems.begin(); it!= configItems.end(); ++it) {
|
||||
MainWindowItem* item = *it;
|
||||
item->deleteLater();
|
||||
|
@ -594,7 +607,7 @@ NonGUIOptionItem* MainWindow::initNonGUIOption(ConfigOption option) {
|
|||
return retValue;
|
||||
}
|
||||
|
||||
void MainWindow::loadAllConfigs(){
|
||||
void MainWindow::loadAllConfigs(SaverImpl* saverPtr){
|
||||
|
||||
//BORROWED FROM ??? //TODO move this code into single location
|
||||
std::string config; i2p::config::GetOption("conf", config);
|
||||
|
@ -635,6 +648,9 @@ void MainWindow::loadAllConfigs(){
|
|||
this->datadir = datadir.c_str();
|
||||
this->tunconfpath = tunConf.c_str();
|
||||
|
||||
saverPtr->setConfPath(this->confpath);
|
||||
saverPtr->setTunnelsConfPath(this->tunconfpath);
|
||||
|
||||
for(QList<MainWindowItem*>::iterator it = configItems.begin(); it!= configItems.end(); ++it) {
|
||||
MainWindowItem* item = *it;
|
||||
item->loadFromConfigOption();
|
||||
|
@ -642,10 +658,40 @@ void MainWindow::loadAllConfigs(){
|
|||
|
||||
ReadTunnelsConfig();
|
||||
|
||||
onLoggingOptionsChange();
|
||||
//onLoggingOptionsChange();
|
||||
}
|
||||
|
||||
void MainWindow::layoutTunnels() {
|
||||
|
||||
int height=0;
|
||||
ui->tunnelsScrollAreaWidgetContents->setGeometry(0,0,0,0);
|
||||
for(std::map<std::string, TunnelConfig*>::iterator it = tunnelConfigs.begin(); it != tunnelConfigs.end(); ++it) {
|
||||
const std::string& name=it->first;
|
||||
TunnelConfig* tunconf = it->second;
|
||||
TunnelPane * tunnelPane=tunconf->getTunnelPane();
|
||||
if(!tunnelPane)continue;
|
||||
int h=tunnelPane->height();
|
||||
height+=h;
|
||||
//qDebug() << "tun.height:" << height << "sz:" << tunnelPanes.size();
|
||||
//int h=tunnelPane->appendClientTunnelForm(ctc, ui->tunnelsScrollAreaWidgetContents, tunnelPanes.size(), height);
|
||||
}
|
||||
//qDebug() << "tun.setting height:" << height;
|
||||
ui->tunnelsScrollAreaWidgetContents->setGeometry(QRect(0, 0, 621, height));
|
||||
/*QList<QWidget*> childWidgets = ui->tunnelsScrollAreaWidgetContents->findChildren<QWidget*>();
|
||||
foreach(QWidget* widget, childWidgets)
|
||||
widget->show();*/
|
||||
}
|
||||
|
||||
void MainWindow::deleteTunnelFromUI(std::string tunnelName, TunnelConfig* cnf) {
|
||||
TunnelPane* tp = cnf->getTunnelPane();
|
||||
if(!tp)return;
|
||||
tunnelPanes.remove(tp);
|
||||
tp->deleteWidget();
|
||||
layoutTunnels();
|
||||
}
|
||||
|
||||
/** returns false iff not valid items present and save was aborted */
|
||||
bool MainWindow::saveAllConfigs(){
|
||||
bool MainWindow::saveAllConfigs(bool focusOnTunnel, std::string tunnelNameToFocus){
|
||||
QString cannotSaveSettings = QApplication::tr("Cannot save settings.");
|
||||
programOptionsWriterCurrentSection="";
|
||||
/*if(!logFileNameOption->lineEdit->text().trimmed().isEmpty())logOption->optionValue=boost::any(std::string("file"));
|
||||
|
@ -653,7 +699,6 @@ bool MainWindow::saveAllConfigs(){
|
|||
daemonOption->optionValue=boost::any(false);
|
||||
serviceOption->optionValue=boost::any(false);
|
||||
|
||||
std::stringstream out;
|
||||
for(QList<MainWindowItem*>::iterator it = configItems.begin(); it!= configItems.end(); ++it) {
|
||||
MainWindowItem* item = *it;
|
||||
if(!item->isValid()){
|
||||
|
@ -661,27 +706,9 @@ bool MainWindow::saveAllConfigs(){
|
|||
return false;
|
||||
}
|
||||
}
|
||||
delayedSaveManagerPtr->delayedSave(++dataSerial, focusOnTunnel, tunnelNameToFocus);
|
||||
|
||||
for(QList<MainWindowItem*>::iterator it = configItems.begin(); it!= configItems.end(); ++it) {
|
||||
MainWindowItem* item = *it;
|
||||
item->saveToStringStream(out);
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
QString backup=confpath+"~";
|
||||
if(QFile::exists(backup)) QFile::remove(backup);//TODO handle errors
|
||||
if(QFile::exists(confpath)) QFile::rename(confpath, backup);//TODO handle errors
|
||||
ofstream outfile;
|
||||
outfile.open(confpath.toStdString());//TODO handle errors
|
||||
outfile << out.str().c_str();
|
||||
outfile.close();
|
||||
|
||||
SaveTunnelsConfig();
|
||||
|
||||
onLoggingOptionsChange();
|
||||
|
||||
//onLoggingOptionsChange();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -711,7 +738,7 @@ void MainWindow::updated() {
|
|||
adjustSizesAccordingToWrongLabel();
|
||||
|
||||
applyTunnelsUiToConfigs();
|
||||
saveAllConfigs();
|
||||
saveAllConfigs(false);
|
||||
}
|
||||
|
||||
void MainWindowItem::installListeners(MainWindow *mainWindow) {}
|
||||
|
@ -725,6 +752,7 @@ void MainWindow::appendTunnelForms(std::string tunnelNameToFocus) {
|
|||
ServerTunnelConfig* stc = tunconf->asServerTunnelConfig();
|
||||
if(stc){
|
||||
ServerTunnelPane * tunnelPane=new ServerTunnelPane(&tunnelsPageUpdateListener, stc, ui->wrongInputLabel, ui->wrongInputLabel, this);
|
||||
tunconf->setTunnelPane(tunnelPane);
|
||||
int h=tunnelPane->appendServerTunnelForm(stc, ui->tunnelsScrollAreaWidgetContents, tunnelPanes.size(), height);
|
||||
height+=h;
|
||||
//qDebug() << "tun.height:" << height << "sz:" << tunnelPanes.size();
|
||||
|
@ -738,6 +766,7 @@ void MainWindow::appendTunnelForms(std::string tunnelNameToFocus) {
|
|||
ClientTunnelConfig* ctc = tunconf->asClientTunnelConfig();
|
||||
if(ctc){
|
||||
ClientTunnelPane * tunnelPane=new ClientTunnelPane(&tunnelsPageUpdateListener, ctc, ui->wrongInputLabel, ui->wrongInputLabel, this);
|
||||
tunconf->setTunnelPane(tunnelPane);
|
||||
int h=tunnelPane->appendClientTunnelForm(ctc, ui->tunnelsScrollAreaWidgetContents, tunnelPanes.size(), height);
|
||||
height+=h;
|
||||
//qDebug() << "tun.height:" << height << "sz:" << tunnelPanes.size();
|
||||
|
@ -784,6 +813,10 @@ bool MainWindow::applyTunnelsUiToConfigs() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::reloadTunnelsConfigAndUI_QString(const QString tunnelNameToFocus) {
|
||||
reloadTunnelsConfigAndUI(tunnelNameToFocus.toStdString());
|
||||
}
|
||||
|
||||
void MainWindow::reloadTunnelsConfigAndUI(std::string tunnelNameToFocus) {
|
||||
deleteTunnelForms();
|
||||
for (std::map<std::string,TunnelConfig*>::iterator it=tunnelConfigs.begin(); it!=tunnelConfigs.end(); ++it) {
|
||||
|
@ -795,31 +828,6 @@ void MainWindow::reloadTunnelsConfigAndUI(std::string tunnelNameToFocus) {
|
|||
appendTunnelForms(tunnelNameToFocus);
|
||||
}
|
||||
|
||||
void MainWindow::SaveTunnelsConfig() {
|
||||
std::stringstream out;
|
||||
|
||||
for (std::map<std::string,TunnelConfig*>::iterator it=tunnelConfigs.begin(); it!=tunnelConfigs.end(); ++it) {
|
||||
const std::string& name = it->first;
|
||||
TunnelConfig* tunconf = it->second;
|
||||
tunconf->saveHeaderToStringStream(out);
|
||||
tunconf->saveToStringStream(out);
|
||||
tunconf->saveI2CPParametersToStringStream(out);
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
QString backup=tunconfpath+"~";
|
||||
if(QFile::exists(backup)) QFile::remove(backup);//TODO handle errors
|
||||
if(QFile::exists(tunconfpath)) QFile::rename(tunconfpath, backup);//TODO handle errors
|
||||
ofstream outfile;
|
||||
outfile.open(tunconfpath.toStdString());//TODO handle errors
|
||||
outfile << out.str().c_str();
|
||||
outfile.close();
|
||||
|
||||
i2p::client::context.ReloadConfig();
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::TunnelsPageUpdateListenerMainWindowImpl::updated(std::string oldName, TunnelConfig* tunConf) {
|
||||
if(oldName!=tunConf->getName()) {
|
||||
//name has changed
|
||||
|
@ -827,7 +835,7 @@ void MainWindow::TunnelsPageUpdateListenerMainWindowImpl::updated(std::string ol
|
|||
if(it!=mainWindow->tunnelConfigs.end())mainWindow->tunnelConfigs.erase(it);
|
||||
mainWindow->tunnelConfigs[tunConf->getName()]=tunConf;
|
||||
}
|
||||
mainWindow->saveAllConfigs();
|
||||
mainWindow->saveAllConfigs(true, tunConf->getName());
|
||||
}
|
||||
|
||||
void MainWindow::TunnelsPageUpdateListenerMainWindowImpl::needsDeleting(std::string oldName){
|
||||
|
@ -875,7 +883,8 @@ void MainWindow::anchorClickedHandler(const QUrl & link) {
|
|||
pageWithBackButton->show();
|
||||
textBrowser->hide();
|
||||
std::stringstream s;
|
||||
i2p::http::ShowLocalDestination(s,str.toStdString());
|
||||
std::string strstd = str.toStdString();
|
||||
i2p::http::ShowLocalDestination(s,strstd,0);
|
||||
childTextBrowser->setHtml(QString::fromStdString(s.str()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,12 @@
|
|||
#include "widgetlockregistry.h"
|
||||
#include "widgetlock.h"
|
||||
|
||||
#include "DelayedSaveManager.h"
|
||||
#include "DelayedSaveManagerImpl.h"
|
||||
#include "SaverImpl.h"
|
||||
|
||||
class SaverImpl;
|
||||
|
||||
class LogViewerManager;
|
||||
|
||||
template<typename ValueType>
|
||||
|
@ -373,10 +379,14 @@ using namespace i2p::qt;
|
|||
|
||||
class Controller;
|
||||
|
||||
class DelayedSaveManagerImpl;
|
||||
|
||||
class MainWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
private:
|
||||
std::shared_ptr<std::iostream> logStream;
|
||||
DelayedSaveManagerImpl* delayedSaveManagerPtr;
|
||||
DelayedSaveManager::DATA_SERIAL_TYPE dataSerial;
|
||||
public:
|
||||
explicit MainWindow(std::shared_ptr<std::iostream> logStream_, QWidget *parent=nullptr);
|
||||
~MainWindow();
|
||||
|
@ -502,16 +512,17 @@ protected:
|
|||
void initStringBox(ConfigOption option, QLineEdit* lineEdit);
|
||||
NonGUIOptionItem* initNonGUIOption(ConfigOption option);
|
||||
|
||||
void loadAllConfigs();
|
||||
void loadAllConfigs(SaverImpl* saverPtr);
|
||||
void layoutTunnels();
|
||||
|
||||
public slots:
|
||||
/** returns false iff not valid items present and save was aborted */
|
||||
bool saveAllConfigs();
|
||||
void SaveTunnelsConfig();
|
||||
bool saveAllConfigs(bool focusOnTunnel, std::string tunnelNameToFocus="");
|
||||
void reloadTunnelsConfigAndUI(std::string tunnelNameToFocus);
|
||||
|
||||
//focus none
|
||||
void reloadTunnelsConfigAndUI() { reloadTunnelsConfigAndUI(""); }
|
||||
void reloadTunnelsConfigAndUI_QString(const QString tunnelNameToFocus);
|
||||
void addServerTunnelPushButtonReleased();
|
||||
void addClientTunnelPushButtonReleased();
|
||||
|
||||
|
@ -530,6 +541,7 @@ private:
|
|||
|
||||
void appendTunnelForms(std::string tunnelNameToFocus);
|
||||
void deleteTunnelForms();
|
||||
void deleteTunnelFromUI(std::string tunnelName, TunnelConfig* cnf);
|
||||
|
||||
template<typename Section, typename Type>
|
||||
std::string GetI2CPOption (const Section& section, const std::string& name, const Type& value) const
|
||||
|
@ -575,11 +587,11 @@ private:
|
|||
std::map<std::string,TunnelConfig*>::const_iterator it=tunnelConfigs.find(name);
|
||||
if(it!=tunnelConfigs.end()){
|
||||
TunnelConfig* tc=it->second;
|
||||
deleteTunnelFromUI(name, tc);
|
||||
tunnelConfigs.erase(it);
|
||||
delete tc;
|
||||
}
|
||||
saveAllConfigs();
|
||||
reloadTunnelsConfigAndUI("");
|
||||
saveAllConfigs(false);
|
||||
}
|
||||
|
||||
std::string GenerateNewTunnelName() {
|
||||
|
@ -614,8 +626,7 @@ private:
|
|||
destinationPort,
|
||||
sigType);
|
||||
|
||||
saveAllConfigs();
|
||||
reloadTunnelsConfigAndUI(name);
|
||||
saveAllConfigs(true, name);
|
||||
}
|
||||
|
||||
void CreateDefaultServerTunnel() {//TODO dedup default values with ReadTunnelsConfig() and with ClientContext.cpp::ReadTunnels ()
|
||||
|
@ -651,8 +662,7 @@ private:
|
|||
isUniqueLocal);
|
||||
|
||||
|
||||
saveAllConfigs();
|
||||
reloadTunnelsConfigAndUI(name);
|
||||
saveAllConfigs(true, name);
|
||||
}
|
||||
|
||||
void ReadTunnelsConfig() //TODO deduplicate the code with ClientContext.cpp::ReadTunnels ()
|
||||
|
@ -793,7 +803,9 @@ private:
|
|||
|
||||
TunnelsPageUpdateListenerMainWindowImpl tunnelsPageUpdateListener;
|
||||
|
||||
void onLoggingOptionsChange() {}
|
||||
//void onLoggingOptionsChange() {}
|
||||
|
||||
SaverImpl* saverPtr;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
Loading…
Add table
Reference in a new issue