diff --git a/.gitignore b/.gitignore index 5424262f..353d839f 100644 --- a/.gitignore +++ b/.gitignore @@ -262,3 +262,5 @@ qt/i2pd_qt/*.ui.autosave qt/i2pd_qt/*.ui.bk* qt/i2pd_qt/*.ui_* +#unknown android stuff +android/libs/ diff --git a/Makefile b/Makefile index 989f8586..a8514826 100644 --- a/Makefile +++ b/Makefile @@ -89,14 +89,14 @@ $(SHLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC)) $(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^ $(ARLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC)) - ar -r $@ $^ + $(AR) -r $@ $^ $(ARLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC)) - ar -r $@ $^ + $(AR) -r $@ $^ clean: - rm -rf obj - rm -rf docs/generated + $(RM) -r obj + $(RM) -r docs/generated $(RM) $(I2PD) $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT) strip: $(I2PD) $(SHLIB_CLIENT) $(SHLIB) diff --git a/Makefile.homebrew b/Makefile.homebrew index 1cce3232..4f69ae36 100644 --- a/Makefile.homebrew +++ b/Makefile.homebrew @@ -1,17 +1,29 @@ # root directory holding homebrew -BREWROOT = /usr/local/ +BREWROOT = /usr/local BOOSTROOT = ${BREWROOT}/opt/boost SSLROOT = ${BREWROOT}/opt/libressl +UPNPROOT = ${BREWROOT}/opt/miniupnpc CXX = clang++ -CXXFLAGS = -g -Wall -std=c++11 -DMAC_OSX -INCFLAGS = -I${SSLROOT}/include -I${BOOSTROOT}/include +CXXFLAGS = -g -Wall -std=c++11 -DMAC_OSX -Wno-overloaded-virtual +INCFLAGS = -I${SSLROOT}/include -I${BOOSTROOT}/include + +ifeq ($(USE_STATIC),yes) +LDLIBS = -lz ${SSLROOT}/lib/libcrypto.a ${SSLROOT}/lib/libssl.a ${BOOSTROOT}/lib/libboost_system.a ${BOOSTROOT}/lib/libboost_date_time.a ${BOOSTROOT}/lib/libboost_filesystem.a ${BOOSTROOT}/lib/libboost_program_options.a -lpthread +else LDFLAGS = -L${SSLROOT}/lib -L${BOOSTROOT}/lib LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread +endif ifeq ($(USE_UPNP),yes) LDFLAGS += -ldl CXXFLAGS += -DUSE_UPNP - LDLIBS += -lminiupnpc + INCFLAGS += -I${UPNPROOT}/include + ifeq ($(USE_STATIC),yes) + LDLIBS += ${UPNPROOT}/lib/libminiupnpc.a + else + LDFLAGS += -L${UPNPROOT}/lib + LDLIBS += -lminiupnpc + endif endif # OSX Notes diff --git a/Makefile.mingw b/Makefile.mingw index d6fedd7b..5b9332e2 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -47,8 +47,7 @@ ifeq ($(USE_AVX),1) endif ifeq ($(USE_ASLR),yes) - LDFLAGS += -Wl,--nxcompat -Wl,--high-entropy-va \ - -Wl,--dynamicbase,--export-all-symbols + LDFLAGS += -Wl,--nxcompat -Wl,--high-entropy-va -Wl,--dynamicbase,--export-all-symbols endif obj/%.o : %.rc diff --git a/Win32/DaemonWin32.cpp b/Win32/DaemonWin32.cpp index 698cf390..3f9226d1 100644 --- a/Win32/DaemonWin32.cpp +++ b/Win32/DaemonWin32.cpp @@ -6,7 +6,6 @@ #include "Log.h" #ifdef _WIN32 - #include "Win32/Win32Service.h" #ifdef WIN32_APP #include "Win32/Win32App.h" @@ -14,99 +13,99 @@ namespace i2p { - namespace util +namespace util +{ + bool DaemonWin32::init(int argc, char* argv[]) { - bool DaemonWin32::init(int argc, char* argv[]) + setlocale(LC_CTYPE, ""); + SetConsoleCP(1251); + SetConsoleOutputCP(1251); + setlocale(LC_ALL, "Russian"); + + if (!Daemon_Singleton::init(argc, argv)) + return false; + + std::string serviceControl; i2p::config::GetOption("svcctl", serviceControl); + if (serviceControl == "install") { - setlocale(LC_CTYPE, ""); - SetConsoleCP(1251); - SetConsoleOutputCP(1251); - setlocale(LC_ALL, "Russian"); - - if (!Daemon_Singleton::init(argc, argv)) - return false; - - std::string serviceControl; i2p::config::GetOption("svcctl", serviceControl); - if (serviceControl == "install") - { - LogPrint(eLogInfo, "WinSVC: installing ", SERVICE_NAME, " as service"); - InstallService( - SERVICE_NAME, // Name of service - SERVICE_DISPLAY_NAME, // Name to display - SERVICE_START_TYPE, // Service start type - SERVICE_DEPENDENCIES, // Dependencies - SERVICE_ACCOUNT, // Service running account - SERVICE_PASSWORD // Password of the account - ); - return false; - } - else if (serviceControl == "remove") - { - LogPrint(eLogInfo, "WinSVC: uninstalling ", SERVICE_NAME, " service"); - UninstallService(SERVICE_NAME); - return false; - } - - if (isDaemon) - { - LogPrint(eLogDebug, "Daemon: running as service"); - I2PService service(SERVICE_NAME); - if (!I2PService::Run(service)) - { - LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError()); - return false; - } - return false; - } - else - LogPrint(eLogDebug, "Daemon: running as user"); - return true; + LogPrint(eLogInfo, "WinSVC: installing ", SERVICE_NAME, " as service"); + InstallService( + SERVICE_NAME, // Name of service + SERVICE_DISPLAY_NAME, // Name to display + SERVICE_START_TYPE, // Service start type + SERVICE_DEPENDENCIES, // Dependencies + SERVICE_ACCOUNT, // Service running account + SERVICE_PASSWORD // Password of the account + ); + return false; + } + else if (serviceControl == "remove") + { + LogPrint(eLogInfo, "WinSVC: uninstalling ", SERVICE_NAME, " service"); + UninstallService(SERVICE_NAME); + return false; } - bool DaemonWin32::start() + if (isDaemon) { - setlocale(LC_CTYPE, ""); - SetConsoleCP(1251); - SetConsoleOutputCP(1251); - setlocale(LC_ALL, "Russian"); -#ifdef WIN32_APP - if (!i2p::win32::StartWin32App ()) return false; + LogPrint(eLogDebug, "Daemon: running as service"); + I2PService service(SERVICE_NAME); + if (!I2PService::Run(service)) + { + LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError()); + return false; + } + return false; + } + else + LogPrint(eLogDebug, "Daemon: running as user"); + return true; + } - // override log - i2p::config::SetOption("log", std::string ("file")); + bool DaemonWin32::start() + { + setlocale(LC_CTYPE, ""); + SetConsoleCP(1251); + SetConsoleOutputCP(1251); + setlocale(LC_ALL, "Russian"); +#ifdef WIN32_APP + if (!i2p::win32::StartWin32App ()) return false; + + // override log + i2p::config::SetOption("log", std::string ("file")); #endif - bool ret = Daemon_Singleton::start(); - if (ret && i2p::log::Logger().GetLogType() == eLogFile) - { - // TODO: find out where this garbage to console comes from - SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE); - SetStdHandle(STD_ERROR_HANDLE, INVALID_HANDLE_VALUE); - } - bool insomnia; i2p::config::GetOption("insomnia", insomnia); - if (insomnia) - SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED); - return ret; - } - - bool DaemonWin32::stop() + bool ret = Daemon_Singleton::start(); + if (ret && i2p::log::Logger().GetLogType() == eLogFile) { + // TODO: find out where this garbage to console comes from + SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE); + SetStdHandle(STD_ERROR_HANDLE, INVALID_HANDLE_VALUE); + } + bool insomnia; i2p::config::GetOption("insomnia", insomnia); + if (insomnia) + SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED); + return ret; + } + + bool DaemonWin32::stop() + { #ifdef WIN32_APP - i2p::win32::StopWin32App (); + i2p::win32::StopWin32App (); #endif - return Daemon_Singleton::stop(); - } + return Daemon_Singleton::stop(); + } - void DaemonWin32::run () - { + void DaemonWin32::run () + { #ifdef WIN32_APP - i2p::win32::RunWin32App (); + i2p::win32::RunWin32App (); #else - while (running) + while (running) { std::this_thread::sleep_for (std::chrono::seconds(1)); } #endif - } } } -#endif +} +#endif //_WIN32 diff --git a/Win32/Win32App.cpp b/Win32/Win32App.cpp index e66b5f08..4c7eae03 100644 --- a/Win32/Win32App.cpp +++ b/Win32/Win32App.cpp @@ -9,6 +9,7 @@ #include "Tunnel.h" #include "version.h" #include "resource.h" +#include "Daemon.h" #include "Win32App.h" #include @@ -21,6 +22,8 @@ #define ID_CONSOLE 2002 #define ID_APP 2003 #define ID_GRACEFUL_SHUTDOWN 2004 +#define ID_STOP_GRACEFUL_SHUTDOWN 2005 +#define ID_RELOAD 2006 #define ID_TRAY_ICON 2050 #define WM_TRAYICON (WM_USER + 1) @@ -39,7 +42,11 @@ namespace win32 InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_APP, "Show app"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_ABOUT, "&About..."); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); - InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_GRACEFUL_SHUTDOWN, "&Graceful shutdown"); + InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_RELOAD, "&Reload configs"); + if (!i2p::util::DaemonWin32::Instance ().isGraceful) + InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_GRACEFUL_SHUTDOWN, "&Graceful shutdown"); + else + InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_STOP_GRACEFUL_SHUTDOWN, "&Stop graceful shutdown"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_EXIT, "E&xit"); SetMenuDefaultItem (hPopup, ID_CONSOLE, FALSE); SendMessage (hWnd, WM_INITMENUPOPUP, (WPARAM)hPopup, 0); @@ -68,7 +75,7 @@ namespace win32 nid.uCallbackMessage = WM_TRAYICON; nid.hIcon = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE (MAINICON)); strcpy (nid.szTip, "i2pd"); - strcpy (nid.szInfo, "i2pd is running"); + strcpy (nid.szInfo, "i2pd is starting"); Shell_NotifyIcon(NIM_ADD, &nid ); } @@ -120,6 +127,7 @@ namespace win32 static void PrintMainWindowText (std::stringstream& s) { + s << "\n"; s << "Status: "; switch (i2p::context.GetStatus()) { @@ -153,6 +161,7 @@ namespace win32 s << "In: " << i2p::tunnel::tunnels.CountInboundTunnels() << "; "; s << "Out: " << i2p::tunnel::tunnels.CountOutboundTunnels() << "; "; s << "Transit: " << i2p::tunnel::tunnels.CountTransitTunnels() << "\n"; + s << "\n"; } static LRESULT CALLBACK WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) @@ -192,6 +201,22 @@ namespace win32 { i2p::context.SetAcceptsTunnels (false); SetTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER, 10*60*1000, nullptr); // 10 minutes + i2p::util::DaemonWin32::Instance ().isGraceful = true; + return 0; + } + case ID_STOP_GRACEFUL_SHUTDOWN: + { + i2p::context.SetAcceptsTunnels (true); + KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER); + i2p::util::DaemonWin32::Instance ().isGraceful = false; + return 0; + } + case ID_RELOAD: + { + i2p::client::context.ReloadConfig(); + std::stringstream text; + text << "I2Pd reloading configs..."; + MessageBox( hWnd, TEXT(text.str ().c_str ()), TEXT("i2pd"), MB_ICONINFORMATION | MB_OK ); return 0; } case ID_CONSOLE: @@ -322,7 +347,7 @@ namespace win32 wclx.lpszClassName = I2PD_WIN32_CLASSNAME; RegisterClassEx (&wclx); // create new window - if (!CreateWindow(I2PD_WIN32_CLASSNAME, TEXT("i2pd"), WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, 100, 100, 350, 180, NULL, NULL, hInst, NULL)) + if (!CreateWindow(I2PD_WIN32_CLASSNAME, TEXT("i2pd"), WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, 100, 100, 350, 210, NULL, NULL, hInst, NULL)) { MessageBox(NULL, "Failed to create main window", TEXT("Warning!"), MB_ICONERROR | MB_OK | MB_TOPMOST); return false; @@ -353,5 +378,14 @@ namespace win32 PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_GRACEFUL_SHUTDOWN, 0), 0); return hWnd; } + + bool StopGracefulShutdown () + { + HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")); + if (hWnd) + PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_STOP_GRACEFUL_SHUTDOWN, 0), 0); + return hWnd; + } + } } diff --git a/Win32/Win32App.h b/Win32/Win32App.h index 3babffa9..b230eb06 100644 --- a/Win32/Win32App.h +++ b/Win32/Win32App.h @@ -7,10 +7,11 @@ namespace i2p { namespace win32 { - bool StartWin32App (); - void StopWin32App (); - int RunWin32App (); - bool GracefulShutdown (); + bool StartWin32App (); + void StopWin32App (); + int RunWin32App (); + bool GracefulShutdown (); + bool StopGracefulShutdown (); } } #endif // WIN32APP_H__ diff --git a/Win32/Win32Service.cpp b/Win32/Win32Service.cpp index d3785999..4a0058ac 100644 --- a/Win32/Win32Service.cpp +++ b/Win32/Win32Service.cpp @@ -15,7 +15,6 @@ I2PService *I2PService::s_service = NULL; BOOL I2PService::isService() { BOOL bIsService = FALSE; - HWINSTA hWinStation = GetProcessWindowStation(); if (hWinStation != NULL) { @@ -31,28 +30,23 @@ BOOL I2PService::isService() BOOL I2PService::Run(I2PService &service) { s_service = &service; - SERVICE_TABLE_ENTRY serviceTable[] = { { service.m_name, ServiceMain }, { NULL, NULL } }; - return StartServiceCtrlDispatcher(serviceTable); } - void WINAPI I2PService::ServiceMain(DWORD dwArgc, PSTR *pszArgv) { assert(s_service != NULL); - s_service->m_statusHandle = RegisterServiceCtrlHandler( s_service->m_name, ServiceCtrlHandler); if (s_service->m_statusHandle == NULL) { throw GetLastError(); } - s_service->Start(dwArgc, pszArgv); } @@ -61,12 +55,12 @@ void WINAPI I2PService::ServiceCtrlHandler(DWORD dwCtrl) { switch (dwCtrl) { - case SERVICE_CONTROL_STOP: s_service->Stop(); break; - case SERVICE_CONTROL_PAUSE: s_service->Pause(); break; - case SERVICE_CONTROL_CONTINUE: s_service->Continue(); break; - case SERVICE_CONTROL_SHUTDOWN: s_service->Shutdown(); break; - case SERVICE_CONTROL_INTERROGATE: break; - default: break; + case SERVICE_CONTROL_STOP: s_service->Stop(); break; + case SERVICE_CONTROL_PAUSE: s_service->Pause(); break; + case SERVICE_CONTROL_CONTINUE: s_service->Continue(); break; + case SERVICE_CONTROL_SHUTDOWN: s_service->Shutdown(); break; + case SERVICE_CONTROL_INTERROGATE: break; + default: break; } } @@ -76,11 +70,8 @@ I2PService::I2PService(PSTR pszServiceName, BOOL fCanPauseContinue) { m_name = (pszServiceName == NULL) ? (PSTR)"" : pszServiceName; - m_statusHandle = NULL; - m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - m_status.dwCurrentState = SERVICE_START_PENDING; DWORD dwControlsAccepted = 0; @@ -90,15 +81,13 @@ I2PService::I2PService(PSTR pszServiceName, dwControlsAccepted |= SERVICE_ACCEPT_SHUTDOWN; if (fCanPauseContinue) dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE; - m_status.dwControlsAccepted = dwControlsAccepted; + m_status.dwControlsAccepted = dwControlsAccepted; m_status.dwWin32ExitCode = NO_ERROR; m_status.dwServiceSpecificExitCode = 0; m_status.dwCheckPoint = 0; m_status.dwWaitHint = 0; - m_fStopping = FALSE; - // Create a manual-reset event that is not signaled at first to indicate // the stopped signal of the service. m_hStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); @@ -108,7 +97,6 @@ I2PService::I2PService(PSTR pszServiceName, } } - I2PService::~I2PService(void) { if (m_hStoppedEvent) @@ -118,92 +106,73 @@ I2PService::~I2PService(void) } } - void I2PService::Start(DWORD dwArgc, PSTR *pszArgv) { try { SetServiceStatus(SERVICE_START_PENDING); - OnStart(dwArgc, pszArgv); - SetServiceStatus(SERVICE_RUNNING); } catch (DWORD dwError) { LogPrint(eLogError, "Win32Service Start", dwError); - SetServiceStatus(SERVICE_STOPPED, dwError); } catch (...) { LogPrint(eLogError, "Win32Service failed to start.", EVENTLOG_ERROR_TYPE); - SetServiceStatus(SERVICE_STOPPED); } } - void I2PService::OnStart(DWORD dwArgc, PSTR *pszArgv) { LogPrint(eLogInfo, "Win32Service in OnStart", EVENTLOG_INFORMATION_TYPE); - Daemon.start(); - //i2p::util::config::OptionParser(dwArgc, pszArgv); //i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs); //i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"), // i2p::util::config::GetArg("-port", 17070)); - _worker = new std::thread(std::bind(&I2PService::WorkerThread, this)); } - void I2PService::WorkerThread() { while (!m_fStopping) { ::Sleep(1000); // Simulate some lengthy operations. } - // Signal the stopped event. SetEvent(m_hStoppedEvent); } - void I2PService::Stop() { DWORD dwOriginalState = m_status.dwCurrentState; try { SetServiceStatus(SERVICE_STOP_PENDING); - OnStop(); - SetServiceStatus(SERVICE_STOPPED); } catch (DWORD dwError) { LogPrint(eLogInfo, "Win32Service Stop", dwError); - SetServiceStatus(dwOriginalState); } catch (...) { LogPrint(eLogError, "Win32Service failed to stop.", EVENTLOG_ERROR_TYPE); - SetServiceStatus(dwOriginalState); } } - void I2PService::OnStop() { // Log a service stop message to the Application log. LogPrint(eLogInfo, "Win32Service in OnStop", EVENTLOG_INFORMATION_TYPE); - Daemon.stop(); - m_fStopping = TRUE; if (WaitForSingleObject(m_hStoppedEvent, INFINITE) != WAIT_OBJECT_0) { @@ -213,57 +182,46 @@ void I2PService::OnStop() delete _worker; } - void I2PService::Pause() { try { SetServiceStatus(SERVICE_PAUSE_PENDING); - OnPause(); - SetServiceStatus(SERVICE_PAUSED); } catch (DWORD dwError) { LogPrint(eLogError, "Win32Service Pause", dwError); - SetServiceStatus(SERVICE_RUNNING); } catch (...) { LogPrint(eLogError, "Win32Service failed to pause.", EVENTLOG_ERROR_TYPE); - SetServiceStatus(SERVICE_RUNNING); } } - void I2PService::OnPause() { } - void I2PService::Continue() { try { SetServiceStatus(SERVICE_CONTINUE_PENDING); - OnContinue(); - SetServiceStatus(SERVICE_RUNNING); } catch (DWORD dwError) { LogPrint(eLogError, "Win32Service Continue", dwError); - SetServiceStatus(SERVICE_PAUSED); } catch (...) { LogPrint(eLogError, "Win32Service failed to resume.", EVENTLOG_ERROR_TYPE); - SetServiceStatus(SERVICE_PAUSED); } } @@ -277,7 +235,6 @@ void I2PService::Shutdown() try { OnShutdown(); - SetServiceStatus(SERVICE_STOPPED); } catch (DWORD dwError) @@ -299,11 +256,9 @@ void I2PService::SetServiceStatus(DWORD dwCurrentState, DWORD dwWaitHint) { static DWORD dwCheckPoint = 1; - m_status.dwCurrentState = dwCurrentState; m_status.dwWin32ExitCode = dwWin32ExitCode; m_status.dwWaitHint = dwWaitHint; - m_status.dwCheckPoint = ((dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED)) ? @@ -328,7 +283,7 @@ void FreeHandles(SC_HANDLE schSCManager, SC_HANDLE schService) } } -void InstallService(PSTR pszServiceName, PSTR pszDisplayName, DWORD dwStartType, PSTR pszDependencies, PSTR pszAccount, PSTR pszPassword) +void InstallService(PCSTR pszServiceName, PCSTR pszDisplayName, DWORD dwStartType, PCSTR pszDependencies, PCSTR pszAccount, PCSTR pszPassword) { printf("Try to install Win32Service (%s).\n", pszServiceName); @@ -383,7 +338,7 @@ void InstallService(PSTR pszServiceName, PSTR pszDisplayName, DWORD dwStartType, FreeHandles(schSCManager, schService); } -void UninstallService(PSTR pszServiceName) +void UninstallService(PCSTR pszServiceName) { printf("Try to uninstall Win32Service (%s).\n", pszServiceName); diff --git a/Win32/Win32Service.h b/Win32/Win32Service.h index 95cad3b5..2830d237 100644 --- a/Win32/Win32Service.h +++ b/Win32/Win32Service.h @@ -4,7 +4,6 @@ #include #include - #ifdef _WIN32 // Internal name of the service #define SERVICE_NAME "i2pdService" @@ -25,7 +24,6 @@ #define SERVICE_PASSWORD NULL #endif - class I2PService { public: @@ -72,13 +70,15 @@ private: std::thread* _worker; }; -void InstallService(PSTR pszServiceName, - PSTR pszDisplayName, +void InstallService( + PCSTR pszServiceName, + PCSTR pszDisplayName, DWORD dwStartType, - PSTR pszDependencies, - PSTR pszAccount, - PSTR pszPassword); + PCSTR pszDependencies, + PCSTR pszAccount, + PCSTR pszPassword + ); -void UninstallService(PSTR pszServiceName); +void UninstallService(PCSTR pszServiceName); #endif // WIN_32_SERVICE_H__ \ No newline at end of file diff --git a/android/jni/Application.mk b/android/jni/Application.mk index e4a2698a..25f2bb71 100755 --- a/android/jni/Application.mk +++ b/android/jni/Application.mk @@ -1,6 +1,7 @@ #APP_ABI := all #APP_ABI := armeabi-v7a x86 #APP_ABI := x86 +#APP_ABI := x86_64 APP_ABI := armeabi-v7a #can be android-3 but will fail for x86 since arch-x86 is not present at ndkroot/platforms/android-3/ . libz is taken from there. APP_PLATFORM := android-14 diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 06e1c24f..03e4c450 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -178,6 +178,9 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") endif () elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") # more tweaks + if (NOT (MSVC OR MSYS OR APPLE)) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++" ) + endif() endif () if (WITH_HARDENING AND MSVC) @@ -322,6 +325,10 @@ endif() find_package ( OpenSSL REQUIRED ) if(NOT DEFINED OPENSSL_INCLUDE_DIR) message(SEND_ERROR "Could not find OpenSSL. Please download and install it first!") +else() + if(NOT (OPENSSL_VERSION VERSION_LESS 1.1)) + message(WARNING "Your OpenSSL version ${OPENSSL_VERSION} >=1.1 is experimental: build with v1.0 when possible.") + endif() endif() if (WITH_UPNP) @@ -393,7 +400,7 @@ message(STATUS " UPnP : ${WITH_UPNP}") message(STATUS " PCH : ${WITH_PCH}") message(STATUS " MESHNET : ${WITH_MESHNET}") message(STATUS " ADDRSANITIZER : ${WITH_ADDRSANITIZER}") -message(STATUS " THEADSANITIZER : ${WITH_THREADSANITIZER}") +message(STATUS " THREADSANITIZER : ${WITH_THREADSANITIZER}") message(STATUS " I2LUA : ${WITH_I2LUA}") message(STATUS " WEBSOCKETS : ${WITH_WEBSOCKETS}") message(STATUS "---------------------------------------") @@ -453,6 +460,12 @@ if (WITH_BINARY) fixup_bundle(\"${APPS}\" \"\" \"${DIRS}\") " COMPONENT Runtime) endif () + + if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + if (NOT (MSVC OR MSYS OR APPLE)) # for Clang build on Linux + target_link_libraries("${PROJECT_NAME}" stdc++) + endif() + endif() endif () install(FILES ../LICENSE diff --git a/contrib/certificates/reseed/igor_at_novg.net.crt b/contrib/certificates/reseed/igor_at_novg.net.crt new file mode 100644 index 00000000..12ce7a61 --- /dev/null +++ b/contrib/certificates/reseed/igor_at_novg.net.crt @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFvjCCA6agAwIBAgIQIDtv8tGMh0FyB2w5XjfZxTANBgkqhkiG9w0BAQsFADBt +MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYDVQQK +ExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEWMBQGA1UEAwwN +aWdvckBub3ZnLm5ldDAeFw0xNzA3MjQxODI4NThaFw0yNzA3MjQxODI4NThaMG0x +CzAJBgNVBAYTAlhYMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgxHjAcBgNVBAoT +FUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRYwFAYDVQQDDA1p +Z29yQG5vdmcubmV0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxst4 +cam3YibBtQHGPCPX13uRQti56U3XZytSZntaKrUFmJxjt41Q/mOy3KYo+lBvhfDF +x3tWKjgP9LJOJ28zvddFhZVNxqZRjcnAoPuSOVCw88g01D9OAasKF11hCfdxZP6h +vGm8WCnjD8KPcYFxJC4HJUiFeProAwuTzEAESTRk4CAQe3Ie91JspuqoLUc5Qxlm +w5QpjnjfZY4kaVHmZDKGIZDgNIt5v85bu4pWwZ6O+o90xQqjxvjyz/xccIec3sHw +MHJ8h8ZKMokCKEJTaRWBvdeNXki7nf3gUy/3GjYQlzo0Nxk/Hw4svPcA+eL0AYiy +Jn83bIB5VToW2zYUdV4u3qHeAhEg8Y7HI0kKcSUGm9AQXzbzP8YCHxi0sbb0GAJy +f1Xf3XzoPfT64giD8ReUHhwKpyMB6uvG/NfWSZAzeAO/NT7DAwXpKIVQdkVdqy8b +mvHvjf9/kWKOirA2Nygf3r79Vbg2mqbYC/b63XI9hheU689+O7qyhTEhNz+11X0d +Zax7UPrLrwOeB9TNfEnztsmrHNdv2n+KcOO2o11Wvz2nHP9g+dgwoZSD1ZEpFzWP +0sD5knKLwAL/64qLlAQ1feqW7hMr80IADcKjLSODkIDIIGm0ksXqEzTjz1JzbRDq +jUjq7EAlkw3G69rv1gHxIntllJRQidAqecyWHOMCAwEAAaNaMFgwDgYDVR0PAQH/ +BAQDAgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8E +BTADAQH/MBYGA1UdDgQPBA1pZ29yQG5vdmcubmV0MA0GCSqGSIb3DQEBCwUAA4IC +AQADyPaec28qc1HQtAV5dscJr47k92RTfvan+GEgIwyQDHZQm38eyTb05xipQCdk +5ruUDFXLB5qXXFJKUbQM6IpaktmWDJqk4Zn+1nGbtFEbKgrF55pd63+NQer5QW9o +3+dGj0eZJa3HX5EBkd2r7j2LFuB6uxv3r/xiTeHaaflCnsmyDLfb7axvYhyEzHQS +AUi1bR+ln+dXewdtuojqc1+YmVGDgzWZK2T0oOz2E21CpZUDiP3wv9QfMaotLEal +zECnbhS++q889inN3GB4kIoN6WpPpeYtTV+/r7FLv9+KUOV1s2z6mxIqC5wBFhZs +0Sr1kVo8hB/EW/YYhDp99LoAOjIO6nn1h+qttfzBYr6C16j+8lGK2A12REJ4LiUQ +cQI/0zTjt2C8Ns6ueNzMLQN1Mvmlg1Z8wIB7Az7jsIbY2zFJ0M5qR5VJveTj33K4 +4WSbC/zMWOBYHTVBvGmc6JGhu5ZUTZ+mWP7QfimGu+tdhvtrybFjE9ROIE/4yFr6 +GkxEyt0UY87TeKXJ/3KygvkMwdvqGWiZhItb807iy99+cySujtbGfF2ZXYGjBXVW +dJOVRbyGQkHh6lrWHQM4ntBv4x+5QA+OAan5PBF3tcDx1vefPx+asYslbOXpzII5 +qhvoQxuRs6j5jsVFG6RdsKNeQAt87Mb2u2zK2ZakMdyD1w== +-----END CERTIFICATE----- diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index 32595390..658bf011 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -94,8 +94,12 @@ namespace i2p std::string logs = ""; i2p::config::GetOption("log", logs); std::string logfile = ""; i2p::config::GetOption("logfile", logfile); std::string loglevel = ""; i2p::config::GetOption("loglevel", loglevel); + bool logclftime; i2p::config::GetOption("logclftime", logclftime); /* setup logging */ + if (logclftime) + i2p::log::Logger().SetTimeFormat ("[%d/%b/%Y:%H:%M:%S %z]"); + if (isDaemon && (logs == "" || logs == "stdout")) logs = "file"; diff --git a/daemon/Daemon.h b/daemon/Daemon.h index 2bc05462..48301e73 100644 --- a/daemon/Daemon.h +++ b/daemon/Daemon.h @@ -6,11 +6,11 @@ namespace i2p { - namespace util +namespace util +{ + class Daemon_Singleton_Private; + class Daemon_Singleton { - class Daemon_Singleton_Private; - class Daemon_Singleton - { public: virtual bool init(int argc, char* argv[]); virtual bool start(); @@ -29,40 +29,38 @@ namespace i2p // d-pointer for httpServer, httpProxy, etc. class Daemon_Singleton_Private; Daemon_Singleton_Private &d; - }; + }; #if defined(QT_GUI_LIB) // check if QT #define Daemon i2p::util::DaemonQT::Instance() - // dummy, invoked from RunQT - class DaemonQT: public i2p::util::Daemon_Singleton + // dummy, invoked from RunQT + class DaemonQT: public i2p::util::Daemon_Singleton { public: - static DaemonQT& Instance() { static DaemonQT instance; return instance; } - }; + }; #elif defined(ANDROID) #define Daemon i2p::util::DaemonAndroid::Instance() // dummy, invoked from android/jni/DaemonAndroid.* - class DaemonAndroid: public i2p::util::Daemon_Singleton + class DaemonAndroid: public i2p::util::Daemon_Singleton { public: - static DaemonAndroid& Instance() { static DaemonAndroid instance; return instance; } - }; + }; #elif defined(_WIN32) #define Daemon i2p::util::DaemonWin32::Instance() - class DaemonWin32 : public Daemon_Singleton - { + class DaemonWin32 : public Daemon_Singleton + { public: static DaemonWin32& Instance() { @@ -74,34 +72,36 @@ namespace i2p bool start(); bool stop(); void run (); - }; + + bool isGraceful; + + DaemonWin32 ():isGraceful(false) {} + }; + #else #define Daemon i2p::util::DaemonLinux::Instance() - class DaemonLinux : public Daemon_Singleton - { - public: - static DaemonLinux& Instance() - { - static DaemonLinux instance; - return instance; - } + class DaemonLinux : public Daemon_Singleton + { + public: + static DaemonLinux& Instance() + { + static DaemonLinux instance; + return instance; + } - bool start(); - bool stop(); - void run (); + bool start(); + bool stop(); + void run (); - private: + private: + std::string pidfile; + int pidFH; - std::string pidfile; - int pidFH; - - public: - - int gracefulShutdownInterval; // in seconds - - }; + public: + int gracefulShutdownInterval; // in seconds + }; #endif - } +} } #endif // DAEMON_H__ diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 52feeb10..d08b6d20 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -83,13 +83,13 @@ namespace http { const char HTTP_COMMAND_DISABLE_TRANSIT[] = "disable_transit"; const char HTTP_COMMAND_SHUTDOWN_START[] = "shutdown_start"; const char HTTP_COMMAND_SHUTDOWN_CANCEL[] = "shutdown_cancel"; - const char HTTP_COMMAND_SHUTDOWN_NOW[] = "terminate"; + const char HTTP_COMMAND_SHUTDOWN_NOW[] = "terminate"; const char HTTP_COMMAND_RUN_PEER_TEST[] = "run_peer_test"; const char HTTP_COMMAND_RELOAD_CONFIG[] = "reload_config"; const char HTTP_PARAM_SAM_SESSION_ID[] = "id"; const char HTTP_PARAM_ADDRESS[] = "address"; - static void ShowUptime (std::stringstream& s, int seconds) + static void ShowUptime (std::stringstream& s, int seconds) { int num; @@ -185,7 +185,7 @@ namespace http { s << "ERROR: " << string << "
\r\n"; } - static void ShowStatus (std::stringstream& s) + void ShowStatus (std::stringstream& s, bool includeHiddenContent) { s << "Uptime: "; ShowUptime(s, i2p::context.GetUptime ()); @@ -195,21 +195,21 @@ namespace http { { case eRouterStatusOK: s << "OK"; break; case eRouterStatusTesting: s << "Testing"; break; - case eRouterStatusFirewalled: s << "Firewalled"; break; - case eRouterStatusError: - { - s << "Error"; + case eRouterStatusFirewalled: s << "Firewalled"; break; + case eRouterStatusError: + { + s << "Error"; switch (i2p::context.GetError ()) { case eRouterErrorClockSkew: - s << "
Clock skew"; + s << "
Clock skew"; break; - default: ; - } + default: ; + } break; - } + } default: s << "Unknown"; - } + } s << "
\r\n"; #if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) if (auto remains = Daemon.gracefulShutdownInterval) { @@ -230,33 +230,35 @@ namespace http { s << " (" << (double) i2p::transport::transports.GetOutBandwidth () / 1024 << " KiB/s)
\r\n"; s << "Transit: "; ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ()); - s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " KiB/s)
\r\n"; + s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " KiB/s)
\r\n"; s << "Data path: " << i2p::fs::GetDataDir() << "
\r\n"; s << "
\r\n\r\n

\r\n"; - s << "Router Ident: " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "
\r\n"; - s << "Router Family: " << i2p::context.GetRouterInfo().GetProperty("family") << "
\r\n"; - s << "Router Caps: " << i2p::context.GetRouterInfo().GetProperty("caps") << "
\r\n"; - s << "Our external address:" << "
\r\n" ; - for (const auto& address : i2p::context.GetRouterInfo().GetAddresses()) - { - switch (address->transportStyle) + if(includeHiddenContent) { + s << "Router Ident: " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "
\r\n"; + s << "Router Family: " << i2p::context.GetRouterInfo().GetProperty("family") << "
\r\n"; + s << "Router Caps: " << i2p::context.GetRouterInfo().GetProperty("caps") << "
\r\n"; + s << "Our external address:" << "
\r\n" ; + for (const auto& address : i2p::context.GetRouterInfo().GetAddresses()) { - case i2p::data::RouterInfo::eTransportNTCP: - if (address->host.is_v6 ()) - s << "NTCP6  "; - else - s << "NTCP  "; - break; - case i2p::data::RouterInfo::eTransportSSU: - if (address->host.is_v6 ()) - s << "SSU6     "; - else - s << "SSU     "; - break; - default: - s << "Unknown  "; + switch (address->transportStyle) + { + case i2p::data::RouterInfo::eTransportNTCP: + if (address->host.is_v6 ()) + s << "NTCP6  "; + else + s << "NTCP  "; + break; + case i2p::data::RouterInfo::eTransportSSU: + if (address->host.is_v6 ()) + s << "SSU6     "; + else + s << "SSU     "; + break; + default: + s << "Unknown  "; + } + s << address->host.to_string() << ":" << address->port << "
\r\n"; } - s << address->host.to_string() << ":" << address->port << "
\r\n"; } s << "

\r\n
\r\n"; s << "Routers: " << i2p::data::netdb.GetNumRouters () << " "; @@ -271,13 +273,13 @@ namespace http { s << "Transit Tunnels: " << std::to_string(transitTunnelCount) << "
\r\n"; } - static void ShowLocalDestinations (std::stringstream& s) + void ShowLocalDestinations (std::stringstream& s) { s << "Local Destinations:
\r\n
\r\n"; for (auto& it: i2p::client::context.GetDestinations ()) { - auto ident = it.second->GetIdentHash (); - s << ""; + auto ident = it.second->GetIdentHash (); + s << ""; s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "
\r\n" << std::endl; } @@ -289,11 +291,11 @@ namespace http { { auto dest = it.second->GetDestination (); if (dest) - { - auto ident = dest->GetIdentHash (); - s << ""; + { + auto ident = dest->GetIdentHash (); + s << ""; s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "
\r\n" << std::endl; - } + } } } } @@ -339,7 +341,7 @@ namespace http { s << "
" << std::endl; } - static void ShowLocalDestination (std::stringstream& s, const std::string& b32) + void ShowLocalDestination (std::stringstream& s, const std::string& b32) { s << "Local Destination:
\r\n
\r\n"; i2p::data::IdentHash ident; @@ -347,7 +349,7 @@ namespace http { auto dest = i2p::client::context.FindLocalDestination (ident); if (dest) { - ShowLeaseSetDestination (s, dest); + ShowLeaseSetDestination (s, dest); // show streams s << "
\r\n"; s << ""; @@ -375,35 +377,35 @@ namespace http { s << ""; s << ""; s << ""; - s << "
\r\n" << std::endl; - } + s << "
\r\n" << std::endl; + } s << "
Streams
StreamID" << it->GetRTT () << "" << it->GetWindowSize () << "" << (int)it->GetStatus () << "
"; } } - static void ShowI2CPLocalDestination (std::stringstream& s, const std::string& id) + static void ShowI2CPLocalDestination (std::stringstream& s, const std::string& id) { auto i2cpServer = i2p::client::context.GetI2CPServer (); if (i2cpServer) { s << "I2CP Local Destination:
\r\n
\r\n"; - auto it = i2cpServer->GetSessions ().find (std::stoi (id)); + auto it = i2cpServer->GetSessions ().find (std::stoi (id)); if (it != i2cpServer->GetSessions ().end ()) ShowLeaseSetDestination (s, it->second->GetDestination ()); else - ShowError(s, "I2CP session not found"); + ShowError(s, "I2CP session not found"); } else ShowError(s, "I2CP is not enabled"); } - static void ShowLeasesSets(std::stringstream& s) + void ShowLeasesSets(std::stringstream& s) { s << "
LeaseSets (click on to show info):

\r\n"; int counter = 1; // for each lease set i2p::data::netdb.VisitLeaseSets( - [&s, &counter](const i2p::data::IdentHash dest, std::shared_ptr leaseSet) + [&s, &counter](const i2p::data::IdentHash dest, std::shared_ptr leaseSet) { // create copy of lease set so we extract leases i2p::data::LeaseSet ls(leaseSet->GetBuffer(), leaseSet->GetBufferLen()); @@ -430,7 +432,7 @@ namespace http { // end for each lease set } - static void ShowTunnels (std::stringstream& s) + void ShowTunnels (std::stringstream& s) { s << "Queue size: " << i2p::tunnel::tunnels.GetQueueSize () << "
\r\n"; @@ -463,18 +465,20 @@ namespace http { else s << " Accept transit tunnels
\r\n"; #if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) - if (Daemon.gracefulShutdownInterval) + if (Daemon.gracefulShutdownInterval) s << " Cancel graceful shutdown
"; - else + else s << " Start graceful shutdown
\r\n"; -#endif -#ifdef WIN32_APP - s << " Graceful shutdown
\r\n"; +#elif defined(WIN32_APP) + if (i2p::util::DaemonWin32::Instance().isGraceful) + s << " Cancel graceful shutdown
"; + else + s << " Graceful shutdown
\r\n"; #endif s << " Force shutdown
\r\n"; } - static void ShowTransitTunnels (std::stringstream& s) + void ShowTransitTunnels (std::stringstream& s) { s << "Transit tunnels:
\r\n
\r\n"; for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ()) @@ -489,10 +493,10 @@ namespace http { } } - static void ShowTransports (std::stringstream& s) + void ShowTransports (std::stringstream& s) { s << "Transports:
\r\n
\r\n"; - auto ntcpServer = i2p::transport::transports.GetNTCPServer (); + auto ntcpServer = i2p::transport::transports.GetNTCPServer (); if (ntcpServer) { auto sessions = ntcpServer->GetNTCPSessions (); @@ -575,7 +579,7 @@ namespace http { } } - static void ShowSAMSessions (std::stringstream& s) + void ShowSAMSessions (std::stringstream& s) { auto sam = i2p::client::context.GetSAMBridge (); if (!sam) { @@ -585,8 +589,9 @@ namespace http { s << "SAM Sessions:
\r\n
\r\n"; for (auto& it: sam->GetSessions ()) { + auto& name = it.second->localDestination->GetNickname (); s << ""; - s << it.first << "
\r\n" << std::endl; + s << name << " (" << it.first << ")
\r\n" << std::endl; } } @@ -622,13 +627,13 @@ namespace http { } } - static void ShowI2PTunnels (std::stringstream& s) + void ShowI2PTunnels (std::stringstream& s) { s << "Client Tunnels:
\r\n
\r\n"; for (auto& it: i2p::client::context.GetClientTunnels ()) { auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); - s << ""; + s << ""; s << it.second->GetName () << " ⇐ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << "
\r\n"<< std::endl; @@ -637,29 +642,32 @@ namespace http { if (httpProxy) { auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash(); - s << ""; + s << ""; s << "HTTP Proxy" << " ⇐ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << "
\r\n"<< std::endl; - } + } auto socksProxy = i2p::client::context.GetSocksProxy (); if (socksProxy) { auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash(); - s << ""; + s << ""; s << "SOCKS Proxy" << " ⇐ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << "
\r\n"<< std::endl; - } - s << "
\r\nServer Tunnels:
\r\n
\r\n"; - for (auto& it: i2p::client::context.GetServerTunnels ()) - { - auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); - s << ""; - s << it.second->GetName () << " ⇒ "; - s << i2p::client::context.GetAddressBook ().ToAddress(ident); - s << ":" << it.second->GetLocalPort (); - s << "
\r\n"<< std::endl; + } + auto& serverTunnels = i2p::client::context.GetServerTunnels (); + if (!serverTunnels.empty ()) { + s << "
\r\nServer Tunnels:
\r\n
\r\n"; + for (auto& it: serverTunnels) + { + auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); + s << ""; + s << it.second->GetName () << " ⇒ "; + s << i2p::client::context.GetAddressBook ().ToAddress(ident); + s << ":" << it.second->GetLocalPort (); + s << "
\r\n"<< std::endl; + } } auto& clientForwards = i2p::client::context.GetClientForwards (); if (!clientForwards.empty ()) @@ -668,7 +676,7 @@ namespace http { for (auto& it: clientForwards) { auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); - s << ""; + s << ""; s << it.second->GetName () << " ⇐ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << "
\r\n"<< std::endl; @@ -681,7 +689,7 @@ namespace http { for (auto& it: serverForwards) { auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); - s << ""; + s << ""; s << it.second->GetName () << " ⇐ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << "
\r\n"<< std::endl; @@ -751,10 +759,10 @@ namespace http { } /* method #2: 'Authorization' header sent */ auto provided = req.GetHeader ("Authorization"); - if (provided.length () > 0) - { + if (provided.length () > 0) + { bool result = false; - + std::string expected = user + ":" + pass; size_t b64_sz = i2p::data::Base64EncodingBufferSize(expected.length()) + 1; char * b64_creds = new char[b64_sz]; @@ -797,7 +805,7 @@ namespace http { } else if (req.uri.find("cmd=") != std::string::npos) { HandleCommand (req, res, s); } else { - ShowStatus (s); + ShowStatus (s, true); res.add_header("Refresh", "10"); } ShowPageTail (s); @@ -809,7 +817,7 @@ namespace http { std::map HTTPConnection::m_Tokens; void HTTPConnection::HandlePage (const HTTPReq& req, HTTPRes& res, std::stringstream& s) - { + { std::map params; std::string page(""); URL url; @@ -835,13 +843,13 @@ namespace http { else ++it; } - m_Tokens[token] = ts; + m_Tokens[token] = ts; ShowCommands (s, token); } else if (page == HTTP_PAGE_TRANSIT_TUNNELS) ShowTransitTunnels (s); else if (page == HTTP_PAGE_LOCAL_DESTINATIONS) - ShowLocalDestinations (s); + ShowLocalDestinations (s); else if (page == HTTP_PAGE_LOCAL_DESTINATION) ShowLocalDestination (s, params["b32"]); else if (page == HTTP_PAGE_I2CP_LOCAL_DESTINATION) @@ -859,7 +867,7 @@ namespace http { ShowError(s, "Unknown page: " + page); return; } - } + } void HTTPConnection::HandleCommand (const HTTPReq& req, HTTPRes& res, std::stringstream& s) { @@ -876,7 +884,7 @@ namespace http { return; } - std::string cmd = params["cmd"]; + std::string cmd = params["cmd"]; if (cmd == HTTP_COMMAND_RUN_PEER_TEST) i2p::transport::transports.PeerTest (); else if (cmd == HTTP_COMMAND_RELOAD_CONFIG) @@ -889,14 +897,15 @@ namespace http { i2p::context.SetAcceptsTunnels (false); #if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) Daemon.gracefulShutdownInterval = 10*60; -#endif -#ifdef WIN32_APP +#elif defined(WIN32_APP) i2p::win32::GracefulShutdown (); #endif } else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) { i2p::context.SetAcceptsTunnels (true); #if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) Daemon.gracefulShutdownInterval = 0; +#elif defined(WIN32_APP) + i2p::win32::StopGracefulShutdown (); #endif } else if (cmd == HTTP_COMMAND_SHUTDOWN_NOW) { Daemon.running = false; @@ -963,7 +972,7 @@ namespace http { m_IsRunning = false; m_Acceptor.close(); m_Service.stop (); - if (m_Thread) + if (m_Thread) { m_Thread->join (); m_Thread = nullptr; @@ -981,7 +990,7 @@ namespace http { catch (std::exception& ex) { LogPrint (eLogError, "HTTPServer: runtime exception: ", ex.what ()); - } + } } } @@ -992,7 +1001,7 @@ namespace http { boost::asio::placeholders::error, newSocket)); } - void HTTPServer::HandleAccept(const boost::system::error_code& ecode, + void HTTPServer::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr newSocket) { if (ecode) @@ -1000,7 +1009,7 @@ namespace http { if(newSocket) newSocket->close(); LogPrint(eLogError, "HTTP Server: error handling accept ", ecode.message()); if(ecode != boost::asio::error::operation_aborted) - Accept(); + Accept(); return; } CreateConnection(newSocket); diff --git a/daemon/HTTPServer.h b/daemon/HTTPServer.h index ec56e08a..ec718532 100644 --- a/daemon/HTTPServer.h +++ b/daemon/HTTPServer.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "HTTP.h" namespace i2p @@ -75,6 +76,17 @@ namespace http boost::asio::io_service::work m_Work; boost::asio::ip::tcp::acceptor m_Acceptor; }; + + //all the below functions are also used by Qt GUI, see mainwindow.cpp -> getStatusPageHtml + void ShowStatus (std::stringstream& s, bool includeHiddenContent); + void ShowLocalDestinations (std::stringstream& s); + void ShowLeasesSets(std::stringstream& s); + void ShowTunnels (std::stringstream& s); + void ShowTransitTunnels (std::stringstream& s); + void ShowTransports (std::stringstream& s); + void ShowSAMSessions (std::stringstream& s); + void ShowI2PTunnels (std::stringstream& s); + void ShowLocalDestination (std::stringstream& s, const std::string& b32); } // http } // i2p diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index 1d7023fb..3d06b97a 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -512,10 +512,10 @@ namespace client { for (auto it = params.begin (); it != params.end (); it++) { - if (it != params.begin ()) results << ","; LogPrint (eLogDebug, "I2PControl: NetworkSetting request: ", it->first); auto it1 = m_NetworkSettingHandlers.find (it->first); if (it1 != m_NetworkSettingHandlers.end ()) { + if (it != params.begin ()) results << ","; (this->*(it1->second))(it->second.data (), results); } else LogPrint (eLogError, "I2PControl: NetworkSetting unknown request: ", it->first); diff --git a/debian/control b/debian/control index 62da41d2..808cdda9 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: i2pd Section: net Priority: optional Maintainer: R4SAS -Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1~), gcc (>= 4.7) | clang (>= 3.3), libboost-system-dev (>= 1.46), libboost-date-time-dev, libboost-filesystem-dev, libboost-program-options-dev, libminiupnpc-dev, libssl-dev, zlib1g-dev +Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1~), gcc (>= 4.7) | clang (>= 3.3), libboost-system-dev (>= 1.46), libboost-date-time-dev, libboost-filesystem-dev, libboost-program-options-dev, libminiupnpc-dev, libssl-dev, zlib1g-dev, dh-apparmor Standards-Version: 3.9.6 Homepage: http://i2pd.website/ Vcs-Git: git://github.com/PurpleI2P/i2pd.git @@ -12,7 +12,7 @@ Package: i2pd Architecture: any Pre-Depends: adduser Depends: ${shlibs:Depends}, ${misc:Depends} -Suggests: tor, privoxy +Suggests: tor, privoxy, apparmor Description: A full-featured C++ implementation of I2P client. I2P (Invisible Internet Protocol) is a universal anonymous network layer. All communications over I2P are anonymous and end-to-end encrypted, participants diff --git a/debian/i2pd.install b/debian/i2pd.install index 7298f5c7..d81101fc 100644 --- a/debian/i2pd.install +++ b/debian/i2pd.install @@ -3,3 +3,4 @@ contrib/i2pd.conf etc/i2pd/ contrib/tunnels.conf etc/i2pd/ contrib/subscriptions.txt etc/i2pd/ contrib/certificates/ usr/share/i2pd/ +contrib/apparmor/usr.sbin.i2pd etc/apparmor.d diff --git a/debian/rules b/debian/rules index 171a5269..4654ae6c 100755 --- a/debian/rules +++ b/debian/rules @@ -12,6 +12,7 @@ PREFIX=/usr %: dh $@ --parallel + dh_apparmor --profile-name=usr.sbin.i2pd -pi2pd override_dh_strip: dh_strip --dbg-package=i2pd-dbg diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 0097eb30..4997852a 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -38,6 +38,7 @@ namespace config { ("log", value()->default_value(""), "Logs destination: stdout, file, syslog (stdout if not set)") ("logfile", value()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)") ("loglevel", value()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error)") + ("logclftime", value()->default_value(false), "Write full CLF-formatted date and time to log (default: write only time)") ("family", value()->default_value(""), "Specify a family, router belongs to") ("datadir", value()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)") ("host", value()->default_value("0.0.0.0"), "External IP") @@ -70,6 +71,8 @@ namespace config { ("limits.coresize", value()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)") ("limits.openfiles", value()->default_value(0), "Maximum number of open files (0 - use system default)") ("limits.transittunnels", value()->default_value(2500), "Maximum active transit sessions (default:2500)") + ("limits.ntcpsoft", value()->default_value(0), "Threshold to start probabalistic backoff with ntcp sessions (default: use system limit)") + ("limits.ntcphard", value()->default_value(0), "Maximum number of ntcp sessions (default: use system limit)") ; options_description httpserver("HTTP Server options"); @@ -189,7 +192,8 @@ namespace config { "https://reseed.memcpy.io/," "https://reseed.onion.im/," "https://itoopie.atomike.ninja/," - "https://i2pseed.creativecowpat.net:8443/" + "https://i2pseed.creativecowpat.net:8443/," + "https://i2p.novg.net/" ), "Reseed URLs, separated by comma") ; diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 0ac65671..caae5d82 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -372,6 +372,107 @@ namespace crypto BN_CTX_free (ctx); } +// ECICS + void ECICSEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) + { + BN_CTX_start (ctx); + BIGNUM * q = BN_CTX_get (ctx); + EC_GROUP_get_order(curve, q, ctx); + int len = BN_num_bytes (q); + BIGNUM * k = BN_CTX_get (ctx); + BN_rand_range (k, q); // 0 < k < q + // point for shared secret + auto p = EC_POINT_new (curve); + EC_POINT_mul (curve, p, k, nullptr, nullptr, ctx); + BIGNUM * x = BN_CTX_get (ctx), * y = BN_CTX_get (ctx); + EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, nullptr); + bn2buf (x, encrypted, len); + bn2buf (y, encrypted + len, len); + RAND_bytes (encrypted + 2*len, 256 - 2*len); + // ecryption key and iv + EC_POINT_mul (curve, p, nullptr, key, k, ctx); + EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, nullptr); + uint8_t keyBuf[64], iv[64], shared[32]; + bn2buf (x, keyBuf, len); + bn2buf (y, iv, len); + SHA256 (keyBuf, len, shared); + // create buffer + uint8_t m[256]; + m[0] = 0xFF; m[255] = 0xFF; + memcpy (m+33, data, 222); + SHA256 (m+33, 222, m+1); + // encrypt + CBCEncryption encryption; + encryption.SetKey (shared); + encryption.SetIV (iv); + encryption.Encrypt (m, 256, encrypted + 256); + EC_POINT_free (p); + BN_CTX_end (ctx); + } + + bool ECICSDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) + { + bool ret = true; + BN_CTX_start (ctx); + BIGNUM * q = BN_CTX_get (ctx); + EC_GROUP_get_order(curve, q, ctx); + int len = BN_num_bytes (q); + // point for shared secret + BIGNUM * x = BN_CTX_get (ctx), * y = BN_CTX_get (ctx); + BN_bin2bn (encrypted, len, x); + BN_bin2bn (encrypted + len, len, y); + auto p = EC_POINT_new (curve); + if (EC_POINT_set_affine_coordinates_GFp (curve, p, x, y, nullptr)) + { + auto s = EC_POINT_new (curve); + EC_POINT_mul (curve, s, nullptr, p, key, ctx); + EC_POINT_get_affine_coordinates_GFp (curve, s, x, y, nullptr); + EC_POINT_free (s); + uint8_t keyBuf[64], iv[64], shared[32]; + bn2buf (x, keyBuf, len); + bn2buf (y, iv, len); + SHA256 (keyBuf, len, shared); + // decrypt + uint8_t m[256]; + CBCDecryption decryption; + decryption.SetKey (shared); + decryption.SetIV (iv); + decryption.Decrypt (encrypted + 256, 256, m); + // verify and copy + uint8_t hash[32]; + SHA256 (m + 33, 222, hash); + if (!memcmp (m + 1, hash, 32)) + memcpy (data, m + 33, 222); + else + { + LogPrint (eLogError, "ECICS decrypt hash doesn't match"); + ret = false; + } + } + else + { + LogPrint (eLogError, "ECICS decrypt point is invalid"); + ret = false; + } + + EC_POINT_free (p); + BN_CTX_end (ctx); + return ret; + } + + void GenerateECICSKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub) + { + BN_CTX * ctx = BN_CTX_new (); + BIGNUM * q = BN_new (); + EC_GROUP_get_order(curve, q, ctx); + priv = BN_new (); + BN_rand_range (priv, q); + pub = EC_POINT_new (curve); + EC_POINT_mul (curve, pub, priv, nullptr, nullptr, ctx); + BN_free (q); + BN_CTX_free (ctx); + } + // HMAC const uint64_t IPAD = 0x3636363636363636; const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C; diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index cb0152ba..18948490 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -52,6 +52,11 @@ namespace crypto bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding = false); void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub); + // ECICS + void ECICSEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx); // 222 bytes data, 512 bytes encrypted + bool ECICSDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx); + void GenerateECICSKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub); + // HMAC typedef i2p::data::Tag<32> MACKey; void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest); diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index d45fdf47..520fc23f 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "Crypto.h" #include "Log.h" #include "FS.h" @@ -13,8 +14,8 @@ namespace i2p namespace client { LeaseSetDestination::LeaseSetDestination (bool isPublic, const std::map * params): - m_IsRunning (false), m_Thread (nullptr), m_IsPublic (isPublic), - m_PublishReplyToken (0), m_LastSubmissionTime (0), m_PublishConfirmationTimer (m_Service), + m_IsRunning (false), m_Thread (nullptr), m_IsPublic (isPublic), + m_PublishReplyToken (0), m_LastSubmissionTime (0), m_PublishConfirmationTimer (m_Service), m_PublishVerificationTimer (m_Service), m_PublishDelayTimer (m_Service), m_CleanupTimer (m_Service) { int inLen = DEFAULT_INBOUND_TUNNEL_LENGTH; @@ -23,8 +24,10 @@ namespace client int outQty = DEFAULT_OUTBOUND_TUNNELS_QUANTITY; int numTags = DEFAULT_TAGS_TO_SEND; std::shared_ptr > explicitPeers; - try { - if (params) { + try + { + if (params) + { auto it = params->find (I2CP_PARAM_INBOUND_TUNNEL_LENGTH); if (it != params->end ()) inLen = std::stoi(it->second); @@ -55,8 +58,12 @@ namespace client LogPrint (eLogInfo, "Destination: Added to explicit peers list: ", b64); } } + it = params->find (I2CP_PARAM_INBOUND_NICKNAME); + if (it != params->end ()) m_Nickname = it->second; // otherwise we set deafult nickname in Start when we know local address } - } catch (std::exception & ex) { + } + catch (std::exception & ex) + { LogPrint(eLogError, "Destination: unable to parse parameters for destination: ", ex.what()); } SetNumTags (numTags); @@ -83,77 +90,79 @@ namespace client LeaseSetDestination::~LeaseSetDestination () { - if (m_IsRunning) + if (m_IsRunning) Stop (); if (m_Pool) - i2p::tunnel::tunnels.DeleteTunnelPool (m_Pool); + i2p::tunnel::tunnels.DeleteTunnelPool (m_Pool); for (auto& it: m_LeaseSetRequests) it.second->Complete (nullptr); - } + } void LeaseSetDestination::Run () { while (m_IsRunning) { try - { + { m_Service.run (); } catch (std::exception& ex) { LogPrint (eLogError, "Destination: runtime exception: ", ex.what ()); - } - } - } + } + } + } bool LeaseSetDestination::Start () - { + { if (!m_IsRunning) - { + { + if (m_Nickname.empty ()) + m_Nickname = i2p::data::GetIdentHashAbbreviation (GetIdentHash ()); // set default nickname LoadTags (); m_IsRunning = true; m_Pool->SetLocalDestination (shared_from_this ()); - m_Pool->SetActive (true); + m_Pool->SetActive (true); m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT)); m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer, - shared_from_this (), std::placeholders::_1)); + shared_from_this (), std::placeholders::_1)); m_Thread = new std::thread (std::bind (&LeaseSetDestination::Run, shared_from_this ())); - + return true; - } + } else return false; } - + bool LeaseSetDestination::Stop () - { + { if (m_IsRunning) - { + { m_CleanupTimer.cancel (); m_PublishConfirmationTimer.cancel (); - m_PublishVerificationTimer.cancel (); + m_PublishVerificationTimer.cancel (); m_IsRunning = false; if (m_Pool) - { + { m_Pool->SetLocalDestination (nullptr); i2p::tunnel::tunnels.StopTunnelPool (m_Pool); - } + } m_Service.stop (); if (m_Thread) - { - m_Thread->join (); + { + m_Thread->join (); delete m_Thread; m_Thread = 0; - } + } SaveTags (); CleanUp (); // GarlicDestination return true; - } + } else return false; - } - + } + std::shared_ptr LeaseSetDestination::FindLeaseSet (const i2p::data::IdentHash& ident) { std::shared_ptr remoteLS; @@ -164,7 +173,7 @@ namespace client remoteLS = it->second; } - if (remoteLS) + if (remoteLS) { if (!remoteLS->IsExpired ()) { @@ -193,9 +202,9 @@ namespace client m_RemoteLeaseSets.erase (ident); return nullptr; } - } + } else - { + { auto ls = i2p::data::netdb.FindLeaseSet (ident); if (ls && !ls->IsExpired ()) { @@ -203,7 +212,7 @@ namespace client std::lock_guard _lock(m_RemoteLeaseSetsMutex); m_RemoteLeaseSets[ident] = ls; return ls; - } + } } return nullptr; } @@ -215,11 +224,11 @@ namespace client UpdateLeaseSet (); std::lock_guard l(m_LeaseSetMutex); return m_LeaseSet; - } + } void LeaseSetDestination::SetLeaseSet (i2p::data::LocalLeaseSet * newLeaseSet) { - { + { std::lock_guard l(m_LeaseSetMutex); m_LeaseSet.reset (newLeaseSet); } @@ -229,21 +238,21 @@ namespace client m_PublishVerificationTimer.cancel (); Publish (); } - } - + } + void LeaseSetDestination::UpdateLeaseSet () { - int numTunnels = m_Pool->GetNumInboundTunnels () + 2; // 2 backup tunnels - if (numTunnels > i2p::data::MAX_NUM_LEASES) numTunnels = i2p::data::MAX_NUM_LEASES; // 16 tunnels maximum + int numTunnels = m_Pool->GetNumInboundTunnels () + 2; // 2 backup tunnels + if (numTunnels > i2p::data::MAX_NUM_LEASES) numTunnels = i2p::data::MAX_NUM_LEASES; // 16 tunnels maximum CreateNewLeaseSet (m_Pool->GetInboundTunnels (numTunnels)); - } + } bool LeaseSetDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag) { struct { uint8_t k[32], t[32]; - } data; + } data; memcpy (data.k, key, 32); memcpy (data.t, tag, 32); auto s = shared_from_this (); @@ -256,42 +265,42 @@ namespace client void LeaseSetDestination::ProcessGarlicMessage (std::shared_ptr msg) { - m_Service.post (std::bind (&LeaseSetDestination::HandleGarlicMessage, shared_from_this (), msg)); + m_Service.post (std::bind (&LeaseSetDestination::HandleGarlicMessage, shared_from_this (), msg)); } void LeaseSetDestination::ProcessDeliveryStatusMessage (std::shared_ptr msg) { - m_Service.post (std::bind (&LeaseSetDestination::HandleDeliveryStatusMessage, shared_from_this (), msg)); + m_Service.post (std::bind (&LeaseSetDestination::HandleDeliveryStatusMessage, shared_from_this (), msg)); } void LeaseSetDestination::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from) { uint8_t typeID = buf[I2NP_HEADER_TYPEID_OFFSET]; switch (typeID) - { + { case eI2NPData: HandleDataMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET)); break; case eI2NPDeliveryStatus: // we assume tunnel tests non-encrypted HandleDeliveryStatusMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from)); - break; + break; case eI2NPDatabaseStore: HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET)); break; case eI2NPDatabaseSearchReply: HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET)); - break; + break; default: i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from)); - } - } + } + } void LeaseSetDestination::HandleDatabaseStoreMessage (const uint8_t * buf, size_t len) { uint32_t replyToken = bufbe32toh (buf + DATABASE_STORE_REPLY_TOKEN_OFFSET); size_t offset = DATABASE_STORE_HEADER_SIZE; - if (replyToken) + if (replyToken) { LogPrint (eLogInfo, "Destination: Reply token is ignored for DatabaseStore"); offset += 36; @@ -307,8 +316,8 @@ namespace client { leaseSet = it->second; if (leaseSet->IsNewer (buf + offset, len - offset)) - { - leaseSet->Update (buf + offset, len - offset); + { + leaseSet->Update (buf + offset, len - offset); if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key) LogPrint (eLogDebug, "Destination: Remote LeaseSet updated"); else @@ -322,7 +331,7 @@ namespace client LogPrint (eLogDebug, "Destination: Remote LeaseSet is older. Not updated"); } else - { + { leaseSet = std::make_shared (buf + offset, len - offset); if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key) { @@ -339,18 +348,18 @@ namespace client LogPrint (eLogError, "Destination: New remote LeaseSet failed"); leaseSet = nullptr; } - } - } + } + } else LogPrint (eLogError, "Destination: Unexpected client's DatabaseStore type ", buf[DATABASE_STORE_TYPE_OFFSET], ", dropped"); - + auto it1 = m_LeaseSetRequests.find (key); if (it1 != m_LeaseSetRequests.end ()) { it1->second->requestTimeoutTimer.cancel (); if (it1->second) it1->second->Complete (leaseSet); m_LeaseSetRequests.erase (it1); - } + } } void LeaseSetDestination::HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len) @@ -364,7 +373,7 @@ namespace client auto request = it->second; bool found = false; if (request->excluded.size () < MAX_NUM_FLOODFILLS_PER_REQUEST) - { + { for (int i = 0; i < num; i++) { i2p::data::IdentHash peerHash (buf + 33 + i*32); @@ -372,28 +381,28 @@ namespace client { LogPrint (eLogInfo, "Destination: Found new floodfill, request it"); // TODO: recheck this message i2p::data::netdb.RequestDestination (peerHash); - } + } } - + auto floodfill = i2p::data::netdb.GetClosestFloodfill (key, request->excluded); if (floodfill) { LogPrint (eLogInfo, "Destination: Requesting ", key.ToBase64 (), " at ", floodfill->GetIdentHash ().ToBase64 ()); if (SendLeaseSetRequest (key, floodfill, request)) found = true; - } - } + } + } if (!found) - { + { LogPrint (eLogInfo, "Destination: ", key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST, " floodfills"); request->Complete (nullptr); m_LeaseSetRequests.erase (key); - } - } - else + } + } + else LogPrint (eLogWarning, "Destination: Request for ", key.ToBase64 (), " not found"); - } - + } + void LeaseSetDestination::HandleDeliveryStatusMessage (std::shared_ptr msg) { uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET); @@ -405,20 +414,20 @@ namespace client // schedule verification m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT)); m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, - shared_from_this (), std::placeholders::_1)); + shared_from_this (), std::placeholders::_1)); } else i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msg); - } + } void LeaseSetDestination::SetLeaseSetUpdated () - { + { UpdateLeaseSet (); } - + void LeaseSetDestination::Publish () - { - if (!m_LeaseSet || !m_Pool) + { + if (!m_LeaseSet || !m_Pool) { LogPrint (eLogError, "Destination: Can't publish non-existing LeaseSet"); return; @@ -435,9 +444,9 @@ namespace client m_PublishDelayTimer.cancel (); m_PublishDelayTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_MIN_INTERVAL)); m_PublishDelayTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishDelayTimer, - shared_from_this (), std::placeholders::_1)); + shared_from_this (), std::placeholders::_1)); return; - } + } auto outbound = m_Pool->GetNextOutboundTunnel (); if (!outbound) { @@ -450,28 +459,28 @@ namespace client LogPrint (eLogError, "Destination: Can't publish LeaseSet. No inbound tunnels"); return; } - auto floodfill = i2p::data::netdb.GetClosestFloodfill (m_LeaseSet->GetIdentHash (), m_ExcludedFloodfills); + auto floodfill = i2p::data::netdb.GetClosestFloodfill (m_LeaseSet->GetIdentHash (), m_ExcludedFloodfills); if (!floodfill) { LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found"); m_ExcludedFloodfills.clear (); return; - } + } m_ExcludedFloodfills.insert (floodfill->GetIdentHash ()); LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ()); RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4); - auto msg = WrapMessage (floodfill, i2p::CreateDatabaseStoreMsg (m_LeaseSet, m_PublishReplyToken, inbound)); + auto msg = WrapMessage (floodfill, i2p::CreateDatabaseStoreMsg (m_LeaseSet, m_PublishReplyToken, inbound)); m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT)); m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer, - shared_from_this (), std::placeholders::_1)); - outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg); + shared_from_this (), std::placeholders::_1)); + outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg); m_LastSubmissionTime = ts; } void LeaseSetDestination::HandlePublishConfirmationTimer (const boost::system::error_code& ecode) { if (ecode != boost::asio::error::operation_aborted) - { + { if (m_PublishReplyToken) { LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds, will try again"); @@ -484,25 +493,25 @@ namespace client void LeaseSetDestination::HandlePublishVerificationTimer (const boost::system::error_code& ecode) { if (ecode != boost::asio::error::operation_aborted) - { + { auto s = shared_from_this (); - RequestLeaseSet (GetIdentHash (), + RequestLeaseSet (GetIdentHash (), // "this" added due to bug in gcc 4.7-4.8 [s,this](std::shared_ptr leaseSet) { - if (leaseSet) + if (leaseSet) { if (s->m_LeaseSet && *s->m_LeaseSet == *leaseSet) { // we got latest LeasetSet LogPrint (eLogDebug, "Destination: published LeaseSet verified for ", GetIdentHash().ToBase32()); s->m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_REGULAR_VERIFICATION_INTERNAL)); - s->m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, s, std::placeholders::_1)); + s->m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, s, std::placeholders::_1)); return; - } + } else LogPrint (eLogDebug, "Destination: LeaseSet is different than just published for ", GetIdentHash().ToBase32()); - } + } else LogPrint (eLogWarning, "Destination: couldn't find published LeaseSet for ", GetIdentHash().ToBase32()); // we have to publish again @@ -515,16 +524,16 @@ namespace client { if (ecode != boost::asio::error::operation_aborted) Publish (); - } - + } + bool LeaseSetDestination::RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete) { - if (!m_Pool || !IsReady ()) - { - if (requestComplete) + if (!m_Pool || !IsReady ()) + { + if (requestComplete) m_Service.post ([requestComplete](void){requestComplete (nullptr);}); return false; - } + } m_Service.post (std::bind (&LeaseSetDestination::RequestLeaseSet, shared_from_this (), dest, requestComplete)); return true; } @@ -536,14 +545,14 @@ namespace client { auto it = s->m_LeaseSetRequests.find (dest); if (it != s->m_LeaseSetRequests.end ()) - { - auto requestComplete = it->second; + { + auto requestComplete = it->second; s->m_LeaseSetRequests.erase (it); if (notify && requestComplete) requestComplete->Complete (nullptr); - } - }); + } + }); } - + void LeaseSetDestination::RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete) { std::set excluded; @@ -564,28 +573,28 @@ namespace client m_LeaseSetRequests.erase (ret.first); if (requestComplete) requestComplete (nullptr); } - } + } else // duplicate { LogPrint (eLogInfo, "Destination: Request of LeaseSet ", dest.ToBase64 (), " is pending already"); if (ts > ret.first->second->requestTime + MAX_LEASESET_REQUEST_TIMEOUT) - { + { // something went wrong m_LeaseSetRequests.erase (ret.first); if (requestComplete) requestComplete (nullptr); } else if (requestComplete) ret.first->second->requestComplete.push_back (requestComplete); - } - } + } + } else - { + { LogPrint (eLogError, "Destination: Can't request LeaseSet, no floodfills found"); if (requestComplete) requestComplete (nullptr); - } - } - - bool LeaseSetDestination::SendLeaseSetRequest (const i2p::data::IdentHash& dest, + } + } + + bool LeaseSetDestination::SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr nextFloodfill, std::shared_ptr request) { if (!request->replyTunnel || !request->replyTunnel->IsEstablished ()) @@ -594,36 +603,36 @@ namespace client if (!request->outboundTunnel || !request->outboundTunnel->IsEstablished ()) request->outboundTunnel = m_Pool->GetNextOutboundTunnel (); if (!request->outboundTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no outbound tunnels found"); - + if (request->replyTunnel && request->outboundTunnel) - { + { request->excluded.insert (nextFloodfill->GetIdentHash ()); request->requestTimeoutTimer.cancel (); uint8_t replyKey[32], replyTag[32]; - RAND_bytes (replyKey, 32); // random session key + RAND_bytes (replyKey, 32); // random session key RAND_bytes (replyTag, 32); // random session tag AddSessionKey (replyKey, replyTag); auto msg = WrapMessage (nextFloodfill, - CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, + CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, request->replyTunnel, replyKey, replyTag)); request->outboundTunnel->SendTunnelDataMsg ( { - i2p::tunnel::TunnelMessageBlock - { + i2p::tunnel::TunnelMessageBlock + { i2p::tunnel::eDeliveryTypeRouter, nextFloodfill->GetIdentHash (), 0, msg } - }); + }); request->requestTimeoutTimer.expires_from_now (boost::posix_time::seconds(LEASESET_REQUEST_TIMEOUT)); request->requestTimeoutTimer.async_wait (std::bind (&LeaseSetDestination::HandleRequestTimoutTimer, shared_from_this (), std::placeholders::_1, dest)); - } + } else return false; return true; - } + } void LeaseSetDestination::HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest) { @@ -641,26 +650,26 @@ namespace client { // reset tunnels, because one them might fail it->second->outboundTunnel = nullptr; - it->second->replyTunnel = nullptr; + it->second->replyTunnel = nullptr; done = !SendLeaseSetRequest (dest, floodfill, it->second); } else done = true; } else - { + { LogPrint (eLogWarning, "Destination: ", dest.ToBase64 (), " was not found within ", MAX_LEASESET_REQUEST_TIMEOUT, " seconds"); done = true; } - + if (done) { - auto requestComplete = it->second; + auto requestComplete = it->second; m_LeaseSetRequests.erase (it); if (requestComplete) requestComplete->Complete (nullptr); - } - } - } + } + } + } } void LeaseSetDestination::HandleCleanupTimer (const boost::system::error_code& ecode) @@ -674,7 +683,7 @@ namespace client m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer, shared_from_this (), std::placeholders::_1)); } - } + } void LeaseSetDestination::CleanupRemoteLeaseSets () { @@ -686,43 +695,43 @@ namespace client { LogPrint (eLogWarning, "Destination: Remote LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired"); it = m_RemoteLeaseSets.erase (it); - } - else + } + else ++it; } - } + } ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params): LeaseSetDestination (isPublic, params), m_Keys (keys), m_DatagramDestination (nullptr), m_RefCounter (0), m_ReadyChecker(GetService()) { - if (isPublic) + if (isPublic) PersistTemporaryKeys (); else i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey); if (isPublic) LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created"); - } + } - ClientDestination::~ClientDestination () + ClientDestination::~ClientDestination () { - } - + } + bool ClientDestination::Start () { if (LeaseSetDestination::Start ()) - { + { m_StreamingDestination = std::make_shared (GetSharedFromThis ()); // TODO: - m_StreamingDestination->Start (); + m_StreamingDestination->Start (); for (auto& it: m_StreamingDestinationsByPorts) it.second->Start (); return true; - } + } else return false; - } - + } + bool ClientDestination::Stop () { if (LeaseSetDestination::Stop ()) @@ -732,21 +741,21 @@ namespace client //m_StreamingDestination->SetOwner (nullptr); m_StreamingDestination = nullptr; for (auto& it: m_StreamingDestinationsByPorts) - { + { it.second->Stop (); //it.second->SetOwner (nullptr); } m_StreamingDestinationsByPorts.clear (); if (m_DatagramDestination) - { + { delete m_DatagramDestination; m_DatagramDestination = nullptr; - } + } return true; } else return false; - } + } #ifdef I2LUA void ClientDestination::Ready(ReadyPromise & p) @@ -773,14 +782,14 @@ namespace client ScheduleCheckForReady(p); } #endif - + void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len) { uint32_t length = bufbe32toh (buf); buf += 4; // we assume I2CP payload uint16_t fromPort = bufbe16toh (buf + 4), // source - toPort = bufbe16toh (buf + 6); // destination + toPort = bufbe16toh (buf + 6); // destination switch (buf[9]) { case PROTOCOL_TYPE_STREAMING: @@ -804,14 +813,14 @@ namespace client LogPrint (eLogError, "Destination: Data: unexpected protocol ", buf[9]); } } - - void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port) + + void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port) { - if (!streamRequestComplete) + if (!streamRequestComplete) { LogPrint (eLogError, "Destination: request callback is not specified in CreateStream"); return; - } + } auto leaseSet = FindLeaseSet (dest); if (leaseSet) streamRequestComplete(CreateStream (leaseSet, port)); @@ -837,18 +846,18 @@ namespace client return nullptr; } - std::shared_ptr ClientDestination::GetStreamingDestination (int port) const - { - if (port) + std::shared_ptr ClientDestination::GetStreamingDestination (int port) const + { + if (port) { auto it = m_StreamingDestinationsByPorts.find (port); if (it != m_StreamingDestinationsByPorts.end ()) return it->second; - } + } // if port is zero or not found, use default destination - return m_StreamingDestination; + return m_StreamingDestination; } - + void ClientDestination::AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor) { if (m_StreamingDestination) @@ -860,35 +869,35 @@ namespace client if (m_StreamingDestination) m_StreamingDestination->ResetAcceptor (); } - + bool ClientDestination::IsAcceptingStreams () const { if (m_StreamingDestination) return m_StreamingDestination->IsAcceptorSet (); return false; - } + } void ClientDestination::AcceptOnce (const i2p::stream::StreamingDestination::Acceptor& acceptor) { if (m_StreamingDestination) m_StreamingDestination->AcceptOnce (acceptor); - } - + } + std::shared_ptr ClientDestination::CreateStreamingDestination (int port, bool gzip) { - auto dest = std::make_shared (GetSharedFromThis (), port, gzip); + auto dest = std::make_shared (GetSharedFromThis (), port, gzip); if (port) m_StreamingDestinationsByPorts[port] = dest; - else // update default + else // update default m_StreamingDestination = dest; return dest; - } - + } + i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination () { if (m_DatagramDestination == nullptr) m_DatagramDestination = new i2p::datagram::DatagramDestination (GetSharedFromThis ()); - return m_DatagramDestination; + return m_DatagramDestination; } std::vector > ClientDestination::GetAllStreams () const @@ -898,12 +907,12 @@ namespace client { for (auto& it: m_StreamingDestination->GetStreams ()) ret.push_back (it.second); - } + } for (auto& it: m_StreamingDestinationsByPorts) for (auto& it1: it.second->GetStreams ()) ret.push_back (it1.second); return ret; - } + } void ClientDestination::PersistTemporaryKeys () { @@ -927,7 +936,7 @@ namespace client return; } LogPrint(eLogError, "Destinations: Can't save keys to ", path); - } + } void ClientDestination::CreateNewLeaseSet (std::vector > tunnels) { @@ -935,7 +944,7 @@ namespace client // sign Sign (leaseSet->GetBuffer (), leaseSet->GetBufferLen () - leaseSet->GetSignatureLen (), leaseSet->GetSignature ()); // TODO SetLeaseSet (leaseSet); - } + } void ClientDestination::CleanupDestination () { diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index ef7437fb..b4c20fcc 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -50,6 +50,7 @@ namespace client const int STREAM_REQUEST_TIMEOUT = 60; //in seconds const char I2CP_PARAM_TAGS_TO_SEND[] = "crypto.tagsToSend"; const int DEFAULT_TAGS_TO_SEND = 40; + const char I2CP_PARAM_INBOUND_NICKNAME[] = "inbound.nickname"; // latency const char I2CP_PARAM_MIN_TUNNEL_LATENCY[] = "latency.min"; @@ -86,6 +87,7 @@ namespace client LeaseSetDestination (bool isPublic, const std::map * params = nullptr); ~LeaseSetDestination (); + const std::string& GetNickname () const { return m_Nickname; }; virtual bool Start (); virtual bool Stop (); @@ -153,6 +155,7 @@ namespace client boost::asio::deadline_timer m_PublishConfirmationTimer, m_PublishVerificationTimer, m_PublishDelayTimer, m_CleanupTimer; + std::string m_Nickname; public: diff --git a/libi2pd/Gost.cpp b/libi2pd/Gost.cpp index 351dac10..8663289a 100644 --- a/libi2pd/Gost.cpp +++ b/libi2pd/Gost.cpp @@ -179,121 +179,595 @@ namespace crypto // ГОСТ 34.11-2012 - static const uint8_t sbox_[256] = + static const uint64_t T0[256] = { - 0xFC, 0xEE, 0xDD, 0x11, 0xCF, 0x6E, 0x31, 0x16, 0xFB, 0xC4, 0xFA, 0xDA, 0x23, 0xC5, 0x04, 0x4D, - 0xE9, 0x77, 0xF0, 0xDB, 0x93, 0x2E, 0x99, 0xBA, 0x17, 0x36, 0xF1, 0xBB, 0x14, 0xCD, 0x5F, 0xC1, - 0xF9, 0x18, 0x65, 0x5A, 0xE2, 0x5C, 0xEF, 0x21, 0x81, 0x1C, 0x3C, 0x42, 0x8B, 0x01, 0x8E, 0x4F, - 0x05, 0x84, 0x02, 0xAE, 0xE3, 0x6A, 0x8F, 0xA0, 0x06, 0x0B, 0xED, 0x98, 0x7F, 0xD4, 0xD3, 0x1F, - 0xEB, 0x34, 0x2C, 0x51, 0xEA, 0xC8, 0x48, 0xAB, 0xF2, 0x2A, 0x68, 0xA2, 0xFD, 0x3A, 0xCE, 0xCC, - 0xB5, 0x70, 0x0E, 0x56, 0x08, 0x0C, 0x76, 0x12, 0xBF, 0x72, 0x13, 0x47, 0x9C, 0xB7, 0x5D, 0x87, - 0x15, 0xA1, 0x96, 0x29, 0x10, 0x7B, 0x9A, 0xC7, 0xF3, 0x91, 0x78, 0x6F, 0x9D, 0x9E, 0xB2, 0xB1, - 0x32, 0x75, 0x19, 0x3D, 0xFF, 0x35, 0x8A, 0x7E, 0x6D, 0x54, 0xC6, 0x80, 0xC3, 0xBD, 0x0D, 0x57, - 0xDF, 0xF5, 0x24, 0xA9, 0x3E, 0xA8, 0x43, 0xC9, 0xD7, 0x79, 0xD6, 0xF6, 0x7C, 0x22, 0xB9, 0x03, - 0xE0, 0x0F, 0xEC, 0xDE, 0x7A, 0x94, 0xB0, 0xBC, 0xDC, 0xE8, 0x28, 0x50, 0x4E, 0x33, 0x0A, 0x4A, - 0xA7, 0x97, 0x60, 0x73, 0x1E, 0x00, 0x62, 0x44, 0x1A, 0xB8, 0x38, 0x82, 0x64, 0x9F, 0x26, 0x41, - 0xAD, 0x45, 0x46, 0x92, 0x27, 0x5E, 0x55, 0x2F, 0x8C, 0xA3, 0xA5, 0x7D, 0x69, 0xD5, 0x95, 0x3B, - 0x07, 0x58, 0xB3, 0x40, 0x86, 0xAC, 0x1D, 0xF7, 0x30, 0x37, 0x6B, 0xE4, 0x88, 0xD9, 0xE7, 0x89, - 0xE1, 0x1B, 0x83, 0x49, 0x4C, 0x3F, 0xF8, 0xFE, 0x8D, 0x53, 0xAA, 0x90, 0xCA, 0xD8, 0x85, 0x61, - 0x20, 0x71, 0x67, 0xA4, 0x2D, 0x2B, 0x09, 0x5B, 0xCB, 0x9B, 0x25, 0xD0, 0xBE, 0xE5, 0x6C, 0x52, - 0x59, 0xA6, 0x74, 0xD2, 0xE6, 0xF4, 0xB4, 0xC0, 0xD1, 0x66, 0xAF, 0xC2, 0x39, 0x4B, 0x63, 0xB6 + 0xE6F87E5C5B711FD0, 0x258377800924FA16, 0xC849E07E852EA4A8, 0x5B4686A18F06C16A, + 0x0B32E9A2D77B416E, 0xABDA37A467815C66, 0xF61796A81A686676, 0xF5DC0B706391954B, + 0x4862F38DB7E64BF1, 0xFF5C629A68BD85C5, 0xCB827DA6FCD75795, 0x66D36DAF69B9F089, + 0x356C9F74483D83B0, 0x7CBCECB1238C99A1, 0x36A702AC31C4708D, 0x9EB6A8D02FBCDFD6, + 0x8B19FA51E5B3AE37, 0x9CCFB5408A127D0B, 0xBC0C78B508208F5A, 0xE533E3842288ECED, + 0xCEC2C7D377C15FD2, 0xEC7817B6505D0F5E, 0xB94CC2C08336871D, 0x8C205DB4CB0B04AD, + 0x763C855B28A0892F, 0x588D1B79F6FF3257, 0x3FECF69E4311933E, 0x0FC0D39F803A18C9, + 0xEE010A26F5F3AD83, 0x10EFE8F4411979A6, 0x5DCDA10C7DE93A10, 0x4A1BEE1D1248E92C, + 0x53BFF2DB21847339, 0xB4F50CCFA6A23D09, 0x5FB4BC9CD84798CD, 0xE88A2D8B071C56F9, + 0x7F7771695A756A9C, 0xC5F02E71A0BA1EBC, 0xA663F9AB4215E672, 0x2EB19E22DE5FBB78, + 0x0DB9CE0F2594BA14, 0x82520E6397664D84, 0x2F031E6A0208EA98, 0x5C7F2144A1BE6BF0, + 0x7A37CB1CD16362DB, 0x83E08E2B4B311C64, 0xCF70479BAB960E32, 0x856BA986B9DEE71E, + 0xB5478C877AF56CE9, 0xB8FE42885F61D6FD, 0x1BDD0156966238C8, 0x622157923EF8A92E, + 0xFC97FF42114476F8, 0x9D7D350856452CEB, 0x4C90C9B0E0A71256, 0x2308502DFBCB016C, + 0x2D7A03FAA7A64845, 0xF46E8B38BFC6C4AB, 0xBDBEF8FDD477DEBA, 0x3AAC4CEBC8079B79, + 0xF09CB105E8879D0C, 0x27FA6A10AC8A58CB, 0x8960E7C1401D0CEA, 0x1A6F811E4A356928, + 0x90C4FB0773D196FF, 0x43501A2F609D0A9F, 0xF7A516E0C63F3796, 0x1CE4A6B3B8DA9252, + 0x1324752C38E08A9B, 0xA5A864733BEC154F, 0x2BF124575549B33F, 0xD766DB15440DC5C7, + 0xA7D179E39E42B792, 0xDADF151A61997FD3, 0x86A0345EC0271423, 0x38D5517B6DA939A4, + 0x6518F077104003B4, 0x02791D90A5AEA2DD, 0x88D267899C4A5D0A, 0x930F66DF0A2865C2, + 0x4EE9D4204509B08B, 0x325538916685292A, 0x412907BFC533A842, 0xB27E2B62544DC673, + 0x6C5304456295E007, 0x5AF406E95351908A, 0x1F2F3B6BC123616F, 0xC37B09DC5255E5C6, + 0x3967D133B1FE6844, 0x298839C7F0E711E2, 0x409B87F71964F9A2, 0xE938ADC3DB4B0719, + 0x0C0B4E47F9C3EBF4, 0x5534D576D36B8843, 0x4610A05AEB8B02D8, 0x20C3CDF58232F251, + 0x6DE1840DBEC2B1E7, 0xA0E8DE06B0FA1D08, 0x7B854B540D34333B, 0x42E29A67BCCA5B7F, + 0xD8A6088AC437DD0E, 0xC63BB3A9D943ED81, 0x21714DBD5E65A3B1, 0x6761EDE7B5EEA169, + 0x2431F7C8D573ABF6, 0xD51FC685E1A3671A, 0x5E063CD40410C92D, 0x283AB98F2CB04002, + 0x8FEBC06CB2F2F790, 0x17D64F116FA1D33C, 0xE07359F1A99EE4AA, 0x784ED68C74CDC006, + 0x6E2A19D5C73B42DA, 0x8712B4161C7045C3, 0x371582E4ED93216D, 0xACE390414939F6FC, + 0x7EC5F12186223B7C, 0xC0B094042BAC16FB, 0xF9D745379A527EBF, 0x737C3F2EA3B68168, + 0x33E7B8D9BAD278CA, 0xA9A32A34C22FFEBB, 0xE48163CCFEDFBD0D, 0x8E5940246EA5A670, + 0x51C6EF4B842AD1E4, 0x22BAD065279C508C, 0xD91488C218608CEE, 0x319EA5491F7CDA17, + 0xD394E128134C9C60, 0x094BF43272D5E3B3, 0x9BF612A5A4AAD791, 0xCCBBDA43D26FFD0F, + 0x34DE1F3C946AD250, 0x4F5B5468995EE16B, 0xDF9FAF6FEA8F7794, 0x2648EA5870DD092B, + 0xBFC7E56D71D97C67, 0xDDE6B2FF4F21D549, 0x3C276B463AE86003, 0x91767B4FAF86C71F, + 0x68A13E7835D4B9A0, 0xB68C115F030C9FD4, 0x141DD2C916582001, 0x983D8F7DDD5324AC, + 0x64AA703FCC175254, 0xC2C989948E02B426, 0x3E5E76D69F46C2DE, 0x50746F03587D8004, + 0x45DB3D829272F1E5, 0x60584A029B560BF3, 0xFBAE58A73FFCDC62, 0xA15A5E4E6CAD4CE8, + 0x4BA96E55CE1FB8CC, 0x08F9747AAE82B253, 0xC102144CF7FB471B, 0x9F042898F3EB8E36, + 0x068B27ADF2EFFB7A, 0xEDCA97FE8C0A5EBE, 0x778E0513F4F7D8CF, 0x302C2501C32B8BF7, + 0x8D92DDFC175C554D, 0xF865C57F46052F5F, 0xEAF3301BA2B2F424, 0xAA68B7ECBBD60D86, + 0x998F0F350104754C, 0x0000000000000000, 0xF12E314D34D0CCEC, 0x710522BE061823B5, + 0xAF280D9930C005C1, 0x97FD5CE25D693C65, 0x19A41CC633CC9A15, 0x95844172F8C79EB8, + 0xDC5432B7937684A9, 0x9436C13A2490CF58, 0x802B13F332C8EF59, 0xC442AE397CED4F5C, + 0xFA1CD8EFE3AB8D82, 0xF2E5AC954D293FD1, 0x6AD823E8907A1B7D, 0x4D2249F83CF043B6, + 0x03CB9DD879F9F33D, 0xDE2D2F2736D82674, 0x2A43A41F891EE2DF, 0x6F98999D1B6C133A, + 0xD4AD46CD3DF436FA, 0xBB35DF50269825C0, 0x964FDCAA813E6D85, 0xEB41B0537EE5A5C4, + 0x0540BA758B160847, 0xA41AE43BE7BB44AF, 0xE3B8C429D0671797, 0x819993BBEE9FBEB9, + 0xAE9A8DD1EC975421, 0xF3572CDD917E6E31, 0x6393D7DAE2AFF8CE, 0x47A2201237DC5338, + 0xA32343DEC903EE35, 0x79FC56C4A89A91E6, 0x01B28048DC5751E0, 0x1296F564E4B7DB7B, + 0x75F7188351597A12, 0xDB6D9552BDCE2E33, 0x1E9DBB231D74308F, 0x520D7293FDD322D9, + 0xE20A44610C304677, 0xFEEEE2D2B4EAD425, 0xCA30FDEE20800675, 0x61EACA4A47015A13, + 0xE74AFE1487264E30, 0x2CC883B27BF119A5, 0x1664CF59B3F682DC, 0xA811AA7C1E78AF5B, + 0x1D5626FB648DC3B2, 0xB73E9117DF5BCE34, 0xD05F7CF06AB56F5D, 0xFD257F0ACD132718, + 0x574DC8E676C52A9E, 0x0739A7E52EB8AA9A, 0x5486553E0F3CD9A3, 0x56FF48AEAA927B7E, + 0xBE756525AD8E2D87, 0x7D0E6CF9FFDBC841, 0x3B1ECCA31450CA99, 0x6913BE30E983E840, + 0xAD511009956EA71C, 0xB1B5B6BA2DB4354E, 0x4469BDCA4E25A005, 0x15AF5281CA0F71E1, + 0x744598CB8D0E2BF2, 0x593F9B312AA863B7, 0xEFB38A6E29A4FC63, 0x6B6AA3A04C2D4A9D, + 0x3D95EB0EE6BF31E3, 0xA291C3961554BFD5, 0x18169C8EEF9BCBF5, 0x115D68BC9D4E2846, + 0xBA875F18FACF7420, 0xD1EDFCB8B6E23EBD, 0xB00736F2F1E364AE, 0x84D929CE6589B6FE, + 0x70B7A2F6DA4F7255, 0x0E7253D75C6D4929, 0x04F23A3D574159A7, 0x0A8069EA0B2C108E, + 0x49D073C56BB11A11, 0x8AAB7A1939E4FFD7, 0xCD095A0B0E38ACEF, 0xC9FB60365979F548, + 0x92BDE697D67F3422, 0xC78933E10514BC61, 0xE1C1D9B975C9B54A, 0xD2266160CF1BCD80, + 0x9A4492ED78FD8671, 0xB3CCAB2A881A9793, 0x72CEBF667FE1D088, 0xD6D45B5D985A9427 + }; + static const uint64_t T1[256] = + { + 0xC811A8058C3F55DE, 0x65F5B43196B50619, 0xF74F96B1D6706E43, 0x859D1E8BCB43D336, + 0x5AAB8A85CCFA3D84, 0xF9C7BF99C295FCFD, 0xA21FD5A1DE4B630F, 0xCDB3EF763B8B456D, + 0x803F59F87CF7C385, 0xB27C73BE5F31913C, 0x98E3AC6633B04821, 0xBF61674C26B8F818, + 0x0FFBC995C4C130C8, 0xAAA0862010761A98, 0x6057F342210116AA, 0xF63C760C0654CC35, + 0x2DDB45CC667D9042, 0xBCF45A964BD40382, 0x68E8A0C3EF3C6F3D, 0xA7BD92D269FF73BC, + 0x290AE20201ED2287, 0xB7DE34CDE885818F, 0xD901EEA7DD61059B, 0xD6FA273219A03553, + 0xD56F1AE874CCCEC9, 0xEA31245C2E83F554, 0x7034555DA07BE499, 0xCE26D2AC56E7BEF7, + 0xFD161857A5054E38, 0x6A0E7DA4527436D1, 0x5BD86A381CDE9FF2, 0xCAF7756231770C32, + 0xB09AAED9E279C8D0, 0x5DEF1091C60674DB, 0x111046A2515E5045, 0x23536CE4729802FC, + 0xC50CBCF7F5B63CFA, 0x73A16887CD171F03, 0x7D2941AFD9F28DBD, 0x3F5E3EB45A4F3B9D, + 0x84EEFE361B677140, 0x3DB8E3D3E7076271, 0x1A3A28F9F20FD248, 0x7EBC7C75B49E7627, + 0x74E5F293C7EB565C, 0x18DCF59E4F478BA4, 0x0C6EF44FA9ADCB52, 0xC699812D98DAC760, + 0x788B06DC6E469D0E, 0xFC65F8EA7521EC4E, 0x30A5F7219E8E0B55, 0x2BEC3F65BCA57B6B, + 0xDDD04969BAF1B75E, 0x99904CDBE394EA57, 0x14B201D1E6EA40F6, 0xBBB0C08241284ADD, + 0x50F20463BF8F1DFF, 0xE8D7F93B93CBACB8, 0x4D8CB68E477C86E8, 0xC1DD1B3992268E3F, + 0x7C5AA11209D62FCB, 0x2F3D98ABDB35C9AE, 0x671369562BFD5FF5, 0x15C1E16C36CEE280, + 0x1D7EB2EDF8F39B17, 0xDA94D37DB00DFE01, 0x877BC3EC760B8ADA, 0xCB8495DFE153AE44, + 0x05A24773B7B410B3, 0x12857B783C32ABDF, 0x8EB770D06812513B, 0x536739B9D2E3E665, + 0x584D57E271B26468, 0xD789C78FC9849725, 0xA935BBFA7D1AE102, 0x8B1537A3DFA64188, + 0xD0CD5D9BC378DE7A, 0x4AC82C9A4D80CFB7, 0x42777F1B83BDB620, 0x72D2883A1D33BD75, + 0x5E7A2D4BAB6A8F41, 0xF4DAAB6BBB1C95D9, 0x905CFFE7FD8D31B6, 0x83AA6422119B381F, + 0xC0AEFB8442022C49, 0xA0F908C663033AE3, 0xA428AF0804938826, 0xADE41C341A8A53C7, + 0xAE7121EE77E6A85D, 0xC47F5C4A25929E8C, 0xB538E9AA55CDD863, 0x06377AA9DAD8EB29, + 0xA18AE87BB3279895, 0x6EDFDA6A35E48414, 0x6B7D9D19825094A7, 0xD41CFA55A4E86CBF, + 0xE5CAEDC9EA42C59C, 0xA36C351C0E6FC179, 0x5181E4DE6FABBF89, 0xFFF0C530184D17D4, + 0x9D41EB1584045892, 0x1C0D525028D73961, 0xF178EC180CA8856A, 0x9A0571018EF811CD, + 0x4091A27C3EF5EFCC, 0x19AF15239F6329D2, 0x347450EFF91EB990, 0xE11B4A078DD27759, + 0xB9561DE5FC601331, 0x912F1F5A2DA993C0, 0x1654DCB65BA2191A, 0x3E2DDE098A6B99EB, + 0x8A66D71E0F82E3FE, 0x8C51ADB7D55A08D7, 0x4533E50F8941FF7F, 0x02E6DD67BD4859EC, + 0xE068AABA5DF6D52F, 0xC24826E3FF4A75A5, 0x6C39070D88ACDDF8, 0x6486548C4691A46F, + 0xD1BEBD26135C7C0C, 0xB30F93038F15334A, 0x82D9849FC1BF9A69, 0x9C320BA85420FAE4, + 0xFA528243AFF90767, 0x9ED4D6CFE968A308, 0xB825FD582C44B147, 0x9B7691BC5EDCB3BB, + 0xC7EA619048FE6516, 0x1063A61F817AF233, 0x47D538683409A693, 0x63C2CE984C6DED30, + 0x2A9FDFD86C81D91D, 0x7B1E3B06032A6694, 0x666089EBFBD9FD83, 0x0A598EE67375207B, + 0x07449A140AFC495F, 0x2CA8A571B6593234, 0x1F986F8A45BBC2FB, 0x381AA4A050B372C2, + 0x5423A3ADD81FAF3A, 0x17273C0B8B86BB6C, 0xFE83258DC869B5A2, 0x287902BFD1C980F1, + 0xF5A94BD66B3837AF, 0x88800A79B2CABA12, 0x55504310083B0D4C, 0xDF36940E07B9EEB2, + 0x04D1A7CE6790B2C5, 0x612413FFF125B4DC, 0x26F12B97C52C124F, 0x86082351A62F28AC, + 0xEF93632F9937E5E7, 0x3507B052293A1BE6, 0xE72C30AE570A9C70, 0xD3586041AE1425E0, + 0xDE4574B3D79D4CC4, 0x92BA228040C5685A, 0xF00B0CA5DC8C271C, 0xBE1287F1F69C5A6E, + 0xF39E317FB1E0DC86, 0x495D114020EC342D, 0x699B407E3F18CD4B, 0xDCA3A9D46AD51528, + 0x0D1D14F279896924, 0x0000000000000000, 0x593EB75FA196C61E, 0x2E4E78160B116BD8, + 0x6D4AE7B058887F8E, 0xE65FD013872E3E06, 0x7A6DDBBBD30EC4E2, 0xAC97FC89CAAEF1B1, + 0x09CCB33C1E19DBE1, 0x89F3EAC462EE1864, 0x7770CF49AA87ADC6, 0x56C57ECA6557F6D6, + 0x03953DDA6D6CFB9A, 0x36928D884456E07C, 0x1EEB8F37959F608D, 0x31D6179C4EAAA923, + 0x6FAC3AD7E5C02662, 0x43049FA653991456, 0xABD3669DC052B8EE, 0xAF02C153A7C20A2B, + 0x3CCB036E3723C007, 0x93C9C23D90E1CA2C, 0xC33BC65E2F6ED7D3, 0x4CFF56339758249E, + 0xB1E94E64325D6AA6, 0x37E16D359472420A, 0x79F8E661BE623F78, 0x5214D90402C74413, + 0x482EF1FDF0C8965B, 0x13F69BC5EC1609A9, 0x0E88292814E592BE, 0x4E198B542A107D72, + 0xCCC00FCBEBAFE71B, 0x1B49C844222B703E, 0x2564164DA840E9D5, 0x20C6513E1FF4F966, + 0xBAC3203F910CE8AB, 0xF2EDD1C261C47EF0, 0x814CB945ACD361F3, 0x95FEB8944A392105, + 0x5C9CF02C1622D6AD, 0x971865F3F77178E9, 0xBD87BA2B9BF0A1F4, 0x444005B259655D09, + 0xED75BE48247FBC0B, 0x7596122E17CFF42A, 0xB44B091785E97A15, 0x966B854E2755DA9F, + 0xEEE0839249134791, 0x32432A4623C652B9, 0xA8465B47AD3E4374, 0xF8B45F2412B15E8B, + 0x2417F6F078644BA3, 0xFB2162FE7FDDA511, 0x4BBBCC279DA46DC1, 0x0173E0BDD024A276, + 0x22208C59A2BCA08A, 0x8FC4906DB836F34D, 0xE4B90D743A6667EA, 0x7147B5E0705F46EF, + 0x2782CB2A1508B039, 0xEC065EF5F45B1E7D, 0x21B5B183CFD05B10, 0xDBE733C060295C77, + 0x9FA73672394C017E, 0xCF55321186C31C81, 0xD8720E1A0D45A7ED, 0x3B8F997A3DDF8958, + 0x3AFC79C7EDFB2B2E, 0xE9A4198643EF0ECE, 0x5F09CDF67B4E2D37, 0x4F6A6BE9FA34DF04, + 0xB6ADD47038A123F9, 0x8D224D0A057EAAA1, 0xC96248B85C1BF7A8, 0xE3FD9760309A2EB5, + 0x0B2A6E5BA351820D, 0xEB42C4E1FEA75722, 0x948D58299A1D8373, 0x7FCF9CC864BAD451, + 0xA55B4FB5D4B72A50, 0x08BF5381CE3D7997, 0x46A6D8D5E42D04E5, 0xD22B80FC7E308796, + 0x57B69E77B57354A0, 0x3969441D8097D0B4, 0x3330CAFBF3E2F0CF, 0xE28E77DDE0BE8CC3, + 0x62B12E259C494F46, 0xA6CE726FB9DBD1CA, 0x41E242C1EED14DBA, 0x76032FF47AA30FB0 + }; + static const uint64_t T2[256] = + { + 0x45B268A93ACDE4CC, 0xAF7F0BE884549D08, 0x048354B3C1468263, 0x925435C2C80EFED2, + 0xEE4E37F27FDFFBA7, 0x167A33920C60F14D, 0xFB123B52EA03E584, 0x4A0CAB53FDBB9007, + 0x9DEAF6380F788A19, 0xCB48EC558F0CB32A, 0xB59DC4B2D6FEF7E0, 0xDCDBCA22F4F3ECB6, + 0x11DF5813549A9C40, 0xE33FDEDF568ACED3, 0xA0C1C8124322E9C3, 0x07A56B8158FA6D0D, + 0x77279579B1E1F3DD, 0xD9B18B74422AC004, 0xB8EC2D9FFFABC294, 0xF4ACF8A82D75914F, + 0x7BBF69B1EF2B6878, 0xC4F62FAF487AC7E1, 0x76CE809CC67E5D0C, 0x6711D88F92E4C14C, + 0x627B99D9243DEDFE, 0x234AA5C3DFB68B51, 0x909B1F15262DBF6D, 0x4F66EA054B62BCB5, + 0x1AE2CF5A52AA6AE8, 0xBEA053FBD0CE0148, 0xED6808C0E66314C9, 0x43FE16CD15A82710, + 0xCD049231A06970F6, 0xE7BC8A6C97CC4CB0, 0x337CE835FCB3B9C0, 0x65DEF2587CC780F3, + 0x52214EDE4132BB50, 0x95F15E4390F493DF, 0x870839625DD2E0F1, 0x41313C1AFB8B66AF, + 0x91720AF051B211BC, 0x477D427ED4EEA573, 0x2E3B4CEEF6E3BE25, 0x82627834EB0BCC43, + 0x9C03E3DD78E724C8, 0x2877328AD9867DF9, 0x14B51945E243B0F2, 0x574B0F88F7EB97E2, + 0x88B6FA989AA4943A, 0x19C4F068CB168586, 0x50EE6409AF11FAEF, 0x7DF317D5C04EABA4, + 0x7A567C5498B4C6A9, 0xB6BBFB804F42188E, 0x3CC22BCF3BC5CD0B, 0xD04336EAAA397713, + 0xF02FAC1BEC33132C, 0x2506DBA7F0D3488D, 0xD7E65D6BF2C31A1E, 0x5EB9B2161FF820F5, + 0x842E0650C46E0F9F, 0x716BEB1D9E843001, 0xA933758CAB315ED4, 0x3FE414FDA2792265, + 0x27C9F1701EF00932, 0x73A4C1CA70A771BE, 0x94184BA6E76B3D0E, 0x40D829FF8C14C87E, + 0x0FBEC3FAC77674CB, 0x3616A9634A6A9572, 0x8F139119C25EF937, 0xF545ED4D5AEA3F9E, + 0xE802499650BA387B, 0x6437E7BD0B582E22, 0xE6559F89E053E261, 0x80AD52E305288DFC, + 0x6DC55A23E34B9935, 0xDE14E0F51AD0AD09, 0xC6390578A659865E, 0x96D7617109487CB1, + 0xE2D6CB3A21156002, 0x01E915E5779FAED1, 0xADB0213F6A77DCB7, 0x9880B76EB9A1A6AB, + 0x5D9F8D248644CF9B, 0xFD5E4536C5662658, 0xF1C6B9FE9BACBDFD, 0xEACD6341BE9979C4, + 0xEFA7221708405576, 0x510771ECD88E543E, 0xC2BA51CB671F043D, 0x0AD482AC71AF5879, + 0xFE787A045CDAC936, 0xB238AF338E049AED, 0xBD866CC94972EE26, 0x615DA6EBBD810290, + 0x3295FDD08B2C1711, 0xF834046073BF0AEA, 0xF3099329758FFC42, 0x1CAEB13E7DCFA934, + 0xBA2307481188832B, 0x24EFCE42874CE65C, 0x0E57D61FB0E9DA1A, 0xB3D1BAD6F99B343C, + 0xC0757B1C893C4582, 0x2B510DB8403A9297, 0x5C7698C1F1DB614A, 0x3E0D0118D5E68CB4, + 0xD60F488E855CB4CF, 0xAE961E0DF3CB33D9, 0x3A8E55AB14A00ED7, 0x42170328623789C1, + 0x838B6DD19C946292, 0x895FEF7DED3B3AEB, 0xCFCBB8E64E4A3149, 0x064C7E642F65C3DC, + 0x3D2B3E2A4C5A63DA, 0x5BD3F340A9210C47, 0xB474D157A1615931, 0xAC5934DA1DE87266, + 0x6EE365117AF7765B, 0xC86ED36716B05C44, 0x9BA6885C201D49C5, 0xB905387A88346C45, + 0x131072C4BAB9DDFF, 0xBF49461EA751AF99, 0xD52977BC1CE05BA1, 0xB0F785E46027DB52, + 0x546D30BA6E57788C, 0x305AD707650F56AE, 0xC987C682612FF295, 0xA5AB8944F5FBC571, + 0x7ED528E759F244CA, 0x8DDCBBCE2C7DB888, 0xAA154ABE328DB1BA, 0x1E619BE993ECE88B, + 0x09F2BD9EE813B717, 0x7401AA4B285D1CB3, 0x21858F143195CAEE, 0x48C381841398D1B8, + 0xFCB750D3B2F98889, 0x39A86A998D1CE1B9, 0x1F888E0CE473465A, 0x7899568376978716, + 0x02CF2AD7EE2341BF, 0x85C713B5B3F1A14E, 0xFF916FE12B4567E7, 0x7C1A0230B7D10575, + 0x0C98FCC85ECA9BA5, 0xA3E7F720DA9E06AD, 0x6A6031A2BBB1F438, 0x973E74947ED7D260, + 0x2CF4663918C0FF9A, 0x5F50A7F368678E24, 0x34D983B4A449D4CD, 0x68AF1B755592B587, + 0x7F3C3D022E6DEA1B, 0xABFC5F5B45121F6B, 0x0D71E92D29553574, 0xDFFDF5106D4F03D8, + 0x081BA87B9F8C19C6, 0xDB7EA1A3AC0981BB, 0xBBCA12AD66172DFA, 0x79704366010829C7, + 0x179326777BFF5F9C, 0x0000000000000000, 0xEB2476A4C906D715, 0x724DD42F0738DF6F, + 0xB752EE6538DDB65F, 0x37FFBC863DF53BA3, 0x8EFA84FCB5C157E6, 0xE9EB5C73272596AA, + 0x1B0BDABF2535C439, 0x86E12C872A4D4E20, 0x9969A28BCE3E087A, 0xFAFB2EB79D9C4B55, + 0x056A4156B6D92CB2, 0x5A3AE6A5DEBEA296, 0x22A3B026A8292580, 0x53C85B3B36AD1581, + 0xB11E900117B87583, 0xC51F3A4A3FE56930, 0xE019E1EDCF3621BD, 0xEC811D2591FCBA18, + 0x445B7D4C4D524A1D, 0xA8DA6069DCAEF005, 0x58F5CC72309DE329, 0xD4C062596B7FF570, + 0xCE22AD0339D59F98, 0x591CD99747024DF8, 0x8B90C5AA03187B54, 0xF663D27FC356D0F0, + 0xD8589E9135B56ED5, 0x35309651D3D67A1C, 0x12F96721CD26732E, 0xD28C1C3D441A36AC, + 0x492A946164077F69, 0x2D1D73DC6F5F514B, 0x6F0A70F40D68D88A, 0x60B4B30ECA1EAC41, + 0xD36509D83385987D, 0x0B3D97490630F6A8, 0x9ECCC90A96C46577, 0xA20EE2C5AD01A87C, + 0xE49AB55E0E70A3DE, 0xA4429CA182646BA0, 0xDA97B446DB962F6A, 0xCCED87D4D7F6DE27, + 0x2AB8185D37A53C46, 0x9F25DCEFE15BCBA6, 0xC19C6EF9FEA3EB53, 0xA764A3931BD884CE, + 0x2FD2590B817C10F4, 0x56A21A6D80743933, 0xE573A0BB79EF0D0F, 0x155C0CA095DC1E23, + 0x6C2C4FC694D437E4, 0x10364DF623053291, 0xDD32DFC7836C4267, 0x03263F3299BCEF6E, + 0x66F8CD6AE57B6F9D, 0x8C35AE2B5BE21659, 0x31B3C2E21290F87F, 0x93BD2027BF915003, + 0x69460E90220D1B56, 0x299E276FAE19D328, 0x63928C3C53A2432F, 0x7082FEF8E91B9ED0, + 0xBC6F792C3EED40F7, 0x4C40D537D2DE53DB, 0x75E8BFAE5FC2B262, 0x4DA9C0D2A541FD0A, + 0x4E8FFFE03CFD1264, 0x2620E495696FA7E3, 0xE1F0F408B8A98F6C, 0xD1AA230FDDA6D9C2, + 0xC7D0109DD1C6288F, 0x8A79D04F7487D585, 0x4694579BA3710BA2, 0x38417F7CFA834F68, + 0x1D47A4DB0A5007E5, 0x206C9AF1460A643F, 0xA128DDF734BD4712, 0x8144470672B7232D, + 0xF2E086CC02105293, 0x182DE58DBC892B57, 0xCAA1F9B0F8931DFB, 0x6B892447CC2E5AE9, + 0xF9DD11850420A43B, 0x4BE5BEB68A243ED6, 0x5584255F19C8D65D, 0x3B67404E633FA006, + 0xA68DB6766C472A1F, 0xF78AC79AB4C97E21, 0xC353442E1080AAEC, 0x9A4F9DB95782E714 + }; + static const uint64_t T3[256] = + { + 0x05BA7BC82C9B3220, 0x31A54665F8B65E4F, 0xB1B651F77547F4D4, 0x8BFA0D857BA46682, + 0x85A96C5AA16A98BB, 0x990FAEF908EB79C9, 0xA15E37A247F4A62D, 0x76857DCD5D27741E, + 0xF8C50B800A1820BC, 0xBE65DCB201F7A2B4, 0x666D1B986F9426E7, 0x4CC921BF53C4E648, + 0x95410A0F93D9CA42, 0x20CDCCAA647BA4EF, 0x429A4060890A1871, 0x0C4EA4F69B32B38B, + 0xCCDA362DDE354CD3, 0x96DC23BC7C5B2FA9, 0xC309BB68AA851AB3, 0xD26131A73648E013, + 0x021DC52941FC4DB2, 0xCD5ADAB7704BE48A, 0xA77965D984ED71E6, 0x32386FD61734BBA4, + 0xE82D6DD538AB7245, 0x5C2147EA6177B4B1, 0x5DA1AB70CF091CE8, 0xAC907FCE72B8BDFF, + 0x57C85DFD972278A8, 0xA4E44C6A6B6F940D, 0x3851995B4F1FDFE4, 0x62578CCAED71BC9E, + 0xD9882BB0C01D2C0A, 0x917B9D5D113C503B, 0xA2C31E11A87643C6, 0xE463C923A399C1CE, + 0xF71686C57EA876DC, 0x87B4A973E096D509, 0xAF0D567D9D3A5814, 0xB40C2A3F59DCC6F4, + 0x3602F88495D121DD, 0xD3E1DD3D9836484A, 0xF945E71AA46688E5, 0x7518547EB2A591F5, + 0x9366587450C01D89, 0x9EA81018658C065B, 0x4F54080CBC4603A3, 0x2D0384C65137BF3D, + 0xDC325078EC861E2A, 0xEA30A8FC79573FF7, 0x214D2030CA050CB6, 0x65F0322B8016C30C, + 0x69BE96DD1B247087, 0xDB95EE9981E161B8, 0xD1FC1814D9CA05F8, 0x820ED2BBCC0DE729, + 0x63D76050430F14C7, 0x3BCCB0E8A09D3A0F, 0x8E40764D573F54A2, 0x39D175C1E16177BD, + 0x12F5A37C734F1F4B, 0xAB37C12F1FDFC26D, 0x5648B167395CD0F1, 0x6C04ED1537BF42A7, + 0xED97161D14304065, 0x7D6C67DAAB72B807, 0xEC17FA87BA4EE83C, 0xDFAF79CB0304FBC1, + 0x733F060571BC463E, 0x78D61C1287E98A27, 0xD07CF48E77B4ADA1, 0xB9C262536C90DD26, + 0xE2449B5860801605, 0x8FC09AD7F941FCFB, 0xFAD8CEA94BE46D0E, 0xA343F28B0608EB9F, + 0x9B126BD04917347B, 0x9A92874AE7699C22, 0x1B017C42C4E69EE0, 0x3A4C5C720EE39256, + 0x4B6E9F5E3EA399DA, 0x6BA353F45AD83D35, 0xE7FEE0904C1B2425, 0x22D009832587E95D, + 0x842980C00F1430E2, 0xC6B3C0A0861E2893, 0x087433A419D729F2, 0x341F3DADD42D6C6F, + 0xEE0A3FAEFBB2A58E, 0x4AEE73C490DD3183, 0xAAB72DB5B1A16A34, 0xA92A04065E238FDF, + 0x7B4B35A1686B6FCC, 0x6A23BF6EF4A6956C, 0x191CB96B851AD352, 0x55D598D4D6DE351A, + 0xC9604DE5F2AE7EF3, 0x1CA6C2A3A981E172, 0xDE2F9551AD7A5398, 0x3025AAFF56C8F616, + 0x15521D9D1E2860D9, 0x506FE31CFA45073A, 0x189C55F12B647B0B, 0x0180EC9AAE7EA859, + 0x7CEC8B40050C105E, 0x2350E5198BF94104, 0xEF8AD33455CC0DD7, 0x07A7BEE16D677F92, + 0xE5E325B90DE76997, 0x5A061591A26E637A, 0xB611EF1618208B46, 0x09F4DF3EB7A981AB, + 0x1EBB078AE87DACC0, 0xB791038CB65E231F, 0x0FD38D4574B05660, 0x67EDF702C1EA8EBE, + 0xBA5F4BE0831238CD, 0xE3C477C2CEFEBE5C, 0x0DCE486C354C1BD2, 0x8C5DB36416C31910, + 0x26EA9ED1A7627324, 0x039D29B3EF82E5EB, 0x9F28FC82CBF2AE02, 0xA8AAE89CF05D2786, + 0x431AACFA2774B028, 0xCF471F9E31B7A938, 0x581BD0B8E3922EC8, 0xBC78199B400BEF06, + 0x90FB71C7BF42F862, 0x1F3BEB1046030499, 0x683E7A47B55AD8DE, 0x988F4263A695D190, + 0xD808C72A6E638453, 0x0627527BC319D7CB, 0xEBB04466D72997AE, 0xE67E0C0AE2658C7C, + 0x14D2F107B056C880, 0x7122C32C30400B8C, 0x8A7AE11FD5DACEDB, 0xA0DEDB38E98A0E74, + 0xAD109354DCC615A6, 0x0BE91A17F655CC19, 0x8DDD5FFEB8BDB149, 0xBFE53028AF890AED, + 0xD65BA6F5B4AD7A6A, 0x7956F0882997227E, 0x10E8665532B352F9, 0x0E5361DFDACEFE39, + 0xCEC7F3049FC90161, 0xFF62B561677F5F2E, 0x975CCF26D22587F0, 0x51EF0F86543BAF63, + 0x2F1E41EF10CBF28F, 0x52722635BBB94A88, 0xAE8DBAE73344F04D, 0x410769D36688FD9A, + 0xB3AB94DE34BBB966, 0x801317928DF1AA9B, 0xA564A0F0C5113C54, 0xF131D4BEBDB1A117, + 0x7F71A2F3EA8EF5B5, 0x40878549C8F655C3, 0x7EF14E6944F05DEC, 0xD44663DCF55137D8, + 0xF2ACFD0D523344FC, 0x0000000000000000, 0x5FBC6E598EF5515A, 0x16CF342EF1AA8532, + 0xB036BD6DDB395C8D, 0x13754FE6DD31B712, 0xBBDFA77A2D6C9094, 0x89E7C8AC3A582B30, + 0x3C6B0E09CDFA459D, 0xC4AE0589C7E26521, 0x49735A777F5FD468, 0xCAFD64561D2C9B18, + 0xDA1502032F9FC9E1, 0x8867243694268369, 0x3782141E3BAF8984, 0x9CB5D53124704BE9, + 0xD7DB4A6F1AD3D233, 0xA6F989432A93D9BF, 0x9D3539AB8A0EE3B0, 0x53F2CAAF15C7E2D1, + 0x6E19283C76430F15, 0x3DEBE2936384EDC4, 0x5E3C82C3208BF903, 0x33B8834CB94A13FD, + 0x6470DEB12E686B55, 0x359FD1377A53C436, 0x61CAA57902F35975, 0x043A975282E59A79, + 0xFD7F70482683129C, 0xC52EE913699CCD78, 0x28B9FF0E7DAC8D1D, 0x5455744E78A09D43, + 0xCB7D88CCB3523341, 0x44BD121B4A13CFBA, 0x4D49CD25FDBA4E11, 0x3E76CB208C06082F, + 0x3FF627BA2278A076, 0xC28957F204FBB2EA, 0x453DFE81E46D67E3, 0x94C1E6953DA7621B, + 0x2C83685CFF491764, 0xF32C1197FC4DECA5, 0x2B24D6BD922E68F6, 0xB22B78449AC5113F, + 0x48F3B6EDD1217C31, 0x2E9EAD75BEB55AD6, 0x174FD8B45FD42D6B, 0x4ED4E4961238ABFA, + 0x92E6B4EEFEBEB5D0, 0x46A0D7320BEF8208, 0x47203BA8A5912A51, 0x24F75BF8E69E3E96, + 0xF0B1382413CF094E, 0xFEE259FBC901F777, 0x276A724B091CDB7D, 0xBDF8F501EE75475F, + 0x599B3C224DEC8691, 0x6D84018F99C1EAFE, 0x7498B8E41CDB39AC, 0xE0595E71217C5BB7, + 0x2AA43A273C50C0AF, 0xF50B43EC3F543B6E, 0x838E3E2162734F70, 0xC09492DB4507FF58, + 0x72BFEA9FDFC2EE67, 0x11688ACF9CCDFAA0, 0x1A8190D86A9836B9, 0x7ACBD93BC615C795, + 0xC7332C3A286080CA, 0x863445E94EE87D50, 0xF6966A5FD0D6DE85, 0xE9AD814F96D5DA1C, + 0x70A22FB69E3EA3D5, 0x0A69F68D582B6440, 0xB8428EC9C2EE757F, 0x604A49E3AC8DF12C, + 0x5B86F90B0C10CB23, 0xE1D9B2EB8F02F3EE, 0x29391394D3D22544, 0xC8E0A17F5CD0D6AA, + 0xB58CC6A5F7A26EAD, 0x8193FB08238F02C2, 0xD5C68F465B2F9F81, 0xFCFF9CD288FDBAC5, + 0x77059157F359DC47, 0x1D262E3907FF492B, 0xFB582233E59AC557, 0xDDB2BCE242F8B673, + 0x2577B76248E096CF, 0x6F99C4A6D83DA74C, 0xC1147E41EB795701, 0xF48BAF76912A9337 + }; + static const uint64_t T4[256] = + { + 0x3EF29D249B2C0A19, 0xE9E16322B6F8622F, 0x5536994047757F7A, 0x9F4D56D5A47B0B33, + 0x822567466AA1174C, 0xB8F5057DEB082FB2, 0xCC48C10BF4475F53, 0x373088D4275DEC3A, + 0x968F4325180AED10, 0x173D232CF7016151, 0xAE4ED09F946FCC13, 0xFD4B4741C4539873, + 0x1B5B3F0DD9933765, 0x2FFCB0967B644052, 0xE02376D20A89840C, 0xA3AE3A70329B18D7, + 0x419CBD2335DE8526, 0xFAFEBF115B7C3199, 0x0397074F85AA9B0D, 0xC58AD4FB4836B970, + 0xBEC60BE3FC4104A8, 0x1EFF36DC4B708772, 0x131FDC33ED8453B6, 0x0844E33E341764D3, + 0x0FF11B6EAB38CD39, 0x64351F0A7761B85A, 0x3B5694F509CFBA0E, 0x30857084B87245D0, + 0x47AFB3BD2297AE3C, 0xF2BA5C2F6F6B554A, 0x74BDC4761F4F70E1, 0xCFDFC64471EDC45E, + 0xE610784C1DC0AF16, 0x7ACA29D63C113F28, 0x2DED411776A859AF, 0xAC5F211E99A3D5EE, + 0xD484F949A87EF33B, 0x3CE36CA596E013E4, 0xD120F0983A9D432C, 0x6BC40464DC597563, + 0x69D5F5E5D1956C9E, 0x9AE95F043698BB24, 0xC9ECC8DA66A4EF44, 0xD69508C8A5B2EAC6, + 0xC40C2235C0503B80, 0x38C193BA8C652103, 0x1CEEC75D46BC9E8F, 0xD331011937515AD1, + 0xD8E2E56886ECA50F, 0xB137108D5779C991, 0x709F3B6905CA4206, 0x4FEB50831680CAEF, + 0xEC456AF3241BD238, 0x58D673AFE181ABBE, 0x242F54E7CAD9BF8C, 0x0211F1810DCC19FD, + 0x90BC4DBB0F43C60A, 0x9518446A9DA0761D, 0xA1BFCBF13F57012A, 0x2BDE4F8961E172B5, + 0x27B853A84F732481, 0xB0B1E643DF1F4B61, 0x18CC38425C39AC68, 0xD2B7F7D7BF37D821, + 0x3103864A3014C720, 0x14AA246372ABFA5C, 0x6E600DB54EBAC574, 0x394765740403A3F3, + 0x09C215F0BC71E623, 0x2A58B947E987F045, 0x7B4CDF18B477BDD8, 0x9709B5EB906C6FE0, + 0x73083C268060D90B, 0xFEDC400E41F9037E, 0x284948C6E44BE9B8, 0x728ECAE808065BFB, + 0x06330E9E17492B1A, 0x5950856169E7294E, 0xBAE4F4FCE6C4364F, 0xCA7BCF95E30E7449, + 0x7D7FD186A33E96C2, 0x52836110D85AD690, 0x4DFAA1021B4CD312, 0x913ABB75872544FA, + 0xDD46ECB9140F1518, 0x3D659A6B1E869114, 0xC23F2CABD719109A, 0xD713FE062DD46836, + 0xD0A60656B2FBC1DC, 0x221C5A79DD909496, 0xEFD26DBCA1B14935, 0x0E77EDA0235E4FC9, + 0xCBFD395B6B68F6B9, 0x0DE0EAEFA6F4D4C4, 0x0422FF1F1A8532E7, 0xF969B85EDED6AA94, + 0x7F6E2007AEF28F3F, 0x3AD0623B81A938FE, 0x6624EE8B7AADA1A7, 0xB682E8DDC856607B, + 0xA78CC56F281E2A30, 0xC79B257A45FAA08D, 0x5B4174E0642B30B3, 0x5F638BFF7EAE0254, + 0x4BC9AF9C0C05F808, 0xCE59308AF98B46AE, 0x8FC58DA9CC55C388, 0x803496C7676D0EB1, + 0xF33CAAE1E70DD7BA, 0xBB6202326EA2B4BF, 0xD5020F87201871CB, 0x9D5CA754A9B712CE, + 0x841669D87DE83C56, 0x8A6184785EB6739F, 0x420BBA6CB0741E2B, 0xF12D5B60EAC1CE47, + 0x76AC35F71283691C, 0x2C6BB7D9FECEDB5F, 0xFCCDB18F4C351A83, 0x1F79C012C3160582, + 0xF0ABADAE62A74CB7, 0xE1A5801C82EF06FC, 0x67A21845F2CB2357, 0x5114665F5DF04D9D, + 0xBF40FD2D74278658, 0xA0393D3FB73183DA, 0x05A409D192E3B017, 0xA9FB28CF0B4065F9, + 0x25A9A22942BF3D7C, 0xDB75E22703463E02, 0xB326E10C5AB5D06C, 0xE7968E8295A62DE6, + 0xB973F3B3636EAD42, 0xDF571D3819C30CE5, 0xEE549B7229D7CBC5, 0x12992AFD65E2D146, + 0xF8EF4E9056B02864, 0xB7041E134030E28B, 0xC02EDD2ADAD50967, 0x932B4AF48AE95D07, + 0x6FE6FB7BC6DC4784, 0x239AACB755F61666, 0x401A4BEDBDB807D6, 0x485EA8D389AF6305, + 0xA41BC220ADB4B13D, 0x753B32B89729F211, 0x997E584BB3322029, 0x1D683193CEDA1C7F, + 0xFF5AB6C0C99F818E, 0x16BBD5E27F67E3A1, 0xA59D34EE25D233CD, 0x98F8AE853B54A2D9, + 0x6DF70AFACB105E79, 0x795D2E99B9BBA425, 0x8E437B6744334178, 0x0186F6CE886682F0, + 0xEBF092A3BB347BD2, 0xBCD7FA62F18D1D55, 0xADD9D7D011C5571E, 0x0BD3E471B1BDFFDE, + 0xAA6C2F808EEAFEF4, 0x5EE57D31F6C880A4, 0xF50FA47FF044FCA0, 0x1ADDC9C351F5B595, + 0xEA76646D3352F922, 0x0000000000000000, 0x85909F16F58EBEA6, 0x46294573AAF12CCC, + 0x0A5512BF39DB7D2E, 0x78DBD85731DD26D5, 0x29CFBE086C2D6B48, 0x218B5D36583A0F9B, + 0x152CD2ADFACD78AC, 0x83A39188E2C795BC, 0xC3B9DA655F7F926A, 0x9ECBA01B2C1D89C3, + 0x07B5F8509F2FA9EA, 0x7EE8D6C926940DCF, 0x36B67E1AAF3B6ECA, 0x86079859702425AB, + 0xFB7849DFD31AB369, 0x4C7C57CC932A51E2, 0xD96413A60E8A27FF, 0x263EA566C715A671, + 0x6C71FC344376DC89, 0x4A4F595284637AF8, 0xDAF314E98B20BCF2, 0x572768C14AB96687, + 0x1088DB7C682EC8BB, 0x887075F9537A6A62, 0x2E7A4658F302C2A2, 0x619116DBE582084D, + 0xA87DDE018326E709, 0xDCC01A779C6997E8, 0xEDC39C3DAC7D50C8, 0xA60A33A1A078A8C0, + 0xC1A82BE452B38B97, 0x3F746BEA134A88E9, 0xA228CCBEBAFD9A27, 0xABEAD94E068C7C04, + 0xF48952B178227E50, 0x5CF48CB0FB049959, 0x6017E0156DE48ABD, 0x4438B4F2A73D3531, + 0x8C528AE649FF5885, 0xB515EF924DFCFB76, 0x0C661C212E925634, 0xB493195CC59A7986, + 0x9CDA519A21D1903E, 0x32948105B5BE5C2D, 0x194ACE8CD45F2E98, 0x438D4CA238129CDB, + 0x9B6FA9CABEFE39D4, 0x81B26009EF0B8C41, 0xDED1EBF691A58E15, 0x4E6DA64D9EE6481F, + 0x54B06F8ECF13FD8A, 0x49D85E1D01C9E1F5, 0xAFC826511C094EE3, 0xF698A33075EE67AD, + 0x5AC7822EEC4DB243, 0x8DD47C28C199DA75, 0x89F68337DB1CE892, 0xCDCE37C57C21DDA3, + 0x530597DE503C5460, 0x6A42F2AA543FF793, 0x5D727A7E73621BA9, 0xE232875307459DF1, + 0x56A19E0FC2DFE477, 0xC61DD3B4CD9C227D, 0xE5877F03986A341B, 0x949EB2A415C6F4ED, + 0x6206119460289340, 0x6380E75AE84E11B0, 0x8BE772B6D6D0F16F, 0x50929091D596CF6D, + 0xE86795EC3E9EE0DF, 0x7CF927482B581432, 0xC86A3E14EEC26DB4, 0x7119CDA78DACC0F6, + 0xE40189CD100CB6EB, 0x92ADBC3A028FDFF7, 0xB2A017C2D2D3529C, 0x200DABF8D05C8D6B, + 0x34A78F9BA2F77737, 0xE3B4719D8F231F01, 0x45BE423C2F5BB7C1, 0xF71E55FEFD88E55D, + 0x6853032B59F3EE6E, 0x65B3E9C4FF073AAA, 0x772AC3399AE5EBEC, 0x87816E97F842A75B, + 0x110E2DB2E0484A4B, 0x331277CB3DD8DEDD, 0xBD510CAC79EB9FA5, 0x352179552A91F5C7 + }; + static const uint64_t T5[256] = + { + 0x8AB0A96846E06A6D, 0x43C7E80B4BF0B33A, 0x08C9B3546B161EE5, 0x39F1C235EBA990BE, + 0xC1BEF2376606C7B2, 0x2C209233614569AA, 0xEB01523B6FC3289A, 0x946953AB935ACEDD, + 0x272838F63E13340E, 0x8B0455ECA12BA052, 0x77A1B2C4978FF8A2, 0xA55122CA13E54086, + 0x2276135862D3F1CD, 0xDB8DDFDE08B76CFE, 0x5D1E12C89E4A178A, 0x0E56816B03969867, + 0xEE5F79953303ED59, 0xAFED748BAB78D71D, 0x6D929F2DF93E53EE, 0xF5D8A8F8BA798C2A, + 0xF619B1698E39CF6B, 0x95DDAF2F749104E2, 0xEC2A9C80E0886427, 0xCE5C8FD8825B95EA, + 0xC4E0D9993AC60271, 0x4699C3A5173076F9, 0x3D1B151F50A29F42, 0x9ED505EA2BC75946, + 0x34665ACFDC7F4B98, 0x61B1FB53292342F7, 0xC721C0080E864130, 0x8693CD1696FD7B74, + 0x872731927136B14B, 0xD3446C8A63A1721B, 0x669A35E8A6680E4A, 0xCAB658F239509A16, + 0xA4E5DE4EF42E8AB9, 0x37A7435EE83F08D9, 0x134E6239E26C7F96, 0x82791A3C2DF67488, + 0x3F6EF00A8329163C, 0x8E5A7E42FDEB6591, 0x5CAAEE4C7981DDB5, 0x19F234785AF1E80D, + 0x255DDDE3ED98BD70, 0x50898A32A99CCCAC, 0x28CA4519DA4E6656, 0xAE59880F4CB31D22, + 0x0D9798FA37D6DB26, 0x32F968F0B4FFCD1A, 0xA00F09644F258545, 0xFA3AD5175E24DE72, + 0xF46C547C5DB24615, 0x713E80FBFF0F7E20, 0x7843CF2B73D2AAFA, 0xBD17EA36AEDF62B4, + 0xFD111BACD16F92CF, 0x4ABAA7DBC72D67E0, 0xB3416B5DAD49FAD3, 0xBCA316B24914A88B, + 0x15D150068AECF914, 0xE27C1DEBE31EFC40, 0x4FE48C759BEDA223, 0x7EDCFD141B522C78, + 0x4E5070F17C26681C, 0xE696CAC15815F3BC, 0x35D2A64B3BB481A7, 0x800CFF29FE7DFDF6, + 0x1ED9FAC3D5BAA4B0, 0x6C2663A91EF599D1, 0x03C1199134404341, 0xF7AD4DED69F20554, + 0xCD9D9649B61BD6AB, 0xC8C3BDE7EADB1368, 0xD131899FB02AFB65, 0x1D18E352E1FAE7F1, + 0xDA39235AEF7CA6C1, 0xA1BBF5E0A8EE4F7A, 0x91377805CF9A0B1E, 0x3138716180BF8E5B, + 0xD9F83ACBDB3CE580, 0x0275E515D38B897E, 0x472D3F21F0FBBCC6, 0x2D946EB7868EA395, + 0xBA3C248D21942E09, 0xE7223645BFDE3983, 0xFF64FEB902E41BB1, 0xC97741630D10D957, + 0xC3CB1722B58D4ECC, 0xA27AEC719CAE0C3B, 0x99FECB51A48C15FB, 0x1465AC826D27332B, + 0xE1BD047AD75EBF01, 0x79F733AF941960C5, 0x672EC96C41A3C475, 0xC27FEBA6524684F3, + 0x64EFD0FD75E38734, 0xED9E60040743AE18, 0xFB8E2993B9EF144D, 0x38453EB10C625A81, + 0x6978480742355C12, 0x48CF42CE14A6EE9E, 0x1CAC1FD606312DCE, 0x7B82D6BA4792E9BB, + 0x9D141C7B1F871A07, 0x5616B80DC11C4A2E, 0xB849C198F21FA777, 0x7CA91801C8D9A506, + 0xB1348E487EC273AD, 0x41B20D1E987B3A44, 0x7460AB55A3CFBBE3, 0x84E628034576F20A, + 0x1B87D16D897A6173, 0x0FE27DEFE45D5258, 0x83CDE6B8CA3DBEB7, 0x0C23647ED01D1119, + 0x7A362A3EA0592384, 0xB61F40F3F1893F10, 0x75D457D1440471DC, 0x4558DA34237035B8, + 0xDCA6116587FC2043, 0x8D9B67D3C9AB26D0, 0x2B0B5C88EE0E2517, 0x6FE77A382AB5DA90, + 0x269CC472D9D8FE31, 0x63C41E46FAA8CB89, 0xB7ABBC771642F52F, 0x7D1DE4852F126F39, + 0xA8C6BA3024339BA0, 0x600507D7CEE888C8, 0x8FEE82C61A20AFAE, 0x57A2448926D78011, + 0xFCA5E72836A458F0, 0x072BCEBB8F4B4CBD, 0x497BBE4AF36D24A1, 0x3CAFE99BB769557D, + 0x12FA9EBD05A7B5A9, 0xE8C04BAA5B836BDB, 0x4273148FAC3B7905, 0x908384812851C121, + 0xE557D3506C55B0FD, 0x72FF996ACB4F3D61, 0x3EDA0C8E64E2DC03, 0xF0868356E6B949E9, + 0x04EAD72ABB0B0FFC, 0x17A4B5135967706A, 0xE3C8E16F04D5367F, 0xF84F30028DAF570C, + 0x1846C8FCBD3A2232, 0x5B8120F7F6CA9108, 0xD46FA231ECEA3EA6, 0x334D947453340725, + 0x58403966C28AD249, 0xBED6F3A79A9F21F5, 0x68CCB483A5FE962D, 0xD085751B57E1315A, + 0xFED0023DE52FD18E, 0x4B0E5B5F20E6ADDF, 0x1A332DE96EB1AB4C, 0xA3CE10F57B65C604, + 0x108F7BA8D62C3CD7, 0xAB07A3A11073D8E1, 0x6B0DAD1291BED56C, 0xF2F366433532C097, + 0x2E557726B2CEE0D4, 0x0000000000000000, 0xCB02A476DE9B5029, 0xE4E32FD48B9E7AC2, + 0x734B65EE2C84F75E, 0x6E5386BCCD7E10AF, 0x01B4FC84E7CBCA3F, 0xCFE8735C65905FD5, + 0x3613BFDA0FF4C2E6, 0x113B872C31E7F6E8, 0x2FE18BA255052AEB, 0xE974B72EBC48A1E4, + 0x0ABC5641B89D979B, 0xB46AA5E62202B66E, 0x44EC26B0C4BBFF87, 0xA6903B5B27A503C7, + 0x7F680190FC99E647, 0x97A84A3AA71A8D9C, 0xDD12EDE16037EA7C, 0xC554251DDD0DC84E, + 0x88C54C7D956BE313, 0x4D91696048662B5D, 0xB08072CC9909B992, 0xB5DE5962C5C97C51, + 0x81B803AD19B637C9, 0xB2F597D94A8230EC, 0x0B08AAC55F565DA4, 0xF1327FD2017283D6, + 0xAD98919E78F35E63, 0x6AB9519676751F53, 0x24E921670A53774F, 0xB9FD3D1C15D46D48, + 0x92F66194FBDA485F, 0x5A35DC7311015B37, 0xDED3F4705477A93D, 0xC00A0EB381CD0D8D, + 0xBB88D809C65FE436, 0x16104997BEACBA55, 0x21B70AC95693B28C, 0x59F4C5E225411876, + 0xD5DB5EB50B21F499, 0x55D7A19CF55C096F, 0xA97246B4C3F8519F, 0x8552D487A2BD3835, + 0x54635D181297C350, 0x23C2EFDC85183BF2, 0x9F61F96ECC0C9379, 0x534893A39DDC8FED, + 0x5EDF0B59AA0A54CB, 0xAC2C6D1A9F38945C, 0xD7AEBBA0D8AA7DE7, 0x2ABFA00C09C5EF28, + 0xD84CC64F3CF72FBF, 0x2003F64DB15878B3, 0xA724C7DFC06EC9F8, 0x069F323F68808682, + 0xCC296ACD51D01C94, 0x055E2BAE5CC0C5C3, 0x6270E2C21D6301B6, 0x3B842720382219C0, + 0xD2F0900E846AB824, 0x52FC6F277A1745D2, 0xC6953C8CE94D8B0F, 0xE009F8FE3095753E, + 0x655B2C7992284D0B, 0x984A37D54347DFC4, 0xEAB5AEBF8808E2A5, 0x9A3FD2C090CC56BA, + 0x9CA0E0FFF84CD038, 0x4C2595E4AFADE162, 0xDF6708F4B3BC6302, 0xBF620F237D54EBCA, + 0x93429D101C118260, 0x097D4FD08CDDD4DA, 0x8C2F9B572E60ECEF, 0x708A7C7F18C4B41F, + 0x3A30DBA4DFE9D3FF, 0x4006F19A7FB0F07B, 0x5F6BF7DD4DC19EF4, 0x1F6D064732716E8F, + 0xF9FBCC866A649D33, 0x308C8DE567744464, 0x8971B0F972A0292C, 0xD61A47243F61B7D8, + 0xEFEB8511D4C82766, 0x961CB6BE40D147A3, 0xAAB35F25F7B812DE, 0x76154E407044329D, + 0x513D76B64E570693, 0xF3479AC7D2F90AA8, 0x9B8B2E4477079C85, 0x297EB99D3D85AC69 + }; + static const uint64_t T6[256] = + { + 0x7E37E62DFC7D40C3, 0x776F25A4EE939E5B, 0xE045C850DD8FB5AD, 0x86ED5BA711FF1952, + 0xE91D0BD9CF616B35, 0x37E0AB256E408FFB, 0x9607F6C031025A7A, 0x0B02F5E116D23C9D, + 0xF3D8486BFB50650C, 0x621CFF27C40875F5, 0x7D40CB71FA5FD34A, 0x6DAA6616DAA29062, + 0x9F5F354923EC84E2, 0xEC847C3DC507C3B3, 0x025A3668043CE205, 0xA8BF9E6C4DAC0B19, + 0xFA808BE2E9BEBB94, 0xB5B99C5277C74FA3, 0x78D9BC95F0397BCC, 0xE332E50CDBAD2624, + 0xC74FCE129332797E, 0x1729ECEB2EA709AB, 0xC2D6B9F69954D1F8, 0x5D898CBFBAB8551A, + 0x859A76FB17DD8ADB, 0x1BE85886362F7FB5, 0xF6413F8FF136CD8A, 0xD3110FA5BBB7E35C, + 0x0A2FEED514CC4D11, 0xE83010EDCD7F1AB9, 0xA1E75DE55F42D581, 0xEEDE4A55C13B21B6, + 0xF2F5535FF94E1480, 0x0CC1B46D1888761E, 0xBCE15FDB6529913B, 0x2D25E8975A7181C2, + 0x71817F1CE2D7A554, 0x2E52C5CB5C53124B, 0xF9F7A6BEEF9C281D, 0x9E722E7D21F2F56E, + 0xCE170D9B81DCA7E6, 0x0E9B82051CB4941B, 0x1E712F623C49D733, 0x21E45CFA42F9F7DC, + 0xCB8E7A7F8BBA0F60, 0x8E98831A010FB646, 0x474CCF0D8E895B23, 0xA99285584FB27A95, + 0x8CC2B57205335443, 0x42D5B8E984EFF3A5, 0x012D1B34021E718C, 0x57A6626AAE74180B, + 0xFF19FC06E3D81312, 0x35BA9D4D6A7C6DFE, 0xC9D44C178F86ED65, 0x506523E6A02E5288, + 0x03772D5C06229389, 0x8B01F4FE0B691EC0, 0xF8DABD8AED825991, 0x4C4E3AEC985B67BE, + 0xB10DF0827FBF96A9, 0x6A69279AD4F8DAE1, 0xE78689DCD3D5FF2E, 0x812E1A2B1FA553D1, + 0xFBAD90D6EBA0CA18, 0x1AC543B234310E39, 0x1604F7DF2CB97827, 0xA6241C6951189F02, + 0x753513CCEAAF7C5E, 0x64F2A59FC84C4EFA, 0x247D2B1E489F5F5A, 0xDB64D718AB474C48, + 0x79F4A7A1F2270A40, 0x1573DA832A9BEBAE, 0x3497867968621C72, 0x514838D2A2302304, + 0xF0AF6537FD72F685, 0x1D06023E3A6B44BA, 0x678588C3CE6EDD73, 0x66A893F7CC70ACFF, + 0xD4D24E29B5EDA9DF, 0x3856321470EA6A6C, 0x07C3418C0E5A4A83, 0x2BCBB22F5635BACD, + 0x04B46CD00878D90A, 0x06EE5AB80C443B0F, 0x3B211F4876C8F9E5, 0x0958C38912EEDE98, + 0xD14B39CDBF8B0159, 0x397B292072F41BE0, 0x87C0409313E168DE, 0xAD26E98847CAA39F, + 0x4E140C849C6785BB, 0xD5FF551DB7F3D853, 0xA0CA46D15D5CA40D, 0xCD6020C787FE346F, + 0x84B76DCF15C3FB57, 0xDEFDA0FCA121E4CE, 0x4B8D7B6096012D3D, 0x9AC642AD298A2C64, + 0x0875D8BD10F0AF14, 0xB357C6EA7B8374AC, 0x4D6321D89A451632, 0xEDA96709C719B23F, + 0xF76C24BBF328BC06, 0xC662D526912C08F2, 0x3CE25EC47892B366, 0xB978283F6F4F39BD, + 0xC08C8F9E9D6833FD, 0x4F3917B09E79F437, 0x593DE06FB2C08C10, 0xD6887841B1D14BDA, + 0x19B26EEE32139DB0, 0xB494876675D93E2F, 0x825937771987C058, 0x90E9AC783D466175, + 0xF1827E03FF6C8709, 0x945DC0A8353EB87F, 0x4516F9658AB5B926, 0x3F9573987EB020EF, + 0xB855330B6D514831, 0x2AE6A91B542BCB41, 0x6331E413C6160479, 0x408F8E8180D311A0, + 0xEFF35161C325503A, 0xD06622F9BD9570D5, 0x8876D9A20D4B8D49, 0xA5533135573A0C8B, + 0xE168D364DF91C421, 0xF41B09E7F50A2F8F, 0x12B09B0F24C1A12D, 0xDA49CC2CA9593DC4, + 0x1F5C34563E57A6BF, 0x54D14F36A8568B82, 0xAF7CDFE043F6419A, 0xEA6A2685C943F8BC, + 0xE5DCBFB4D7E91D2B, 0xB27ADDDE799D0520, 0x6B443CAED6E6AB6D, 0x7BAE91C9F61BE845, + 0x3EB868AC7CAE5163, 0x11C7B65322E332A4, 0xD23C1491B9A992D0, 0x8FB5982E0311C7CA, + 0x70AC6428E0C9D4D8, 0x895BC2960F55FCC5, 0x76423E90EC8DEFD7, 0x6FF0507EDE9E7267, + 0x3DCF45F07A8CC2EA, 0x4AA06054941F5CB1, 0x5810FB5BB0DEFD9C, 0x5EFEA1E3BC9AC693, + 0x6EDD4B4ADC8003EB, 0x741808F8E8B10DD2, 0x145EC1B728859A22, 0x28BC9F7350172944, + 0x270A06424EBDCCD3, 0x972AEDF4331C2BF6, 0x059977E40A66A886, 0x2550302A4A812ED6, + 0xDD8A8DA0A7037747, 0xC515F87A970E9B7B, 0x3023EAA9601AC578, 0xB7E3AA3A73FBADA6, + 0x0FB699311EAAE597, 0x0000000000000000, 0x310EF19D6204B4F4, 0x229371A644DB6455, + 0x0DECAF591A960792, 0x5CA4978BB8A62496, 0x1C2B190A38753536, 0x41A295B582CD602C, + 0x3279DCC16426277D, 0xC1A194AA9F764271, 0x139D803B26DFD0A1, 0xAE51C4D441E83016, + 0xD813FA44AD65DFC1, 0xAC0BF2BC45D4D213, 0x23BE6A9246C515D9, 0x49D74D08923DCF38, + 0x9D05032127D066E7, 0x2F7FDEFF5E4D63C7, 0xA47E2A0155247D07, 0x99B16FF12FA8BFED, + 0x4661D4398C972AAF, 0xDFD0BBC8A33F9542, 0xDCA79694A51D06CB, 0xB020EBB67DA1E725, + 0xBA0F0563696DAA34, 0xE4F1A480D5F76CA7, 0xC438E34E9510EAF7, 0x939E81243B64F2FC, + 0x8DEFAE46072D25CF, 0x2C08F3A3586FF04E, 0xD7A56375B3CF3A56, 0x20C947CE40E78650, + 0x43F8A3DD86F18229, 0x568B795EAC6A6987, 0x8003011F1DBB225D, 0xF53612D3F7145E03, + 0x189F75DA300DEC3C, 0x9570DB9C3720C9F3, 0xBB221E576B73DBB8, 0x72F65240E4F536DD, + 0x443BE25188ABC8AA, 0xE21FFE38D9B357A8, 0xFD43CA6EE7E4F117, 0xCAA3614B89A47EEC, + 0xFE34E732E1C6629E, 0x83742C431B99B1D4, 0xCF3A16AF83C2D66A, 0xAAE5A8044990E91C, + 0x26271D764CA3BD5F, 0x91C4B74C3F5810F9, 0x7C6DD045F841A2C6, 0x7F1AFD19FE63314F, + 0xC8F957238D989CE9, 0xA709075D5306EE8E, 0x55FC5402AA48FA0E, 0x48FA563C9023BEB4, + 0x65DFBEABCA523F76, 0x6C877D22D8BCE1EE, 0xCC4D3BF385E045E3, 0xBEBB69B36115733E, + 0x10EAAD6720FD4328, 0xB6CEB10E71E5DC2A, 0xBDCC44EF6737E0B7, 0x523F158EA412B08D, + 0x989C74C52DB6CE61, 0x9BEB59992B945DE8, 0x8A2CEFCA09776F4C, 0xA3BD6B8D5B7E3784, + 0xEB473DB1CB5D8930, 0xC3FBA2C29B4AA074, 0x9C28181525CE176B, 0x683311F2D0C438E4, + 0x5FD3BAD7BE84B71F, 0xFC6ED15AE5FA809B, 0x36CDB0116C5EFE77, 0x29918447520958C8, + 0xA29070B959604608, 0x53120EBAA60CC101, 0x3A0C047C74D68869, 0x691E0AC6D2DA4968, + 0x73DB4974E6EB4751, 0x7A838AFDF40599C9, 0x5A4ACD33B4E21F99, 0x6046C94FC03497F0, + 0xE6AB92E8D1CB8EA2, 0x3354C7F5663856F1, 0xD93EE170AF7BAE4D, 0x616BD27BC22AE67C, + 0x92B39A10397A8370, 0xABC8B3304B8E9890, 0xBF967287630B02B2, 0x5B67D607B6FC6E15 + }; + static uint64_t T7[256] = + { + 0xD031C397CE553FE6, 0x16BA5B01B006B525, 0xA89BADE6296E70C8, 0x6A1F525D77D3435B, + 0x6E103570573DFA0B, 0x660EFB2A17FC95AB, 0x76327A9E97634BF6, 0x4BAD9D6462458BF5, + 0xF1830CAEDBC3F748, 0xC5C8F542669131FF, 0x95044A1CDC48B0CB, 0x892962DF3CF8B866, + 0xB0B9E208E930C135, 0xA14FB3F0611A767C, 0x8D2605F21C160136, 0xD6B71922FECC549E, + 0x37089438A5907D8B, 0x0B5DA38E5803D49C, 0x5A5BCC9CEA6F3CBC, 0xEDAE246D3B73FFE5, + 0xD2B87E0FDE22EDCE, 0x5E54ABB1CA8185EC, 0x1DE7F88FE80561B9, 0xAD5E1A870135A08C, + 0x2F2ADBD665CECC76, 0x5780B5A782F58358, 0x3EDC8A2EEDE47B3F, 0xC9D95C3506BEE70F, + 0x83BE111D6C4E05EE, 0xA603B90959367410, 0x103C81B4809FDE5D, 0x2C69B6027D0C774A, + 0x399080D7D5C87953, 0x09D41E16487406B4, 0xCDD63B1826505E5F, 0xF99DC2F49B0298E8, + 0x9CD0540A943CB67F, 0xBCA84B7F891F17C5, 0x723D1DB3B78DF2A6, 0x78AA6E71E73B4F2E, + 0x1433E699A071670D, 0x84F21BE454620782, 0x98DF3327B4D20F2F, 0xF049DCE2D3769E5C, + 0xDB6C60199656EB7A, 0x648746B2078B4783, 0x32CD23598DCBADCF, 0x1EA4955BF0C7DA85, + 0xE9A143401B9D46B5, 0xFD92A5D9BBEC21B8, 0xC8138C790E0B8E1B, 0x2EE00B9A6D7BA562, + 0xF85712B893B7F1FC, 0xEB28FED80BEA949D, 0x564A65EB8A40EA4C, 0x6C9988E8474A2823, + 0x4535898B121D8F2D, 0xABD8C03231ACCBF4, 0xBA2E91CAB9867CBD, 0x7960BE3DEF8E263A, + 0x0C11A977602FD6F0, 0xCB50E1AD16C93527, 0xEAE22E94035FFD89, 0x2866D12F5DE2CE1A, + 0xFF1B1841AB9BF390, 0x9F9339DE8CFE0D43, 0x964727C8C48A0BF7, 0x524502C6AAAE531C, + 0x9B9C5EF3AC10B413, 0x4FA2FA4942AB32A5, 0x3F165A62E551122B, 0xC74148DA76E6E3D7, + 0x924840E5E464B2A7, 0xD372AE43D69784DA, 0x233B72A105E11A86, 0xA48A04914941A638, + 0xB4B68525C9DE7865, 0xDDEABAACA6CF8002, 0x0A9773C250B6BD88, 0xC284FFBB5EBD3393, + 0x8BA0DF472C8F6A4E, 0x2AEF6CB74D951C32, 0x427983722A318D41, 0x73F7CDFFBF389BB2, + 0x074C0AF9382C026C, 0x8A6A0F0B243A035A, 0x6FDAE53C5F88931F, 0xC68B98967E538AC3, + 0x44FF59C71AA8E639, 0xE2FCE0CE439E9229, 0xA20CDE2479D8CD40, 0x19E89FA2C8EBD8E9, + 0xF446BBCFF398270C, 0x43B3533E2284E455, 0xD82F0DCD8E945046, 0x51066F12B26CE820, + 0xE73957AF6BC5426D, 0x081ECE5A40C16FA0, 0x3B193D4FC5BFAB7B, 0x7FE66488DF174D42, + 0x0E9814EF705804D8, 0x8137AC857C39D7C6, 0xB1733244E185A821, 0x695C3F896F11F867, + 0xF6CF0657E3EFF524, 0x1AABF276D02963D5, 0x2DA3664E75B91E5E, 0x0289BD981077D228, + 0x90C1FD7DF413608F, 0x3C5537B6FD93A917, 0xAA12107E3919A2E0, 0x0686DAB530996B78, + 0xDAA6B0559EE3826E, 0xC34E2FF756085A87, 0x6D5358A44FFF4137, 0xFC587595B35948AC, + 0x7CA5095CC7D5F67E, 0xFB147F6C8B754AC0, 0xBFEB26AB91DDACF9, 0x6896EFC567A49173, + 0xCA9A31E11E7C5C33, 0xBBE44186B13315A9, 0x0DDB793B689ABFE4, 0x70B4A02BA7FA208E, + 0xE47A3A7B7307F951, 0x8CECD5BE14A36822, 0xEEED49B923B144D9, 0x17708B4DB8B3DC31, + 0x6088219F2765FED3, 0xB3FA8FDCF1F27A09, 0x910B2D31FCA6099B, 0x0F52C4A378ED6DCC, + 0x50CCBF5EBAD98134, 0x6BD582117F662A4F, 0x94CE9A50D4FDD9DF, 0x2B25BCFB45207526, + 0x67C42B661F49FCBF, 0x492420FC723259DD, 0x03436DD418C2BB3C, 0x1F6E4517F872B391, + 0xA08563BC69AF1F68, 0xD43EA4BAEEBB86B6, 0x01CAD04C08B56914, 0xAC94CACB0980C998, + 0x54C3D8739A373864, 0x26FEC5C02DBACAC2, 0xDEA9D778BE0D3B3E, 0x040F672D20EEB950, + 0xE5B0EA377BB29045, 0xF30AB136CBB42560, 0x62019C0737122CFB, 0xE86B930C13282FA1, + 0xCC1CEB542EE5374B, 0x538FD28AA21B3A08, 0x1B61223AD89C0AC1, 0x36C24474AD25149F, + 0x7A23D3E9F74C9D06, 0xBE21F6E79968C5ED, 0xCF5F868036278C77, 0xF705D61BEB5A9C30, + 0x4D2B47D152DCE08D, 0x5F9E7BFDC234ECF8, 0x247778583DCD18EA, 0x867BA67C4415D5AA, + 0x4CE1979D5A698999, 0x0000000000000000, 0xEC64F42133C696F1, 0xB57C5569C16B1171, + 0xC1C7926F467F88AF, 0x654D96FE0F3E2E97, 0x15F936D5A8C40E19, 0xB8A72C52A9F1AE95, + 0xA9517DAA21DB19DC, 0x58D27104FA18EE94, 0x5918A148F2AD8780, 0x5CDD1629DAF657C4, + 0x8274C15164FB6CFA, 0xD1FB13DBC6E056F2, 0x7D6FD910CF609F6A, 0xB63F38BDD9A9AA4D, + 0x3D9FE7FAF526C003, 0x74BBC706871499DE, 0xDF630734B6B8522A, 0x3AD3ED03CD0AC26F, + 0xFADEAF2083C023D4, 0xC00D42234ECAE1BB, 0x8538CBA85CD76E96, 0xC402250E6E2458EB, + 0x47BC3413026A5D05, 0xAFD7A71F114272A4, 0x978DF784CC3F62E3, 0xB96DFC1EA144C781, + 0x21B2CF391596C8AE, 0x318E4E8D950916F3, 0xCE9556CC3E92E563, 0x385A509BDD7D1047, + 0x358129A0B5E7AFA3, 0xE6F387E363702B79, 0xE0755D5653E94001, 0x7BE903A5FFF9F412, + 0x12B53C2C90E80C75, 0x3307F315857EC4DB, 0x8FAFB86A0C61D31E, 0xD9E5DD8186213952, + 0x77F8AAD29FD622E2, 0x25BDA814357871FE, 0x7571174A8FA1F0CA, 0x137FEC60985D6561, + 0x30449EC19DBC7FE7, 0xA540D4DD41F4CF2C, 0xDC206AE0AE7AE916, 0x5B911CD0E2DA55A8, + 0xB2305F90F947131D, 0x344BF9ECBD52C6B7, 0x5D17C665D2433ED0, 0x18224FEEC05EB1FD, + 0x9E59E992844B6457, 0x9A568EBFA4A5DD07, 0xA3C60E68716DA454, 0x7E2CB4C4D7A22456, + 0x87B176304CA0BCBE, 0x413AEEA632F3367D, 0x9915E36BBC67663B, 0x40F03EEA3A465F69, + 0x1C2D28C3E0B008AD, 0x4E682A054A1E5BB1, 0x05C5B761285BD044, 0xE1BF8D1A5B5C2915, + 0xF2C0617AC3014C74, 0xB7F5E8F1D11CC359, 0x63CB4C4B3FA745EF, 0x9D1A84469C89DF6B, + 0xE33630824B2BFB3D, 0xD5F474F6E60EEFA2, 0xF58C6B83FB2D4E18, 0x4676E45F0ADF3411, + 0x20781F751D23A1BA, 0xBD629B3381AA7ED1, 0xAE1D775319F71BB0, 0xFED1C80DA32E9A84, + 0x5509083F92825170, 0x29AC01635557A70E, 0xA7C9694551831D04, 0x8E65682604D4BA0A, + 0x11F651F8882AB749, 0xD77DC96EF6793D8A, 0xEF2799F52B042DCD, 0x48EEF0B07A8730C9, + 0x22F1A2ED0D547392, 0x6142F1D32FD097C7, 0x4A674D286AF0E2E1, 0x80FD7CC9748CBED2, + 0x717E7067AF4F499A, 0x938290A9ECD1DBB3, 0x88E3B293344DD172, 0x2734158C250FA3D6 }; - static const uint64_t A_[64] = - { - 0x8e20faa72ba0b470, 0x47107ddd9b505a38, 0xad08b0e0c3282d1c, 0xd8045870ef14980e, - 0x6c022c38f90a4c07, 0x3601161cf205268d, 0x1b8e0b0e798c13c8, 0x83478b07b2468764, - 0xa011d380818e8f40, 0x5086e740ce47c920, 0x2843fd2067adea10, 0x14aff010bdd87508, - 0x0ad97808d06cb404, 0x05e23c0468365a02, 0x8c711e02341b2d01, 0x46b60f011a83988e, - 0x90dab52a387ae76f, 0x486dd4151c3dfdb9, 0x24b86a840e90f0d2, 0x125c354207487869, - 0x092e94218d243cba, 0x8a174a9ec8121e5d, 0x4585254f64090fa0, 0xaccc9ca9328a8950, - 0x9d4df05d5f661451, 0xc0a878a0a1330aa6, 0x60543c50de970553, 0x302a1e286fc58ca7, - 0x18150f14b9ec46dd, 0x0c84890ad27623e0, 0x0642ca05693b9f70, 0x0321658cba93c138, - 0x86275df09ce8aaa8, 0x439da0784e745554, 0xafc0503c273aa42a, 0xd960281e9d1d5215, - 0xe230140fc0802984, 0x71180a8960409a42, 0xb60c05ca30204d21, 0x5b068c651810a89e, - 0x456c34887a3805b9, 0xac361a443d1c8cd2, 0x561b0d22900e4669, 0x2b838811480723ba, - 0x9bcf4486248d9f5d, 0xc3e9224312c8c1a0, 0xeffa11af0964ee50, 0xf97d86d98a327728, - 0xe4fa2054a80b329c, 0x727d102a548b194e, 0x39b008152acb8227, 0x9258048415eb419d, - 0x492c024284fbaec0, 0xaa16012142f35760, 0x550b8e9e21f7a530, 0xa48b474f9ef5dc18, - 0x70a6a56e2440598e, 0x3853dc371220a247, 0x1ca76e95091051ad, 0x0edd37c48a08a6d8, - 0x07e095624504536c, 0x8d70c431ac02a736, 0xc83862965601dd1b, 0x641c314b2b8ee083 - }; - - static const uint8_t C_[12][64] = + static const uint64_t C_[12][8] = { { - 0xb1,0x08,0x5b,0xda,0x1e,0xca,0xda,0xe9,0xeb,0xcb,0x2f,0x81,0xc0,0x65,0x7c,0x1f, - 0x2f,0x6a,0x76,0x43,0x2e,0x45,0xd0,0x16,0x71,0x4e,0xb8,0x8d,0x75,0x85,0xc4,0xfc, - 0x4b,0x7c,0xe0,0x91,0x92,0x67,0x69,0x01,0xa2,0x42,0x2a,0x08,0xa4,0x60,0xd3,0x15, - 0x05,0x76,0x74,0x36,0xcc,0x74,0x4d,0x23,0xdd,0x80,0x65,0x59,0xf2,0xa6,0x45,0x07 - }, + 0xe9daca1eda5b08b1, 0x1f7c65c0812fcbeb, 0x16d0452e43766a2f, 0xfcc485758db84e71, + 0x0169679291e07c4b, 0x15d360a4082a42a2, 0x234d74cc36747605, 0x0745a6f2596580dd + }, { - 0x6f,0xa3,0xb5,0x8a,0xa9,0x9d,0x2f,0x1a,0x4f,0xe3,0x9d,0x46,0x0f,0x70,0xb5,0xd7, - 0xf3,0xfe,0xea,0x72,0x0a,0x23,0x2b,0x98,0x61,0xd5,0x5e,0x0f,0x16,0xb5,0x01,0x31, - 0x9a,0xb5,0x17,0x6b,0x12,0xd6,0x99,0x58,0x5c,0xb5,0x61,0xc2,0xdb,0x0a,0xa7,0xca, - 0x55,0xdd,0xa2,0x1b,0xd7,0xcb,0xcd,0x56,0xe6,0x79,0x04,0x70,0x21,0xb1,0x9b,0xb7 - }, + 0x1a2f9da98ab5a36f, 0xd7b5700f469de34f, 0x982b230a72eafef3, 0x3101b5160f5ed561, + 0x5899d6126b17b59a, 0xcaa70adbc261b55c, 0x56cdcbd71ba2dd55, 0xb79bb121700479e6 + }, { - 0xf5,0x74,0xdc,0xac,0x2b,0xce,0x2f,0xc7,0x0a,0x39,0xfc,0x28,0x6a,0x3d,0x84,0x35, - 0x06,0xf1,0x5e,0x5f,0x52,0x9c,0x1f,0x8b,0xf2,0xea,0x75,0x14,0xb1,0x29,0x7b,0x7b, - 0xd3,0xe2,0x0f,0xe4,0x90,0x35,0x9e,0xb1,0xc1,0xc9,0x3a,0x37,0x60,0x62,0xdb,0x09, - 0xc2,0xb6,0xf4,0x43,0x86,0x7a,0xdb,0x31,0x99,0x1e,0x96,0xf5,0x0a,0xba,0x0a,0xb2 - }, + 0xc72fce2bacdc74f5, 0x35843d6a28fc390a, 0x8b1f9c525f5ef106, 0x7b7b29b11475eaf2, + 0xb19e3590e40fe2d3, 0x09db6260373ac9c1, 0x31db7a8643f4b6c2, 0xb20aba0af5961e99 + }, { - 0xef,0x1f,0xdf,0xb3,0xe8,0x15,0x66,0xd2,0xf9,0x48,0xe1,0xa0,0x5d,0x71,0xe4,0xdd, - 0x48,0x8e,0x85,0x7e,0x33,0x5c,0x3c,0x7d,0x9d,0x72,0x1c,0xad,0x68,0x5e,0x35,0x3f, - 0xa9,0xd7,0x2c,0x82,0xed,0x03,0xd6,0x75,0xd8,0xb7,0x13,0x33,0x93,0x52,0x03,0xbe, - 0x34,0x53,0xea,0xa1,0x93,0xe8,0x37,0xf1,0x22,0x0c,0xbe,0xbc,0x84,0xe3,0xd1,0x2e - }, + 0xd26615e8b3df1fef, 0xdde4715da0e148f9, 0x7d3c5c337e858e48, 0x3f355e68ad1c729d, + 0x75d603ed822cd7a9, 0xbe0352933313b7d8, 0xf137e893a1ea5334, 0x2ed1e384bcbe0c22 + }, { - 0x4b,0xea,0x6b,0xac,0xad,0x47,0x47,0x99,0x9a,0x3f,0x41,0x0c,0x6c,0xa9,0x23,0x63, - 0x7f,0x15,0x1c,0x1f,0x16,0x86,0x10,0x4a,0x35,0x9e,0x35,0xd7,0x80,0x0f,0xff,0xbd, - 0xbf,0xcd,0x17,0x47,0x25,0x3a,0xf5,0xa3,0xdf,0xff,0x00,0xb7,0x23,0x27,0x1a,0x16, - 0x7a,0x56,0xa2,0x7e,0xa9,0xea,0x63,0xf5,0x60,0x17,0x58,0xfd,0x7c,0x6c,0xfe,0x57 - }, + 0x994747adac6bea4b, 0x6323a96c0c413f9a, 0x4a1086161f1c157f, 0xbdff0f80d7359e35, + 0xa3f53a254717cdbf, 0x161a2723b700ffdf, 0xf563eaa97ea2567a, 0x57fe6c7cfd581760 + }, { - 0xae,0x4f,0xae,0xae,0x1d,0x3a,0xd3,0xd9,0x6f,0xa4,0xc3,0x3b,0x7a,0x30,0x39,0xc0, - 0x2d,0x66,0xc4,0xf9,0x51,0x42,0xa4,0x6c,0x18,0x7f,0x9a,0xb4,0x9a,0xf0,0x8e,0xc6, - 0xcf,0xfa,0xa6,0xb7,0x1c,0x9a,0xb7,0xb4,0x0a,0xf2,0x1f,0x66,0xc2,0xbe,0xc6,0xb6, - 0xbf,0x71,0xc5,0x72,0x36,0x90,0x4f,0x35,0xfa,0x68,0x40,0x7a,0x46,0x64,0x7d,0x6e - }, + 0xd9d33a1daeae4fae, 0xc039307a3bc3a46f, 0x6ca44251f9c4662d, 0xc68ef09ab49a7f18, + 0xb4b79a1cb7a6facf, 0xb6c6bec2661ff20a, 0x354f903672c571bf, 0x6e7d64467a4068fa + }, { - 0xf4,0xc7,0x0e,0x16,0xee,0xaa,0xc5,0xec,0x51,0xac,0x86,0xfe,0xbf,0x24,0x09,0x54, - 0x39,0x9e,0xc6,0xc7,0xe6,0xbf,0x87,0xc9,0xd3,0x47,0x3e,0x33,0x19,0x7a,0x93,0xc9, - 0x09,0x92,0xab,0xc5,0x2d,0x82,0x2c,0x37,0x06,0x47,0x69,0x83,0x28,0x4a,0x05,0x04, - 0x35,0x17,0x45,0x4c,0xa2,0x3c,0x4a,0xf3,0x88,0x86,0x56,0x4d,0x3a,0x14,0xd4,0x93 - }, + 0xecc5aaee160ec7f4, 0x540924bffe86ac51, 0xc987bfe6c7c69e39, 0xc9937a19333e47d3, + 0x372c822dc5ab9209, 0x04054a2883694706, 0xf34a3ca24c451735, 0x93d4143a4d568688 + }, { - 0x9b,0x1f,0x5b,0x42,0x4d,0x93,0xc9,0xa7,0x03,0xe7,0xaa,0x02,0x0c,0x6e,0x41,0x41, - 0x4e,0xb7,0xf8,0x71,0x9c,0x36,0xde,0x1e,0x89,0xb4,0x44,0x3b,0x4d,0xdb,0xc4,0x9a, - 0xf4,0x89,0x2b,0xcb,0x92,0x9b,0x06,0x90,0x69,0xd1,0x8d,0x2b,0xd1,0xa5,0xc4,0x2f, - 0x36,0xac,0xc2,0x35,0x59,0x51,0xa8,0xd9,0xa4,0x7f,0x0d,0xd4,0xbf,0x02,0xe7,0x1e - }, + 0xa7c9934d425b1f9b, 0x41416e0c02aae703, 0x1ede369c71f8b74e, 0x9ac4db4d3b44b489, + 0x90069b92cb2b89f4, 0x2fc4a5d12b8dd169, 0xd9a8515935c2ac36, 0x1ee702bfd40d7fa4 + }, { - 0x37,0x8f,0x5a,0x54,0x16,0x31,0x22,0x9b,0x94,0x4c,0x9a,0xd8,0xec,0x16,0x5f,0xde, - 0x3a,0x7d,0x3a,0x1b,0x25,0x89,0x42,0x24,0x3c,0xd9,0x55,0xb7,0xe0,0x0d,0x09,0x84, - 0x80,0x0a,0x44,0x0b,0xdb,0xb2,0xce,0xb1,0x7b,0x2b,0x8a,0x9a,0xa6,0x07,0x9c,0x54, - 0x0e,0x38,0xdc,0x92,0xcb,0x1f,0x2a,0x60,0x72,0x61,0x44,0x51,0x83,0x23,0x5a,0xdb - }, + 0x9b223116545a8f37, 0xde5f16ecd89a4c94, 0x244289251b3a7d3a, 0x84090de0b755d93c, + 0xb1ceb2db0b440a80, 0x549c07a69a8a2b7b, 0x602a1fcb92dc380e, 0xdb5a238351446172 + }, { - 0xab,0xbe,0xde,0xa6,0x80,0x05,0x6f,0x52,0x38,0x2a,0xe5,0x48,0xb2,0xe4,0xf3,0xf3, - 0x89,0x41,0xe7,0x1c,0xff,0x8a,0x78,0xdb,0x1f,0xff,0xe1,0x8a,0x1b,0x33,0x61,0x03, - 0x9f,0xe7,0x67,0x02,0xaf,0x69,0x33,0x4b,0x7a,0x1e,0x6c,0x30,0x3b,0x76,0x52,0xf4, - 0x36,0x98,0xfa,0xd1,0x15,0x3b,0xb6,0xc3,0x74,0xb4,0xc7,0xfb,0x98,0x45,0x9c,0xed - }, + 0x526f0580a6debeab, 0xf3f3e4b248e52a38, 0xdb788aff1ce74189, 0x0361331b8ae1ff1f, + 0x4b3369af0267e79f, 0xf452763b306c1e7a, 0xc3b63b15d1fa9836, 0xed9c4598fbc7b474 + }, { - 0x7b,0xcd,0x9e,0xd0,0xef,0xc8,0x89,0xfb,0x30,0x02,0xc6,0xcd,0x63,0x5a,0xfe,0x94, - 0xd8,0xfa,0x6b,0xbb,0xeb,0xab,0x07,0x61,0x20,0x01,0x80,0x21,0x14,0x84,0x66,0x79, - 0x8a,0x1d,0x71,0xef,0xea,0x48,0xb9,0xca,0xef,0xba,0xcd,0x1d,0x7d,0x47,0x6e,0x98, - 0xde,0xa2,0x59,0x4a,0xc0,0x6f,0xd8,0x5d,0x6b,0xca,0xa4,0xcd,0x81,0xf3,0x2d,0x1b - }, + 0xfb89c8efd09ecd7b, 0x94fe5a63cdc60230, 0x6107abebbb6bfad8, 0x7966841421800120, + 0xcab948eaef711d8a, 0x986e477d1dcdbaef, 0x5dd86fc04a59a2de, 0x1b2df381cda4ca6b + }, { - 0x37,0x8e,0xe7,0x67,0xf1,0x16,0x31,0xba,0xd2,0x13,0x80,0xb0,0x04,0x49,0xb1,0x7a, - 0xcd,0xa4,0x3c,0x32,0xbc,0xdf,0x1d,0x77,0xf8,0x20,0x12,0xd4,0x30,0x21,0x9f,0x9b, - 0x5d,0x80,0xef,0x9d,0x18,0x91,0xcc,0x86,0xe7,0x1d,0xa4,0xaa,0x88,0xe1,0x28,0x52, - 0xfa,0xf4,0x17,0xd5,0xd9,0xb2,0x1b,0x99,0x48,0xbc,0x92,0x4a,0xf1,0x1b,0xd7,0x20 + 0xba3116f167e78e37, 0x7ab14904b08013d2, 0x771ddfbc323ca4cd, 0x9b9f2130d41220f8, + 0x86cc91189def805d, 0x5228e188aaa41de7, 0x991bb2d9d517f4fa, 0x20d71bf14a92bc48 } }; + union GOST3411Block // 8 bytes aligned { @@ -307,15 +781,15 @@ namespace crypto ret.ll[i] = ll[i]^other.ll[i]; return ret; } - - GOST3411Block operator^(const uint8_t * other) const + + GOST3411Block operator^(const uint64_t * other) const { GOST3411Block ret; - for (int i = 0; i < 64; i++) - ret.buf[i] = buf[i]^other[i]; + for (int i = 0; i < 8; i++) + ret.ll[i] = ll[i]^other[i]; return ret; } - + GOST3411Block operator+(const GOST3411Block& other) const { GOST3411Block ret; @@ -340,26 +814,24 @@ namespace crypto } } - void SPL () + void F () { - uint8_t p[64]; - memcpy (p, buf, 64); // we need to copy it for P's transposition - for (int i = 0; i < 8; i++) + uint64_t res[8]; + for (int b=0; b<8; b++) { - uint64_t c = 0; - for (int j = 0; j < 8; j++) - { - uint8_t bit = 0x80; - uint8_t byte = sbox_[p[j*8+i]]; // S - sbox_, P - transpose (i,j) - for (int k = 0; k < 8; k++) - { - if (byte & bit) c ^= A_[j*8+k]; - bit >>= 1; - } - } - ll[i] = htobe64 (c); - } - } + uint64_t r; + r = T0[buf[b+56]]; + r ^= T1[buf[b+48]]; + r ^= T2[buf[b+40]]; + r ^= T3[buf[b+32]]; + r ^= T4[buf[b+24]]; + r ^= T5[buf[b+16]]; + r ^= T6[buf[b+8]]; + r ^= T7[buf[b]]; + res[b] = r; + } + memcpy (buf, res, 64); + } GOST3411Block E (const GOST3411Block& m) { @@ -367,9 +839,9 @@ namespace crypto GOST3411Block res = k^m; for (int i = 0; i < 12; i++) { - res.SPL (); + res.F (); k = k^C_[i]; - k.SPL (); + k.F (); res = k^res; } return res; @@ -379,7 +851,7 @@ namespace crypto static GOST3411Block gN (const GOST3411Block& N, const GOST3411Block& h, const GOST3411Block& m) { GOST3411Block res = N ^ h; - res.SPL (); + res.F (); res = res.E (m); res = res^h; res = res^m; diff --git a/libi2pd/HTTP.cpp b/libi2pd/HTTP.cpp index cc6e724b..c81b1a07 100644 --- a/libi2pd/HTTP.cpp +++ b/libi2pd/HTTP.cpp @@ -29,7 +29,7 @@ namespace http { inline bool is_http_method(const std::string & str) { return std::find(HTTP_METHODS.begin(), HTTP_METHODS.end(), str) != std::end(HTTP_METHODS); } - + void strsplit(const std::string & line, std::vector &tokens, char delim, std::size_t limit = 0) { std::size_t count = 0; std::stringstream ss(line); @@ -195,6 +195,11 @@ namespace http { return out; } + bool URL::is_i2p() const + { + return host.rfind(".i2p") == ( host.size() - 4 ); + } + void HTTPMsg::add_header(const char *name, std::string & value, bool replace) { add_header(name, value.c_str(), replace); } diff --git a/libi2pd/HTTP.h b/libi2pd/HTTP.h index 198362f5..272f2f44 100644 --- a/libi2pd/HTTP.h +++ b/libi2pd/HTTP.h @@ -56,6 +56,11 @@ namespace http * @note Returns relative url if schema if empty, absolute url otherwise */ std::string to_string (); + + /** + * @brief return true if the host is inside i2p + */ + bool is_i2p() const; }; struct HTTPMsg @@ -89,7 +94,7 @@ namespace http /** @brief Serialize HTTP request to string */ std::string to_string(); - void write(std::ostream & o); + void write(std::ostream & o); void AddHeader (const std::string& name, const std::string& value); void UpdateHeader (const std::string& name, const std::string& value); @@ -131,7 +136,7 @@ namespace http std::string to_string(); void write(std::ostream & o); - + /** @brief Checks that response declared as chunked data */ bool is_chunked() const ; diff --git a/libi2pd/Log.cpp b/libi2pd/Log.cpp index 7cd4205e..8ae417c2 100644 --- a/libi2pd/Log.cpp +++ b/libi2pd/Log.cpp @@ -58,7 +58,7 @@ namespace log { Log::Log(): m_Destination(eLogStdout), m_MinLevel(eLogInfo), - m_LogStream (nullptr), m_Logfile(""), m_HasColors(true), + m_LogStream (nullptr), m_Logfile(""), m_HasColors(true), m_TimeFormat("%H:%M:%S"), m_IsRunning (false), m_Thread (nullptr) { } @@ -118,7 +118,7 @@ namespace log { const char * Log::TimeAsString(std::time_t t) { if (t != m_LastTimestamp) { - strftime(m_LastDateTime, sizeof(m_LastDateTime), "%H:%M:%S", localtime(&t)); + strftime(m_LastDateTime, sizeof(m_LastDateTime), m_TimeFormat.c_str(), localtime(&t)); m_LastTimestamp = t; } return m_LastDateTime; diff --git a/libi2pd/Log.h b/libi2pd/Log.h index 1d02a845..bec741a8 100644 --- a/libi2pd/Log.h +++ b/libi2pd/Log.h @@ -58,6 +58,7 @@ namespace log { char m_LastDateTime[64]; i2p::util::Queue > m_Queue; bool m_HasColors; + std::string m_TimeFormat; volatile bool m_IsRunning; std::thread * m_Thread; @@ -107,6 +108,12 @@ namespace log { */ void SendTo (std::shared_ptr os); + /** + * @brief Sets format for timestamps in log + * @param format String with timestamp format + */ + void SetTimeFormat (std::string format) { m_TimeFormat = format; }; + #ifndef _WIN32 /** * @brief Sets log destination to syslog diff --git a/libi2pd/NTCPSession.cpp b/libi2pd/NTCPSession.cpp index a6329f04..27f30600 100644 --- a/libi2pd/NTCPSession.cpp +++ b/libi2pd/NTCPSession.cpp @@ -791,7 +791,8 @@ namespace transport NTCPServer::NTCPServer (): m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), m_TerminationTimer (m_Service), m_NTCPAcceptor (nullptr), m_NTCPV6Acceptor (nullptr), - m_ProxyType(eNoProxy), m_Resolver(m_Service), m_ProxyEndpoint(nullptr) + m_ProxyType(eNoProxy), m_Resolver(m_Service), m_ProxyEndpoint(nullptr), + m_SoftLimit(0), m_HardLimit(0) { } @@ -965,6 +966,13 @@ namespace transport auto ep = conn->GetSocket ().remote_endpoint(ec); if (!ec) { + if(ShouldLimit()) + { + // hit limit, close premature + LogPrint(eLogWarning, "NTCP: limiting with backoff session from ", ep); + conn->Terminate(); + return; + } LogPrint (eLogDebug, "NTCP: Connected from ", ep); if (conn) { @@ -993,6 +1001,14 @@ namespace transport auto ep = conn->GetSocket ().remote_endpoint(ec); if (!ec) { + if(ShouldLimit()) + { + // hit limit, close premature + LogPrint(eLogWarning, "NTCP: limiting with backoff on session from ", ep); + conn->Terminate(); + return; + } + LogPrint (eLogDebug, "NTCP: Connected from ", ep); if (conn) { diff --git a/libi2pd/NTCPSession.h b/libi2pd/NTCPSession.h index a45f06f7..b64f63aa 100644 --- a/libi2pd/NTCPSession.h +++ b/libi2pd/NTCPSession.h @@ -167,8 +167,19 @@ namespace transport boost::asio::io_service& GetService () { return m_Service; }; + void SetSessionLimits(uint16_t softLimit, uint16_t hardLimit) { m_SoftLimit = softLimit; m_HardLimit = hardLimit; } + bool ShouldLimit() const { return ShouldHardLimit() || ShouldSoftLimit(); } private: + /** @brief return true for hard limit */ + bool ShouldHardLimit() const { return m_HardLimit && m_NTCPSessions.size() >= m_HardLimit; } + + /** @brief return true for probabalistic soft backoff */ + bool ShouldSoftLimit() const + { + auto sessions = m_NTCPSessions.size(); + return sessions && m_SoftLimit && m_SoftLimit < sessions && ( rand() % sessions ) <= m_SoftLimit; + } void Run (); void HandleAccept (std::shared_ptr conn, const boost::system::error_code& error); void HandleAcceptV6 (std::shared_ptr conn, const boost::system::error_code& error); @@ -198,6 +209,8 @@ namespace transport uint16_t m_ProxyPort; boost::asio::ip::tcp::resolver m_Resolver; boost::asio::ip::tcp::endpoint * m_ProxyEndpoint; + + uint16_t m_SoftLimit, m_HardLimit; public: // for HTTP/I2PControl diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 7be25b04..ff19d27f 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -16,8 +16,8 @@ namespace i2p RouterContext context; RouterContext::RouterContext (): - m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false), - m_StartupTime (0), m_ShareRatio (100), m_Status (eRouterStatusOK), + m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false), + m_StartupTime (0), m_ShareRatio (100), m_Status (eRouterStatusOK), m_Error (eRouterErrorNone), m_NetID (I2PD_NET_ID) { } @@ -33,11 +33,11 @@ namespace i2p void RouterContext::CreateNewRouter () { -#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER) +#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER) m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519); #else m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); -#endif +#endif SaveKeys (); NewRouterInfo (); } @@ -75,7 +75,7 @@ namespace i2p std::string host = "::"; if (!i2p::config::IsDefault("host") && !ipv4) // override if v6 only i2p::config::GetOption("host", host); - else if (!ifname.empty()) + else if (!ifname.empty()) host = i2p::util::net::GetInterfaceAddress(ifname, true).to_string(); // v6 if(ifname6.size()) @@ -84,10 +84,10 @@ namespace i2p routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); routerInfo.AddNTCPAddress (host.c_str(), port); } - - routerInfo.SetCaps (i2p::data::RouterInfo::eReachable | + + routerInfo.SetCaps (i2p::data::RouterInfo::eReachable | i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC - routerInfo.SetProperty ("netId", std::to_string (m_NetID)); + routerInfo.SetProperty ("netId", std::to_string (m_NetID)); routerInfo.SetProperty ("router.version", I2P_VERSION); routerInfo.CreateBuffer (m_Keys); m_RouterInfo.SetRouterIdentity (GetIdentity ()); @@ -99,39 +99,39 @@ namespace i2p m_RouterInfo.CreateBuffer (m_Keys); m_RouterInfo.SaveToFile (i2p::fs::DataDirPath (ROUTER_INFO)); m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch (); - } + } - void RouterContext::SetStatus (RouterStatus status) - { + void RouterContext::SetStatus (RouterStatus status) + { if (status != m_Status) - { + { m_Status = status; m_Error = eRouterErrorNone; switch (m_Status) - { + { case eRouterStatusOK: SetReachable (); break; case eRouterStatusFirewalled: SetUnreachable (); - break; + break; default: ; } - } + } } - + void RouterContext::UpdatePort (int port) { bool updated = false; for (auto& address : m_RouterInfo.GetAddresses ()) { if (address->port != port) - { + { address->port = port; updated = true; - } - } + } + } if (updated) UpdateRouterInfo (); } @@ -142,11 +142,11 @@ namespace i2p for (auto& address : m_RouterInfo.GetAddresses ()) { if (address->host != host && address->IsCompatible (host)) - { + { address->host = host; updated = true; - } - } + } + } auto ts = i2p::util::GetSecondsSinceEpoch (); if (updated || ts > m_LastUpdateTime + ROUTER_INFO_UPDATE_INTERVAL) UpdateRouterInfo (); @@ -156,16 +156,16 @@ namespace i2p { bool ret = m_RouterInfo.AddIntroducer (introducer); if (ret) - UpdateRouterInfo (); + UpdateRouterInfo (); return ret; - } + } void RouterContext::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e) { if (m_RouterInfo.RemoveIntroducer (e)) UpdateRouterInfo (); - } - + } + void RouterContext::SetFloodfill (bool floodfill) { m_IsFloodfill = floodfill; @@ -195,19 +195,20 @@ namespace i2p { m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_FAMILY, family); m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_FAMILY_SIG, signature); - } + } else { m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_FAMILY); m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_FAMILY_SIG); - } - } + } + } - void RouterContext::SetBandwidth (char L) { - uint16_t limit = 0; + void RouterContext::SetBandwidth (char L) + { + uint32_t limit = 0; enum { low, high, extra, unlim } type = high; /* detect parameters */ - switch (L) + switch (L) { case i2p::data::CAPS_FLAG_LOW_BANDWIDTH1 : limit = 12; type = low; break; case i2p::data::CAPS_FLAG_LOW_BANDWIDTH2 : limit = 48; type = low; break; @@ -215,7 +216,7 @@ namespace i2p case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH2 : limit = 128; type = high; break; case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH3 : limit = 256; type = high; break; case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH1 : limit = 2048; type = extra; break; - case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH2 : limit = 9999; type = unlim; break; + case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH2 : limit = 1000000; type = unlim; break; // 1Gbyte/s default: limit = 48; type = low; } @@ -223,7 +224,7 @@ namespace i2p auto caps = m_RouterInfo.GetCaps (); caps &= ~i2p::data::RouterInfo::eHighBandwidth; caps &= ~i2p::data::RouterInfo::eExtraBandwidth; - switch (type) + switch (type) { case low : /* not set */; break; case extra : caps |= i2p::data::RouterInfo::eExtraBandwidth; break; // 'P' @@ -235,7 +236,7 @@ namespace i2p m_BandwidthLimit = limit; } - void RouterContext::SetBandwidth (int limit) + void RouterContext::SetBandwidth (int limit) { if (limit > 2000) { SetBandwidth('X'); } else if (limit > 256) { SetBandwidth('P'); } @@ -256,8 +257,8 @@ namespace i2p bool RouterContext::IsUnreachable () const { return m_RouterInfo.GetCaps () & i2p::data::RouterInfo::eUnreachable; - } - + } + void RouterContext::SetUnreachable () { // set caps @@ -266,7 +267,7 @@ namespace i2p caps |= i2p::data::RouterInfo::eUnreachable; caps &= ~i2p::data::RouterInfo::eFloodfill; // can't be floodfill caps &= ~i2p::data::RouterInfo::eSSUIntroducer; // can't be introducer - m_RouterInfo.SetCaps (caps); + m_RouterInfo.SetCaps (caps); // remove NTCP address auto& addresses = m_RouterInfo.GetAddresses (); for (auto it = addresses.begin (); it != addresses.end (); ++it) @@ -277,12 +278,12 @@ namespace i2p addresses.erase (it); break; } - } + } // delete previous introducers - for (auto& addr : addresses) + for (auto& addr : addresses) if (addr->ssu) addr->ssu->introducers.clear (); - + // update UpdateRouterInfo (); } @@ -297,7 +298,7 @@ namespace i2p if (m_IsFloodfill) caps |= i2p::data::RouterInfo::eFloodfill; m_RouterInfo.SetCaps (caps); - + // insert NTCP back auto& addresses = m_RouterInfo.GetAddresses (); for (const auto& addr : addresses) @@ -309,16 +310,16 @@ namespace i2p m_RouterInfo.AddNTCPAddress (addr->host.to_string ().c_str (), addr->port); break; } - } + } // delete previous introducers for (auto& addr : addresses) if (addr->ssu) addr->ssu->introducers.clear (); - + // update UpdateRouterInfo (); - } - + } + void RouterContext::SetSupportsV6 (bool supportsV6) { if (supportsV6) @@ -327,7 +328,7 @@ namespace i2p m_RouterInfo.DisableV6 (); UpdateRouterInfo (); } - + void RouterContext::SetSupportsV4 (bool supportsV4) { if (supportsV4) @@ -336,11 +337,11 @@ namespace i2p m_RouterInfo.DisableV4 (); UpdateRouterInfo (); } - + void RouterContext::UpdateNTCPV6Address (const boost::asio::ip::address& host) { - bool updated = false, found = false; + bool updated = false, found = false; int port = 0; auto& addresses = m_RouterInfo.GetAddresses (); for (auto& addr: addresses) @@ -352,24 +353,24 @@ namespace i2p addr->host = host; updated = true; } - found = true; - } + found = true; + } else - port = addr->port; - } + port = addr->port; + } if (!found) { // create new address m_RouterInfo.AddNTCPAddress (host.to_string ().c_str (), port); auto mtu = i2p::util::net::GetMTU (host); if (mtu) - { + { LogPrint (eLogDebug, "Router: Our v6 MTU=", mtu); if (mtu > 1472) { // TODO: magic constant mtu = 1472; LogPrint(eLogWarning, "Router: MTU dropped to upper limit of 1472 bytes"); } - } + } m_RouterInfo.AddSSUAddress (host.to_string ().c_str (), port, GetIdentHash (), mtu ? mtu : 1472); // TODO updated = true; } @@ -384,21 +385,21 @@ namespace i2p // update routers and leasesets m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_LEASESETS, std::to_string(i2p::data::netdb.GetNumLeaseSets ())); m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_ROUTERS, std::to_string(i2p::data::netdb.GetNumRouters ())); - UpdateRouterInfo (); + UpdateRouterInfo (); } } - + bool RouterContext::Load () { std::ifstream fk (i2p::fs::DataDirPath (ROUTER_KEYS), std::ifstream::in | std::ifstream::binary); if (!fk.is_open ()) return false; fk.seekg (0, std::ios::end); size_t len = fk.tellg(); - fk.seekg (0, std::ios::beg); + fk.seekg (0, std::ios::beg); if (len == sizeof (i2p::data::Keys)) // old keys file format { - i2p::data::Keys keys; + i2p::data::Keys keys; fk.read ((char *)&keys, sizeof (keys)); m_Keys = keys; } @@ -411,7 +412,7 @@ namespace i2p } m_RouterInfo.SetRouterIdentity (GetIdentity ()); - i2p::data::RouterInfo routerInfo(i2p::fs::DataDirPath (ROUTER_INFO)); + i2p::data::RouterInfo routerInfo(i2p::fs::DataDirPath (ROUTER_INFO)); if (!routerInfo.IsUnreachable ()) // router.info looks good { m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ()); @@ -426,16 +427,16 @@ namespace i2p { LogPrint (eLogError, ROUTER_INFO, " is malformed. Creating new"); NewRouterInfo (); - } + } if (IsUnreachable ()) SetReachable (); // we assume reachable until we discover firewall through peer tests - + return true; } void RouterContext::SaveKeys () - { + { // save in the same format as .dat files std::ofstream fk (i2p::fs::DataDirPath (ROUTER_KEYS), std::ofstream::binary | std::ofstream::out); size_t len = m_Keys.GetFullLen (); @@ -447,9 +448,9 @@ namespace i2p std::shared_ptr RouterContext::GetTunnelPool () const { - return i2p::tunnel::tunnels.GetExploratoryPool (); - } - + return i2p::tunnel::tunnels.GetExploratoryPool (); + } + void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from) { i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from)); @@ -459,22 +460,22 @@ namespace i2p { std::unique_lock l(m_GarlicMutex); i2p::garlic::GarlicDestination::ProcessGarlicMessage (msg); - } - + } + void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr msg) { std::unique_lock l(m_GarlicMutex); i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg); - } + } void RouterContext::CleanupDestination () { std::unique_lock l(m_GarlicMutex); i2p::garlic::GarlicDestination::CleanupExpiredTags (); } - + uint32_t RouterContext::GetUptime () const { return i2p::util::GetSecondsSinceEpoch () - m_StartupTime; - } + } } diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index be2a5904..3719e68a 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -166,7 +166,6 @@ namespace data for (int i = 0; i < numAddresses; i++) { uint8_t supportedTransports = 0; - bool isValidAddress = true; auto address = std::make_shared
(); s.read ((char *)&address->cost, sizeof (address->cost)); s.read ((char *)&address->date, sizeof (address->date)); @@ -269,7 +268,8 @@ namespace data } if (!s) return; } - if (isValidAddress) + if (introducers) supportedTransports |= eSSUV4; // in case if host is not presented + if (supportedTransports) { addresses->push_back(address); m_SupportedTransports |= supportedTransports; diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index 12ee6c2c..c5c2419b 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -353,6 +353,7 @@ namespace crypto BN_mod_mul (x, x, I, q, ctx); if (BN_is_odd (x)) BN_sub (x, q, x); + BN_CTX_end (ctx); return x; } @@ -370,7 +371,7 @@ namespace crypto buf1[0] &= 0x7f; // clear highest bit BIGNUM * y = BN_new (); BN_bin2bn (buf1, EDDSA25519_PUBLIC_KEY_LENGTH, y); - auto x = RecoverX (y, ctx); + BIGNUM * x = RecoverX (y, ctx); if (BN_is_bit_set (x, 0) != isHighestBitSet) BN_sub (x, q, x); // x = q - x BIGNUM * z = BN_new (), * t = BN_new (); diff --git a/libi2pd/Signature.h b/libi2pd/Signature.h index b85ef4cf..531fdfdf 100644 --- a/libi2pd/Signature.h +++ b/libi2pd/Signature.h @@ -363,31 +363,43 @@ namespace crypto // EdDSA struct EDDSAPoint { - BIGNUM * x, * y; - BIGNUM * z, * t; // projective coordinates - EDDSAPoint (): x(nullptr), y(nullptr), z(nullptr), t(nullptr) {}; - EDDSAPoint (const EDDSAPoint& other): x(nullptr), y(nullptr), z(nullptr), t(nullptr) - { *this = other; }; - EDDSAPoint (EDDSAPoint&& other): x(nullptr), y(nullptr), z(nullptr), t(nullptr) - { *this = std::move (other); }; - EDDSAPoint (BIGNUM * x1, BIGNUM * y1, BIGNUM * z1 = nullptr, BIGNUM * t1 = nullptr): x(x1), y(y1), z(z1), t(t1) {}; - ~EDDSAPoint () { BN_free (x); BN_free (y); BN_free(z); BN_free(t); }; + BIGNUM * x {nullptr}; + BIGNUM * y {nullptr}; + BIGNUM * z {nullptr}; + BIGNUM * t {nullptr}; // projective coordinates + + EDDSAPoint () {} + EDDSAPoint (const EDDSAPoint& other) { *this = other; } + EDDSAPoint (EDDSAPoint&& other) { *this = std::move (other); } + EDDSAPoint (BIGNUM * x1, BIGNUM * y1, BIGNUM * z1 = nullptr, BIGNUM * t1 = nullptr) + : x(x1) + , y(y1) + , z(z1) + , t(t1) + {} + ~EDDSAPoint () { BN_free (x); BN_free (y); BN_free(z); BN_free(t); } EDDSAPoint& operator=(EDDSAPoint&& other) { - if (x) BN_free (x); x = other.x; other.x = nullptr; - if (y) BN_free (y); y = other.y; other.y = nullptr; - if (z) BN_free (z); z = other.z; other.z = nullptr; - if (t) BN_free (t); t = other.t; other.t = nullptr; + if (this != &other) + { + BN_free (x); x = other.x; other.x = nullptr; + BN_free (y); y = other.y; other.y = nullptr; + BN_free (z); z = other.z; other.z = nullptr; + BN_free (t); t = other.t; other.t = nullptr; + } return *this; } EDDSAPoint& operator=(const EDDSAPoint& other) { - if (x) BN_free (x); x = other.x ? BN_dup (other.x) : nullptr; - if (y) BN_free (y); y = other.y ? BN_dup (other.y) : nullptr; - if (z) BN_free (z); z = other.z ? BN_dup (other.z) : nullptr; - if (t) BN_free (t); t = other.t ? BN_dup (other.t) : nullptr; + if (this != &other) + { + BN_free (x); x = other.x ? BN_dup (other.x) : nullptr; + BN_free (y); y = other.y ? BN_dup (other.y) : nullptr; + BN_free (z); z = other.z ? BN_dup (other.z) : nullptr; + BN_free (t); t = other.t ? BN_dup (other.t) : nullptr; + } return *this; } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index c598245a..eae959ed 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -276,8 +276,8 @@ namespace stream /** set max connections per minute per destination */ void SetMaxConnsPerMinute(const uint32_t conns); - Packet * NewPacket () { return m_PacketsPool.Acquire (); }; - void DeletePacket (Packet * p) { if (p) m_PacketsPool.Release (p); }; + Packet * NewPacket () { return m_PacketsPool.Acquire (); } + void DeletePacket (Packet * p) { m_PacketsPool.Release (p); } private: diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index b531bf71..bb94036a 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -102,9 +102,14 @@ namespace transport void DHKeysPairSupplier::Return (std::shared_ptr pair) { - std::unique_lockl(m_AcquiredMutex); - if ((int)m_Queue.size () < 2*m_QueueSize) - m_Queue.push (pair); + if (pair) + { + std::unique_lockl(m_AcquiredMutex); + if ((int)m_Queue.size () < 2*m_QueueSize) + m_Queue.push (pair); + } + else + LogPrint(eLogError, "Transports: return null DHKeys"); } Transports transports; @@ -142,13 +147,20 @@ namespace transport m_PeerTestTimer = new boost::asio::deadline_timer (*m_Service); } - i2p::config::GetOption("nat", m_IsNAT); - + i2p::config::GetOption("nat", m_IsNAT); m_DHKeysPairSupplier.Start (); m_IsRunning = true; m_Thread = new std::thread (std::bind (&Transports::Run, this)); std::string ntcpproxy; i2p::config::GetOption("ntcpproxy", ntcpproxy); i2p::http::URL proxyurl; + uint16_t softLimit, hardLimit; + i2p::config::GetOption("limits.ntcpsoft", softLimit); + i2p::config::GetOption("limits.ntcphard", hardLimit); + if(softLimit > 0 && hardLimit > 0 && softLimit >= hardLimit) + { + LogPrint(eLogError, "ntcp soft limit must be less than ntcp hard limit"); + return; + } if(ntcpproxy.size() && enableNTCP) { if(proxyurl.parse(ntcpproxy)) @@ -156,12 +168,11 @@ namespace transport if(proxyurl.schema == "socks" || proxyurl.schema == "http") { m_NTCPServer = new NTCPServer(); - + m_NTCPServer->SetSessionLimits(softLimit, hardLimit); NTCPServer::ProxyType proxytype = NTCPServer::eSocksProxy; if (proxyurl.schema == "http") proxytype = NTCPServer::eHTTPProxy; - m_NTCPServer->UseProxy(proxytype, proxyurl.host, proxyurl.port) ; m_NTCPServer->Start(); if(!m_NTCPServer->NetworkIsReady()) @@ -188,6 +199,7 @@ namespace transport if (m_NTCPServer == nullptr && enableNTCP) { m_NTCPServer = new NTCPServer (); + m_NTCPServer->SetSessionLimits(softLimit, hardLimit); m_NTCPServer->Start (); if (!(m_NTCPServer->IsBoundV6() || m_NTCPServer->IsBoundV4())) { /** failed to bind to NTCP */ @@ -389,20 +401,27 @@ namespace transport { if (!peer.router->UsesIntroducer () && !peer.router->IsUnreachable ()) { - auto s = std::make_shared (*m_NTCPServer, peer.router); - if(m_NTCPServer->UsingProxy()) + if(!m_NTCPServer->ShouldLimit()) { - NTCPServer::RemoteAddressType remote = NTCPServer::eIP4Address; - std::string addr = address->host.to_string(); + auto s = std::make_shared (*m_NTCPServer, peer.router); + if(m_NTCPServer->UsingProxy()) + { + NTCPServer::RemoteAddressType remote = NTCPServer::eIP4Address; + std::string addr = address->host.to_string(); - if(address->host.is_v6()) - remote = NTCPServer::eIP6Address; + if(address->host.is_v6()) + remote = NTCPServer::eIP6Address; - m_NTCPServer->ConnectWithProxy(addr, address->port, remote, s); + m_NTCPServer->ConnectWithProxy(addr, address->port, remote, s); + } + else + m_NTCPServer->Connect (address->host, address->port, s); + return true; } else - m_NTCPServer->Connect (address->host, address->port, s); - return true; + { + LogPrint(eLogWarning, "Transports: NTCP Limit hit falling back to SSU"); + } } } else // we don't have address diff --git a/libi2pd/util.h b/libi2pd/util.h index 38ca6b28..813af0fb 100644 --- a/libi2pd/util.h +++ b/libi2pd/util.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #ifdef ANDROID @@ -14,7 +15,7 @@ namespace std template std::string to_string(T value) { - return boost::lexical_cast(value); + return boost::lexical_cast(value); } inline int stoi(const std::string& str) @@ -29,12 +30,14 @@ namespace i2p namespace util { - template + template class MemoryPool { + //BOOST_STATIC_ASSERT_MSG(sizeof(T) >= sizeof(void*), "size cannot be less that general pointer size"); + public: - MemoryPool (): m_Head (nullptr) {}; + MemoryPool (): m_Head (nullptr) {} ~MemoryPool () { while (m_Head) @@ -48,12 +51,12 @@ namespace util template T * Acquire (TArgs&&... args) { - if (!m_Head) return new T(args...); + if (!m_Head) return new T(std::forward(args)...); else { auto tmp = m_Head; m_Head = static_cast(*(void * *)m_Head); // next - return new (tmp)T(args...); + return new (tmp)T(std::forward(args)...); } } @@ -68,14 +71,15 @@ namespace util template std::unique_ptr > AcquireUnique (TArgs&&... args) { - return std::unique_ptr >(Acquire (args...), + return std::unique_ptr >(Acquire (std::forward(args)...), std::bind (&MemoryPool::Release, this, std::placeholders::_1)); } template std::shared_ptr AcquireShared (TArgs&&... args) { - return std::shared_ptr(Acquire (args...), std::bind (&MemoryPool::Release, this, std::placeholders::_1)); + return std::shared_ptr(Acquire (std::forward(args)...), + std::bind (&MemoryPool::Release, this, std::placeholders::_1)); } protected: @@ -88,13 +92,13 @@ namespace util { public: - MemoryPoolMt () {}; + MemoryPoolMt () {} template T * AcquireMt (TArgs&&... args) { - if (!this->m_Head) return new T(args...); + if (!this->m_Head) return new T(std::forward(args)...); std::lock_guard l(m_Mutex); - return this->Acquire (args...); + return this->Acquire (std::forward(args)...); } void ReleaseMt (T * t) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 4eea297e..a15bbb14 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -48,12 +48,13 @@ namespace client std::shared_ptr localDestination; bool httproxy; i2p::config::GetOption("httpproxy.enabled", httproxy); - if (httproxy) + if (httproxy) { std::string httpProxyKeys; i2p::config::GetOption("httpproxy.keys", httpProxyKeys); std::string httpProxyAddr; i2p::config::GetOption("httpproxy.address", httpProxyAddr); uint16_t httpProxyPort; i2p::config::GetOption("httpproxy.port", httpProxyPort); i2p::data::SigningKeyType sigType; i2p::config::GetOption("httpproxy.signaturetype", sigType); + std::string httpOutProxyURL; i2p::config::GetOption("httpproxy.outproxy", httpOutProxyURL); LogPrint(eLogInfo, "Clients: starting HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort); if (httpProxyKeys.length () > 0) { @@ -68,12 +69,12 @@ namespace client else LogPrint(eLogError, "Clients: failed to load HTTP Proxy key"); } - try + try { - m_HttpProxy = new i2p::proxy::HTTPProxy(httpProxyAddr, httpProxyPort, localDestination); + m_HttpProxy = new i2p::proxy::HTTPProxy(httpProxyAddr, httpProxyPort, httpOutProxyURL, localDestination); m_HttpProxy->Start(); - } - catch (std::exception& e) + } + catch (std::exception& e) { LogPrint(eLogError, "Clients: Exception in HTTP Proxy: ", e.what()); } @@ -253,7 +254,7 @@ namespace client void ClientContext::ReloadConfig () { - // TODO: handle config changes + // TODO: handle config changes /*std::string config; i2p::config::GetOption("conf", config); i2p::config::ParseConfig(config);*/ @@ -269,7 +270,7 @@ namespace client std::unique_lock l(m_DestinationsMutex); for (auto it = m_Destinations.begin (); it != m_Destinations.end ();) { - auto dest = it->second; + auto dest = it->second; if (dest->GetRefCounter () > 0) ++it; // skip else { @@ -536,7 +537,8 @@ namespace client else if (type == I2P_TUNNELS_SECTION_TYPE_HTTPPROXY) { // http proxy - clientTunnel = new i2p::proxy::HTTPProxy(address, port, localDestination); + std::string outproxy = section.second.get("outproxy", ""); + clientTunnel = new i2p::proxy::HTTPProxy(address, port, outproxy, localDestination); clientEndpoint = ((i2p::proxy::HTTPProxy*)clientTunnel)->GetLocalEndpoint (); } else if (type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS) @@ -551,6 +553,13 @@ namespace client clientTunnel = new I2PClientTunnel (name, dest, address, port, localDestination, destinationPort); clientEndpoint = ((I2PClientTunnel*)clientTunnel)->GetLocalEndpoint (); } + uint32_t timeout = section.second.get(I2P_CLIENT_TUNNEL_CONNECT_TIMEOUT, 0); + if(timeout) + { + clientTunnel->SetConnectTimeout(timeout); + LogPrint(eLogInfo, "Clients: I2P Client tunnel connect timeout set to ", timeout); + } + auto ins = m_ClientTunnels.insert (std::make_pair (clientEndpoint, std::unique_ptr(clientTunnel))); if (ins.second) { @@ -560,8 +569,13 @@ namespace client else { // TODO: update + if (ins.first->second->GetLocalDestination () != clientTunnel->GetLocalDestination ()) + { + LogPrint (eLogInfo, "Clients: I2P client tunnel destination updated"); + ins.first->second->SetLocalDestination (clientTunnel->GetLocalDestination ()); + } ins.first->second->isUpdated = true; - LogPrint (eLogInfo, "Clients: I2P client tunnel for endpoint ", clientEndpoint, "already exists"); + LogPrint (eLogInfo, "Clients: I2P client tunnel for endpoint ", clientEndpoint, " already exists"); } } } @@ -657,7 +671,7 @@ namespace client } auto ins = m_ServerTunnels.insert (std::make_pair ( std::make_pair (localDestination->GetIdentHash (), inPort), - std::unique_ptr(serverTunnel))); + std::unique_ptr(serverTunnel))); if (ins.second) { serverTunnel->Start (); @@ -666,6 +680,11 @@ namespace client else { // TODO: update + if (ins.first->second->GetLocalDestination () != serverTunnel->GetLocalDestination ()) + { + LogPrint (eLogInfo, "Clients: I2P server tunnel destination updated"); + ins.first->second->SetLocalDestination (serverTunnel->GetLocalDestination ()); + } ins.first->second->isUpdated = true; LogPrint (eLogInfo, "Clients: I2P server tunnel for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), "/", inPort, " already exists"); } @@ -715,8 +734,8 @@ namespace client it = c.erase (it); } else - it++; - } + it++; + } } template diff --git a/libi2pd_client/ClientContext.h b/libi2pd_client/ClientContext.h index 0eef1f79..f22c0817 100644 --- a/libi2pd_client/ClientContext.h +++ b/libi2pd_client/ClientContext.h @@ -36,6 +36,7 @@ namespace client const char I2P_CLIENT_TUNNEL_SIGNATURE_TYPE[] = "signaturetype"; 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_SERVER_TUNNEL_HOST[] = "host"; const char I2P_SERVER_TUNNEL_HOST_OVERRIDE[] = "hostoverride"; const char I2P_SERVER_TUNNEL_PORT[] = "port"; diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 50a45e99..b1e1a545 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -67,23 +67,26 @@ namespace proxy { void ForwardToUpstreamProxy(); void HandleUpstreamHTTPProxyConnect(const boost::system::error_code & ec); void HandleUpstreamSocksProxyConnect(const boost::system::error_code & ec); - + void HTTPConnect(const std::string & host, uint16_t port); + void HandleHTTPConnectStreamRequestComplete(std::shared_ptr stream); + void HandleSocksProxySendHandshake(const boost::system::error_code & ec, std::size_t bytes_transfered); void HandleSocksProxyReply(const boost::system::error_code & ec, std::size_t bytes_transfered); - + typedef std::function ProxyResolvedHandler; - + void HandleUpstreamProxyResolved(const boost::system::error_code & ecode, boost::asio::ip::tcp::resolver::iterator itr, ProxyResolvedHandler handler); void SocksProxySuccess(); void HandoverToUpstreamProxy(); - + uint8_t m_recv_chunk[8192]; std::string m_recv_buf; // from client std::string m_send_buf; // to upstream std::shared_ptr m_sock; std::shared_ptr m_proxysock; boost::asio::ip::tcp::resolver m_proxy_resolver; + std::string m_OutproxyUrl; i2p::http::URL m_ProxyURL; i2p::http::URL m_RequestURL; uint8_t m_socks_buf[255+8]; // for socks request/response @@ -97,7 +100,8 @@ namespace proxy { HTTPReqHandler(HTTPProxy * parent, std::shared_ptr sock) : I2PServiceHandler(parent), m_sock(sock), m_proxysock(std::make_shared(parent->GetService())), - m_proxy_resolver(parent->GetService()) {} + m_proxy_resolver(parent->GetService()), + m_OutproxyUrl(parent->GetOutproxyURL()) {} ~HTTPReqHandler() { Terminate(); } void Handle () { AsyncSockRead(); } /* overload */ }; @@ -116,7 +120,7 @@ namespace proxy { void HTTPReqHandler::Terminate() { if (Kill()) return; - if (m_sock) + if (m_sock) { LogPrint(eLogDebug, "HTTPProxy: close sock"); m_sock->close(); @@ -200,13 +204,14 @@ namespace proxy { void HTTPReqHandler::SanitizeHTTPRequest(i2p::http::HTTPReq & req) { /* drop common headers */ - req.RemoveHeader ("Referer"); + req.RemoveHeader("Referer"); req.RemoveHeader("Via"); - req.RemoveHeader("Forwarded"); - req.RemoveHeader("Accept-", "Accept-Encoding"); // Accept-*, but Accept-Encoding + req.RemoveHeader("From"); + req.RemoveHeader("Forwarded"); + req.RemoveHeader("Accept", "Accept-Encoding"); // Accept*, but Accept-Encoding /* drop proxy-disclosing headers */ req.RemoveHeader("X-Forwarded"); - req.RemoveHeader("Proxy-"); // Proxy-* + req.RemoveHeader("Proxy-"); // Proxy-* /* replace headers */ req.UpdateHeader("User-Agent", "MYOB/6.66 (AN/ON)"); /* add headers */ @@ -238,14 +243,14 @@ namespace proxy { LogPrint(eLogDebug, "HTTPProxy: requested: ", m_ClientRequest.uri); m_RequestURL.parse(m_ClientRequest.uri); - if (ExtractAddressHelper(m_RequestURL, b64)) + if (ExtractAddressHelper(m_RequestURL, b64)) { bool addresshelper; i2p::config::GetOption("httpproxy.addresshelper", addresshelper); if (!addresshelper) { LogPrint(eLogWarning, "HTTPProxy: addresshelper disabled"); GenericProxyError("Invalid request", "adddresshelper is not supported"); - return true; + return true; } i2p::client::context.GetAddressBook ().InsertAddress (m_RequestURL.host, b64); LogPrint (eLogInfo, "HTTPProxy: added b64 from addresshelper for ", m_RequestURL.host); @@ -256,43 +261,63 @@ namespace proxy { GenericProxyInfo("Addresshelper found", ss.str().c_str()); return true; /* request processed */ } - - SanitizeHTTPRequest(m_ClientRequest); - - std::string dest_host = m_RequestURL.host; - uint16_t dest_port = m_RequestURL.port; - /* always set port, even if missing in request */ - if (!dest_port) - dest_port = (m_RequestURL.schema == "https") ? 443 : 80; - /* detect dest_host, set proper 'Host' header in upstream request */ - if (dest_host != "") + std::string dest_host; + uint16_t dest_port; + bool useConnect = false; + if(m_ClientRequest.method == "CONNECT") { - /* absolute url, replace 'Host' header */ - std::string h = dest_host; - if (dest_port != 0 && dest_port != 80) - h += ":" + std::to_string(dest_port); - m_ClientRequest.UpdateHeader("Host", h); - } - else - { - auto h = m_ClientRequest.GetHeader ("Host"); - if (h.length () > 0) + std::string uri(m_ClientRequest.uri); + auto pos = uri.find(":"); + if(pos == std::string::npos || pos == uri.size() - 1) { - /* relative url and 'Host' header provided. transparent proxy mode? */ - i2p::http::URL u; - std::string t = "http://" + h; - u.parse(t); - dest_host = u.host; - dest_port = u.port; - } - else - { - /* relative url and missing 'Host' header */ - GenericProxyError("Invalid request", "Can't detect destination host from request"); + GenericProxyError("Invalid Request", "invalid request uri"); return true; } - } + else + { + useConnect = true; + dest_port = std::stoi(uri.substr(pos+1)); + dest_host = uri.substr(0, pos); + } + } + else + { + SanitizeHTTPRequest(m_ClientRequest); + dest_host = m_RequestURL.host; + dest_port = m_RequestURL.port; + /* always set port, even if missing in request */ + if (!dest_port) + dest_port = (m_RequestURL.schema == "https") ? 443 : 80; + /* detect dest_host, set proper 'Host' header in upstream request */ + if (dest_host != "") + { + /* absolute url, replace 'Host' header */ + std::string h = dest_host; + if (dest_port != 0 && dest_port != 80) + h += ":" + std::to_string(dest_port); + m_ClientRequest.UpdateHeader("Host", h); + } + else + { + auto h = m_ClientRequest.GetHeader ("Host"); + if (h.length () > 0) + { + /* relative url and 'Host' header provided. transparent proxy mode? */ + i2p::http::URL u; + std::string t = "http://" + h; + u.parse(t); + dest_host = u.host; + dest_port = u.port; + } + else + { + /* relative url and missing 'Host' header */ + GenericProxyError("Invalid request", "Can't detect destination host from request"); + return true; + } + } + } /* check dest_host really exists and inside I2P network */ i2p::data::IdentHash identHash; if (str_rmatch(dest_host, ".i2p")) { @@ -301,10 +326,9 @@ namespace proxy { return true; /* request processed */ } } else { - std::string outproxyUrl; i2p::config::GetOption("httpproxy.outproxy", outproxyUrl); - if(outproxyUrl.size()) { - LogPrint (eLogDebug, "HTTPProxy: use outproxy ", outproxyUrl); - if(m_ProxyURL.parse(outproxyUrl)) + if(m_OutproxyUrl.size()) { + LogPrint (eLogDebug, "HTTPProxy: use outproxy ", m_OutproxyUrl); + if(m_ProxyURL.parse(m_OutproxyUrl)) ForwardToUpstreamProxy(); else GenericProxyError("Outproxy failure", "bad outproxy settings"); @@ -315,6 +339,11 @@ namespace proxy { } return true; } + if(useConnect) + { + HTTPConnect(dest_host, dest_port); + return true; + } /* make relative url */ m_RequestURL.schema = ""; @@ -346,15 +375,24 @@ namespace proxy { m_ClientRequest.write(m_ClientRequestBuffer); m_ClientRequestBuffer << m_recv_buf.substr(m_req_len); - + // assume http if empty schema if (m_ProxyURL.schema == "" || m_ProxyURL.schema == "http") { // handle upstream http proxy if (!m_ProxyURL.port) m_ProxyURL.port = 80; - boost::asio::ip::tcp::resolver::query q(m_ProxyURL.host, std::to_string(m_ProxyURL.port)); - m_proxy_resolver.async_resolve(q, std::bind(&HTTPReqHandler::HandleUpstreamProxyResolved, this, std::placeholders::_1, std::placeholders::_2, [&](boost::asio::ip::tcp::endpoint ep) { - m_proxysock->async_connect(ep, std::bind(&HTTPReqHandler::HandleUpstreamHTTPProxyConnect, this, std::placeholders::_1)); - })); + if (m_ProxyURL.is_i2p()) + { + m_send_buf = m_recv_buf; + GetOwner()->CreateStream (std::bind (&HTTPReqHandler::HandleStreamRequestComplete, + shared_from_this(), std::placeholders::_1), m_ProxyURL.host, m_ProxyURL.port); + } + else + { + boost::asio::ip::tcp::resolver::query q(m_ProxyURL.host, std::to_string(m_ProxyURL.port)); + m_proxy_resolver.async_resolve(q, std::bind(&HTTPReqHandler::HandleUpstreamProxyResolved, this, std::placeholders::_1, std::placeholders::_2, [&](boost::asio::ip::tcp::endpoint ep) { + m_proxysock->async_connect(ep, std::bind(&HTTPReqHandler::HandleUpstreamHTTPProxyConnect, this, std::placeholders::_1)); + })); + } } else if (m_ProxyURL.schema == "socks") { // handle upstream socks proxy if (!m_ProxyURL.port) m_ProxyURL.port = 9050; // default to tor default if not specified @@ -371,7 +409,7 @@ namespace proxy { void HTTPReqHandler::HandleUpstreamProxyResolved(const boost::system::error_code & ec, boost::asio::ip::tcp::resolver::iterator it, ProxyResolvedHandler handler) { if(ec) GenericProxyError("cannot resolve upstream proxy", ec.message().c_str()); - else handler(*it); + else handler(*it); } void HTTPReqHandler::HandleUpstreamSocksProxyConnect(const boost::system::error_code & ec) @@ -425,7 +463,38 @@ namespace proxy { connection->Start(); Terminate(); } - + + void HTTPReqHandler::HTTPConnect(const std::string & host, uint16_t port) + { + LogPrint(eLogDebug, "HTTPProxy: CONNECT ",host, ":", port); + std::string hostname(host); + if(str_rmatch(hostname, ".i2p")) + GetOwner()->CreateStream (std::bind (&HTTPReqHandler::HandleHTTPConnectStreamRequestComplete, + shared_from_this(), std::placeholders::_1), host, port); + else + ForwardToUpstreamProxy(); + } + + void HTTPReqHandler::HandleHTTPConnectStreamRequestComplete(std::shared_ptr stream) + { + if(stream) + { + m_ClientResponse.code = 200; + m_ClientResponse.status = "OK"; + m_send_buf = m_ClientResponse.to_string(); + m_sock->send(boost::asio::buffer(m_send_buf)); + auto connection = std::make_shared(GetOwner(), m_sock, stream); + GetOwner()->AddHandler(connection); + connection->I2PConnect(); + m_sock = nullptr; + Terminate(); + } + else + { + GenericProxyError("CONNECT error", "Failed to Connect"); + } + } + void HTTPReqHandler::SocksProxySuccess() { if(m_ClientRequest.method == "CONNECT") { @@ -444,7 +513,7 @@ namespace proxy { }); } } - + void HTTPReqHandler::HandleSocksProxyReply(const boost::system::error_code & ec, std::size_t bytes_transferred) { if(!ec) @@ -462,7 +531,7 @@ namespace proxy { } else GenericProxyError("No Reply From socks proxy", ec.message().c_str()); } - + void HTTPReqHandler::HandleUpstreamHTTPProxyConnect(const boost::system::error_code & ec) { if(!ec) { @@ -470,12 +539,12 @@ namespace proxy { GenericProxyError("cannot connect", "http out proxy not implemented"); } else GenericProxyError("cannot connect to upstream http proxy", ec.message().c_str()); } - + /* will be called after some data received from client */ void HTTPReqHandler::HandleSockRecv(const boost::system::error_code & ecode, std::size_t len) { LogPrint(eLogDebug, "HTTPProxy: sock recv: ", len, " bytes, recv buf: ", m_recv_buf.length(), ", send buf: ", m_send_buf.length()); - if(ecode) + if(ecode) { LogPrint(eLogWarning, "HTTPProxy: sock recv got error: ", ecode); Terminate(); @@ -513,11 +582,12 @@ namespace proxy { Done (shared_from_this()); } - HTTPProxy::HTTPProxy(const std::string& address, int port, std::shared_ptr localDestination): - TCPIPAcceptor(address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ()) + HTTPProxy::HTTPProxy(const std::string& address, int port, const std::string & outproxy, std::shared_ptr localDestination): + TCPIPAcceptor(address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ()), + m_OutproxyUrl(outproxy) { } - + std::shared_ptr HTTPProxy::CreateHandler(std::shared_ptr socket) { return std::make_shared (this, socket); diff --git a/libi2pd_client/HTTPProxy.h b/libi2pd_client/HTTPProxy.h index 29b997eb..0adb2d2e 100644 --- a/libi2pd_client/HTTPProxy.h +++ b/libi2pd_client/HTTPProxy.h @@ -6,14 +6,20 @@ namespace proxy { class HTTPProxy: public i2p::client::TCPIPAcceptor { public: - - HTTPProxy(const std::string& address, int port, std::shared_ptr localDestination = nullptr); + HTTPProxy(const std::string& address, int port, const std::string & outproxy, std::shared_ptr localDestination); + HTTPProxy(const std::string& address, int port, std::shared_ptr localDestination = nullptr) : + HTTPProxy(address, port, "", localDestination) {} ; ~HTTPProxy() {}; + std::string GetOutproxyURL() const { return m_OutproxyUrl; } + protected: // Implements TCPIPAcceptor std::shared_ptr CreateHandler(std::shared_ptr socket); const char* GetName() { return "HTTP Proxy"; } + + private: + std::string m_OutproxyUrl; }; } // http } // i2p diff --git a/libi2pd_client/I2PService.cpp b/libi2pd_client/I2PService.cpp index 9348ec48..6fd5d763 100644 --- a/libi2pd_client/I2PService.cpp +++ b/libi2pd_client/I2PService.cpp @@ -2,6 +2,7 @@ #include "Identity.h" #include "ClientContext.h" #include "I2PService.h" +#include namespace i2p { @@ -11,37 +12,99 @@ namespace client I2PService::I2PService (std::shared_ptr localDestination): m_LocalDestination (localDestination ? localDestination : - i2p::client::context.CreateNewLocalDestination (false, I2P_SERVICE_DEFAULT_KEY_TYPE)), isUpdated (true) + i2p::client::context.CreateNewLocalDestination (false, I2P_SERVICE_DEFAULT_KEY_TYPE)), + m_ReadyTimer(m_LocalDestination->GetService()), + m_ConnectTimeout(0), + isUpdated (true) { - m_LocalDestination->Acquire (); + m_LocalDestination->Acquire (); } - + I2PService::I2PService (i2p::data::SigningKeyType kt): m_LocalDestination (i2p::client::context.CreateNewLocalDestination (false, kt)), + m_ReadyTimer(m_LocalDestination->GetService()), + m_ConnectTimeout(0), isUpdated (true) { m_LocalDestination->Acquire (); } - - I2PService::~I2PService () - { - ClearHandlers (); - if (m_LocalDestination) m_LocalDestination->Release (); + + I2PService::~I2PService () + { + ClearHandlers (); + if (m_LocalDestination) m_LocalDestination->Release (); } void I2PService::ClearHandlers () { + if(m_ConnectTimeout) + m_ReadyTimer.cancel(); std::unique_lock l(m_HandlersMutex); for (auto it: m_Handlers) it->Terminate (); m_Handlers.clear(); } - + + void I2PService::SetConnectTimeout(uint32_t timeout) + { + if(timeout && !m_ConnectTimeout) + { + TriggerReadyCheckTimer(); + } + else if (m_ConnectTimeout && !timeout) + { + m_ReadyTimer.cancel(); + } + m_ConnectTimeout = timeout; + } + + void I2PService::AddReadyCallback(ReadyCallback cb) + { + uint32_t now = i2p::util::GetSecondsSinceEpoch(); + uint32_t tm = now + m_ConnectTimeout; + LogPrint(eLogDebug, "I2PService::AddReadyCallback() ", tm, " ", now); + m_ReadyCallbacks.push_back({cb, tm}); + } + + void I2PService::TriggerReadyCheckTimer() + { + m_ReadyTimer.expires_from_now(boost::posix_time::seconds (1)); + m_ReadyTimer.async_wait(std::bind(&I2PService::HandleReadyCheckTimer, this, std::placeholders::_1)); + } + + void I2PService::HandleReadyCheckTimer(const boost::system::error_code &ec) + { + if(ec || m_LocalDestination->IsReady()) + { + for(auto & itr : m_ReadyCallbacks) + itr.first(ec); + m_ReadyCallbacks.clear(); + } + else if(!m_LocalDestination->IsReady()) + { + // expire timed out requests + uint32_t now = i2p::util::GetSecondsSinceEpoch (); + auto itr = m_ReadyCallbacks.begin(); + while(itr != m_ReadyCallbacks.end()) + { + if(itr->second >= now) + { + itr->first(boost::asio::error::timed_out); + itr = m_ReadyCallbacks.erase(itr); + } + else + ++itr; + } + } + if(!ec) + TriggerReadyCheckTimer(); + } + void I2PService::CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port) { assert(streamRequestComplete); i2p::data::IdentHash identHash; if (i2p::client::context.GetAddressBook ().GetIdentHash (dest, identHash)) - m_LocalDestination->CreateStream (streamRequestComplete, identHash, port); + CreateStream(streamRequestComplete, identHash, port); else { LogPrint (eLogWarning, "I2PService: Remote destination not found: ", dest); @@ -49,6 +112,29 @@ namespace client } } + void I2PService::CreateStream(StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash & identHash, int port) + { + if(m_ConnectTimeout) + { + if(m_LocalDestination->IsReady()) + m_LocalDestination->CreateStream (streamRequestComplete, identHash, port); + else + { + AddReadyCallback([this, streamRequestComplete, identHash, port] (const boost::system::error_code & ec) { + if(ec) + { + LogPrint(eLogWarning, "I2PService::CeateStream() ", ec.message()); + streamRequestComplete(nullptr); + } + else + this->m_LocalDestination->CreateStream(streamRequestComplete, identHash, port); + }); + } + } + else + m_LocalDestination->CreateStream(streamRequestComplete, identHash, port); + } + TCPIPPipe::TCPIPPipe(I2PService * owner, std::shared_ptr upstream, std::shared_ptr downstream) : I2PServiceHandler(owner), m_up(upstream), m_down(downstream) { boost::asio::socket_base::receive_buffer_size option(TCP_IP_PIPE_BUFFER_SIZE); @@ -60,7 +146,7 @@ namespace client { Terminate(); } - + void TCPIPPipe::Start() { AsyncReceiveUpstream(); @@ -70,124 +156,127 @@ namespace client void TCPIPPipe::Terminate() { if(Kill()) return; - if (m_up) { - if (m_up->is_open()) { + if (m_up) + { + if (m_up->is_open()) m_up->close(); - } m_up = nullptr; } - if (m_down) { - if (m_down->is_open()) { + if (m_down) + { + if (m_down->is_open()) m_down->close(); - } m_down = nullptr; } Done(shared_from_this()); } - + void TCPIPPipe::AsyncReceiveUpstream() { - if (m_up) { + if (m_up) + { m_up->async_read_some(boost::asio::buffer(m_upstream_to_down_buf, TCP_IP_PIPE_BUFFER_SIZE), - std::bind(&TCPIPPipe::HandleUpstreamReceived, shared_from_this(), - std::placeholders::_1, std::placeholders::_2)); - } else { - LogPrint(eLogError, "TCPIPPipe: upstream receive: no socket"); + std::bind(&TCPIPPipe::HandleUpstreamReceived, shared_from_this(), + std::placeholders::_1, std::placeholders::_2)); } + else + LogPrint(eLogError, "TCPIPPipe: upstream receive: no socket"); } void TCPIPPipe::AsyncReceiveDownstream() { if (m_down) { m_down->async_read_some(boost::asio::buffer(m_downstream_to_up_buf, TCP_IP_PIPE_BUFFER_SIZE), - std::bind(&TCPIPPipe::HandleDownstreamReceived, shared_from_this(), - std::placeholders::_1, std::placeholders::_2)); - } else { - LogPrint(eLogError, "TCPIPPipe: downstream receive: no socket"); + std::bind(&TCPIPPipe::HandleDownstreamReceived, shared_from_this(), + std::placeholders::_1, std::placeholders::_2)); } + else + LogPrint(eLogError, "TCPIPPipe: downstream receive: no socket"); } void TCPIPPipe::UpstreamWrite(size_t len) { - if (m_up) { + if (m_up) + { LogPrint(eLogDebug, "TCPIPPipe: upstream: ", (int) len, " bytes written"); boost::asio::async_write(*m_up, boost::asio::buffer(m_upstream_buf, len), - boost::asio::transfer_all(), - std::bind(&TCPIPPipe::HandleUpstreamWrite, - shared_from_this(), - std::placeholders::_1) - ); - } else { - LogPrint(eLogError, "TCPIPPipe: upstream write: no socket"); + boost::asio::transfer_all(), + std::bind(&TCPIPPipe::HandleUpstreamWrite, + shared_from_this(), + std::placeholders::_1)); } + else + LogPrint(eLogError, "TCPIPPipe: upstream write: no socket"); } void TCPIPPipe::DownstreamWrite(size_t len) { - if (m_down) { + if (m_down) + { LogPrint(eLogDebug, "TCPIPPipe: downstream: ", (int) len, " bytes written"); boost::asio::async_write(*m_down, boost::asio::buffer(m_downstream_buf, len), - boost::asio::transfer_all(), - std::bind(&TCPIPPipe::HandleDownstreamWrite, - shared_from_this(), - std::placeholders::_1) - ); - } else { - LogPrint(eLogError, "TCPIPPipe: downstream write: no socket"); + boost::asio::transfer_all(), + std::bind(&TCPIPPipe::HandleDownstreamWrite, + shared_from_this(), + std::placeholders::_1)); } + else + LogPrint(eLogError, "TCPIPPipe: downstream write: no socket"); } - - + + void TCPIPPipe::HandleDownstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered) { LogPrint(eLogDebug, "TCPIPPipe: downstream: ", (int) bytes_transfered, " bytes received"); - if (ecode) { + if (ecode) + { LogPrint(eLogError, "TCPIPPipe: downstream read error:" , ecode.message()); if (ecode != boost::asio::error::operation_aborted) Terminate(); } else { - if (bytes_transfered > 0 ) { + if (bytes_transfered > 0 ) memcpy(m_upstream_buf, m_downstream_to_up_buf, bytes_transfered); - } UpstreamWrite(bytes_transfered); } } void TCPIPPipe::HandleDownstreamWrite(const boost::system::error_code & ecode) { - if (ecode) { + if (ecode) + { LogPrint(eLogError, "TCPIPPipe: downstream write error:" , ecode.message()); if (ecode != boost::asio::error::operation_aborted) Terminate(); - } else { - AsyncReceiveUpstream(); } + else + AsyncReceiveUpstream(); } - + void TCPIPPipe::HandleUpstreamWrite(const boost::system::error_code & ecode) { - if (ecode) { + if (ecode) + { LogPrint(eLogError, "TCPIPPipe: upstream write error:" , ecode.message()); if (ecode != boost::asio::error::operation_aborted) Terminate(); - } else { - AsyncReceiveDownstream(); } + else + AsyncReceiveDownstream(); } - + void TCPIPPipe::HandleUpstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered) { LogPrint(eLogDebug, "TCPIPPipe: upstream ", (int)bytes_transfered, " bytes received"); - if (ecode) { + if (ecode) + { LogPrint(eLogError, "TCPIPPipe: upstream read error:" , ecode.message()); if (ecode != boost::asio::error::operation_aborted) Terminate(); } else { - if (bytes_transfered > 0 ) { + if (bytes_transfered > 0 ) memcpy(m_downstream_buf, m_upstream_to_down_buf, bytes_transfered); - } DownstreamWrite(bytes_transfered); } } - + void TCPIPAcceptor::Start () { m_Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService (), m_LocalEndpoint)); @@ -198,10 +287,10 @@ namespace client void TCPIPAcceptor::Stop () { if (m_Acceptor) - { + { m_Acceptor->close(); m_Acceptor.reset (nullptr); - } + } m_Timer.cancel (); ClearHandlers(); } @@ -219,12 +308,12 @@ namespace client { LogPrint(eLogDebug, "I2PService: ", GetName(), " accepted"); auto handler = CreateHandler(socket); - if (handler) + if (handler) { AddHandler(handler); handler->Handle(); - } - else + } + else socket->close(); Accept(); } diff --git a/libi2pd_client/I2PService.h b/libi2pd_client/I2PService.h index cf0cfd98..fd5e8999 100644 --- a/libi2pd_client/I2PService.h +++ b/libi2pd_client/I2PService.h @@ -14,8 +14,11 @@ namespace i2p namespace client { class I2PServiceHandler; - class I2PService + class I2PService : std::enable_shared_from_this { + public: + typedef std::function ReadyCallback; + public: I2PService (std::shared_ptr localDestination = nullptr); I2PService (i2p::data::SigningKeyType kt); @@ -33,25 +36,41 @@ namespace client } void ClearHandlers (); + void SetConnectTimeout(uint32_t timeout); + + void AddReadyCallback(ReadyCallback cb); + inline std::shared_ptr GetLocalDestination () { return m_LocalDestination; } inline std::shared_ptr GetLocalDestination () const { return m_LocalDestination; } - inline void SetLocalDestination (std::shared_ptr dest) { m_LocalDestination = dest; } + inline void SetLocalDestination (std::shared_ptr dest) + { + if (m_LocalDestination) m_LocalDestination->Release (); + if (dest) dest->Acquire (); + m_LocalDestination = dest; + } void CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port = 0); - + void CreateStream(StreamRequestComplete complete, const i2p::data::IdentHash & ident, int port); inline boost::asio::io_service& GetService () { return m_LocalDestination->GetService (); } virtual void Start () = 0; virtual void Stop () = 0; virtual const char* GetName() { return "Generic I2P Service"; } - private: + private: + void TriggerReadyCheckTimer(); + void HandleReadyCheckTimer(const boost::system::error_code & ec); + + private: std::shared_ptr m_LocalDestination; std::unordered_set > m_Handlers; std::mutex m_HandlersMutex; + std::vector > m_ReadyCallbacks; + boost::asio::deadline_timer m_ReadyTimer; + uint32_t m_ConnectTimeout; public: - bool isUpdated; // transient, used during reload only + bool isUpdated; // transient, used during reload only }; /*Simple interface for I2PHandlers, allows detection of finalization amongst other things */ @@ -64,7 +83,7 @@ namespace client virtual void Handle() {}; //Start handling the socket void Terminate () { Kill (); }; - + protected: // Call when terminating or handing over to avoid race conditions inline bool Kill () { return m_Dead.exchange(true); } @@ -74,6 +93,7 @@ namespace client inline void Done (std::shared_ptr me) { if(m_Service) m_Service->RemoveHandler(me); } // Call to talk with the owner inline I2PService * GetOwner() { return m_Service; } + private: I2PService *m_Service; std::atomic m_Dead; //To avoid cleaning up multiple times @@ -82,27 +102,30 @@ namespace client const size_t TCP_IP_PIPE_BUFFER_SIZE = 8192 * 8; // bidirectional pipe for 2 tcp/ip sockets - class TCPIPPipe: public I2PServiceHandler, public std::enable_shared_from_this { - public: - TCPIPPipe(I2PService * owner, std::shared_ptr upstream, std::shared_ptr downstream); - ~TCPIPPipe(); - void Start(); - protected: - void Terminate(); - void AsyncReceiveUpstream(); - void AsyncReceiveDownstream(); - void HandleUpstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transferred); - void HandleDownstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transferred); - void HandleUpstreamWrite(const boost::system::error_code & ecode); - void HandleDownstreamWrite(const boost::system::error_code & ecode); - void UpstreamWrite(size_t len); - void DownstreamWrite(size_t len); - private: - uint8_t m_upstream_to_down_buf[TCP_IP_PIPE_BUFFER_SIZE], m_downstream_to_up_buf[TCP_IP_PIPE_BUFFER_SIZE]; - uint8_t m_upstream_buf[TCP_IP_PIPE_BUFFER_SIZE], m_downstream_buf[TCP_IP_PIPE_BUFFER_SIZE]; - std::shared_ptr m_up, m_down; + class TCPIPPipe: public I2PServiceHandler, public std::enable_shared_from_this + { + public: + TCPIPPipe(I2PService * owner, std::shared_ptr upstream, std::shared_ptr downstream); + ~TCPIPPipe(); + void Start(); + + protected: + void Terminate(); + void AsyncReceiveUpstream(); + void AsyncReceiveDownstream(); + void HandleUpstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transferred); + void HandleDownstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transferred); + void HandleUpstreamWrite(const boost::system::error_code & ecode); + void HandleDownstreamWrite(const boost::system::error_code & ecode); + void UpstreamWrite(size_t len); + void DownstreamWrite(size_t len); + + private: + uint8_t m_upstream_to_down_buf[TCP_IP_PIPE_BUFFER_SIZE], m_downstream_to_up_buf[TCP_IP_PIPE_BUFFER_SIZE]; + uint8_t m_upstream_buf[TCP_IP_PIPE_BUFFER_SIZE], m_downstream_buf[TCP_IP_PIPE_BUFFER_SIZE]; + std::shared_ptr m_up, m_down; }; - + /* TODO: support IPv6 too */ //This is a service that listens for connections on the IP network and interacts with I2P class TCPIPAcceptor: public I2PService @@ -124,10 +147,11 @@ namespace client const boost::asio::ip::tcp::endpoint& GetLocalEndpoint () const { return m_LocalEndpoint; }; - virtual const char* GetName() { return "Generic TCP/IP accepting daemon"; } + virtual const char* GetName() { return "Generic TCP/IP accepting daemon"; } protected: virtual std::shared_ptr CreateHandler(std::shared_ptr socket) = 0; + private: void Accept(); void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index 71b09e1a..da5dbfee 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -14,29 +14,29 @@ namespace client static void I2PTunnelSetSocketOptions(std::shared_ptr socket) { if (socket && socket->is_open()) - { + { boost::asio::socket_base::receive_buffer_size option(I2P_TUNNEL_CONNECTION_BUFFER_SIZE); socket->set_option(option); } } - + I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr socket, - std::shared_ptr leaseSet, int port): + std::shared_ptr leaseSet, int port): I2PServiceHandler(owner), m_Socket (socket), m_RemoteEndpoint (socket->remote_endpoint ()), m_IsQuiet (true) { m_Stream = GetOwner()->GetLocalDestination ()->CreateStream (leaseSet, port); - } + } I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, - std::shared_ptr socket, std::shared_ptr stream): + std::shared_ptr socket, std::shared_ptr stream): I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream), m_RemoteEndpoint (socket->remote_endpoint ()), m_IsQuiet (true) { } I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr stream, - std::shared_ptr socket, const boost::asio::ip::tcp::endpoint& target, bool quiet): + std::shared_ptr socket, const boost::asio::ip::tcp::endpoint& target, bool quiet): I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream), m_RemoteEndpoint (target), m_IsQuiet (quiet) { @@ -44,15 +44,15 @@ namespace client I2PTunnelConnection::~I2PTunnelConnection () { - } - + } + void I2PTunnelConnection::I2PConnect (const uint8_t * msg, size_t len) { if (m_Stream) { if (msg) m_Stream->Send (msg, len); // connect and send - else + else m_Stream->Send (m_Buffer, 0); // connect } StreamReceive (); @@ -68,11 +68,11 @@ namespace client boost::asio::ip::address ourIP = boost::asio::ip::address_v4 (bytes); return ourIP; } - + static void MapToLoopback(const std::shared_ptr & sock, const i2p::data::IdentHash & addr) { - // bind to 127.x.x.x address + // bind to 127.x.x.x address // where x.x.x are first three bytes from ident auto ourIP = GetLoopbackAddressFor(addr); sock->bind (boost::asio::ip::tcp::endpoint (ourIP, 0)); @@ -82,7 +82,7 @@ namespace client void I2PTunnelConnection::Connect (bool isUniqueLocal) { I2PTunnelSetSocketOptions(m_Socket); - if (m_Socket) + if (m_Socket) { #ifdef __linux__ if (isUniqueLocal && m_RemoteEndpoint.address ().is_v4 () && @@ -96,8 +96,8 @@ namespace client m_Socket->async_connect (m_RemoteEndpoint, std::bind (&I2PTunnelConnection::HandleConnect, shared_from_this (), std::placeholders::_1)); } - } - + } + void I2PTunnelConnection::Terminate () { if (Kill()) return; @@ -105,21 +105,21 @@ namespace client { m_Stream->Close (); m_Stream.reset (); - } + } boost::system::error_code ec; m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec); // avoid RST m_Socket->close (); Done(shared_from_this ()); - } + } void I2PTunnelConnection::Receive () { - m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), - std::bind(&I2PTunnelConnection::HandleReceived, shared_from_this (), + m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), + std::bind(&I2PTunnelConnection::HandleReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); - } - + } + void I2PTunnelConnection::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) { if (ecode) @@ -131,21 +131,21 @@ namespace client } } else - { + { if (m_Stream) - { + { auto s = shared_from_this (); m_Stream->AsyncSend (m_Buffer, bytes_transferred, [s](const boost::system::error_code& ecode) - { + { if (!ecode) s->Receive (); else s->Terminate (); }); - } + } } - } + } void I2PTunnelConnection::HandleWrite (const boost::system::error_code& ecode) { @@ -164,13 +164,13 @@ namespace client if (m_Stream) { if (m_Stream->GetStatus () == i2p::stream::eStreamStatusNew || - m_Stream->GetStatus () == i2p::stream::eStreamStatusOpen) // regular - { + m_Stream->GetStatus () == i2p::stream::eStreamStatusOpen) // regular + { m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), std::bind (&I2PTunnelConnection::HandleStreamReceive, shared_from_this (), std::placeholders::_1, std::placeholders::_2), I2P_TUNNEL_CONNECTION_MAX_IDLE); - } + } else // closed by peer { // get remaning data @@ -178,10 +178,10 @@ namespace client if (len > 0) // still some data Write (m_StreamBuffer, len); else // no more data - Terminate (); - } - } - } + Terminate (); + } + } + } void I2PTunnelConnection::HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) { @@ -207,7 +207,7 @@ namespace client void I2PTunnelConnection::Write (const uint8_t * buf, size_t len) { boost::asio::async_write (*m_Socket, boost::asio::buffer (buf, len), boost::asio::transfer_all (), - std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1)); + std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1)); } void I2PTunnelConnection::HandleConnect (const boost::system::error_code& ecode) @@ -231,8 +231,8 @@ namespace client memcpy (m_StreamBuffer, dest.c_str (), dest.size ()); } HandleStreamReceive (boost::system::error_code (), dest.size ()); - } - Receive (); + } + Receive (); } } @@ -253,20 +253,20 @@ namespace client { if (line == "\r") endOfHeader = true; else - { + { if (!m_ConnectionSent && !line.compare(0, 10, "Connection")) - { + { m_OutHeader << "Connection: close\r\n"; m_ConnectionSent = true; - } + } else if (!m_ProxyConnectionSent && !line.compare(0, 16, "Proxy-Connection")) - { + { m_OutHeader << "Proxy-Connection: close\r\n"; m_ProxyConnectionSent = true; - } + } else m_OutHeader << line << "\n"; - } + } } else break; @@ -283,10 +283,10 @@ namespace client I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ()); } } - } - + } + I2PServerTunnelConnectionHTTP::I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr stream, - std::shared_ptr socket, + std::shared_ptr socket, const boost::asio::ip::tcp::endpoint& target, const std::string& host): I2PTunnelConnection (owner, stream, socket, target), m_Host (host), m_HeaderSent (false), m_From (stream->GetRemoteIdentity ()) { @@ -297,7 +297,7 @@ namespace client if (m_HeaderSent) I2PTunnelConnection::Write (buf, len); else - { + { m_InHeader.clear (); m_InHeader.write ((const char *)buf, len); std::string line; @@ -309,12 +309,12 @@ namespace client { if (line == "\r") endOfHeader = true; else - { + { if (m_Host.length () > 0 && line.find ("Host:") != std::string::npos) m_OutHeader << "Host: " << m_Host << "\r\n"; // override host else m_OutHeader << line << "\n"; - } + } } else break; @@ -335,52 +335,52 @@ namespace client m_HeaderSent = true; I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ()); } - } + } } I2PTunnelConnectionIRC::I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr stream, - std::shared_ptr socket, - const boost::asio::ip::tcp::endpoint& target, const std::string& webircpass): - I2PTunnelConnection (owner, stream, socket, target), m_From (stream->GetRemoteIdentity ()), - m_NeedsWebIrc (webircpass.length() ? true : false), m_WebircPass (webircpass) - { - } + std::shared_ptr socket, + const boost::asio::ip::tcp::endpoint& target, const std::string& webircpass): + I2PTunnelConnection (owner, stream, socket, target), m_From (stream->GetRemoteIdentity ()), + m_NeedsWebIrc (webircpass.length() ? true : false), m_WebircPass (webircpass) + { + } - void I2PTunnelConnectionIRC::Write (const uint8_t * buf, size_t len) - { + void I2PTunnelConnectionIRC::Write (const uint8_t * buf, size_t len) + { m_OutPacket.str (""); - if (m_NeedsWebIrc) + if (m_NeedsWebIrc) { - m_NeedsWebIrc = false; - m_OutPacket << "WEBIRC " << m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()) << " " << GetSocket ()->local_endpoint ().address () << std::endl; - } + m_NeedsWebIrc = false; + m_OutPacket << "WEBIRC " << m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()) << " " << GetSocket ()->local_endpoint ().address () << std::endl; + } - m_InPacket.clear (); - m_InPacket.write ((const char *)buf, len); - - while (!m_InPacket.eof () && !m_InPacket.fail ()) - { + m_InPacket.clear (); + m_InPacket.write ((const char *)buf, len); + + while (!m_InPacket.eof () && !m_InPacket.fail ()) + { std::string line; - std::getline (m_InPacket, line); - if (line.length () == 0 && m_InPacket.eof ()) - m_InPacket.str (""); - auto pos = line.find ("USER"); - if (!pos) // start of line - { - pos = line.find (" "); - pos++; - pos = line.find (" ", pos); - pos++; - auto nextpos = line.find (" ", pos); - m_OutPacket << line.substr (0, pos); - m_OutPacket << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()); - m_OutPacket << line.substr (nextpos) << '\n'; - } + std::getline (m_InPacket, line); + if (line.length () == 0 && m_InPacket.eof ()) + m_InPacket.str (""); + auto pos = line.find ("USER"); + if (!pos) // start of line + { + pos = line.find (" "); + pos++; + pos = line.find (" ", pos); + pos++; + auto nextpos = line.find (" ", pos); + m_OutPacket << line.substr (0, pos); + m_OutPacket << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()); + m_OutPacket << line.substr (nextpos) << '\n'; + } else - m_OutPacket << line << '\n'; - } - I2PTunnelConnection::Write ((uint8_t *)m_OutPacket.str ().c_str (), m_OutPacket.str ().length ()); - } + m_OutPacket << line << '\n'; + } + I2PTunnelConnection::Write ((uint8_t *)m_OutPacket.str ().c_str (), m_OutPacket.str ().length ()); + } /* This handler tries to stablish a connection with the desired server and dies if it fails to do so */ @@ -389,7 +389,7 @@ namespace client public: I2PClientTunnelHandler (I2PClientTunnel * parent, i2p::data::IdentHash destination, int destinationPort, std::shared_ptr socket): - I2PServiceHandler(parent), m_DestinationIdentHash(destination), + I2PServiceHandler(parent), m_DestinationIdentHash(destination), m_DestinationPort (destinationPort), m_Socket(socket) {}; void Handle(); void Terminate(); @@ -402,8 +402,8 @@ namespace client void I2PClientTunnelHandler::Handle() { - GetOwner()->GetLocalDestination ()->CreateStream ( - std::bind (&I2PClientTunnelHandler::HandleStreamRequestComplete, shared_from_this(), std::placeholders::_1), + GetOwner()->CreateStream ( + std::bind (&I2PClientTunnelHandler::HandleStreamRequestComplete, shared_from_this(), std::placeholders::_1), m_DestinationIdentHash, m_DestinationPort); } @@ -436,12 +436,12 @@ namespace client Done(shared_from_this()); } - I2PClientTunnel::I2PClientTunnel (const std::string& name, const std::string& destination, - const std::string& address, int port, std::shared_ptr localDestination, int destinationPort): - TCPIPAcceptor (address, port, localDestination), m_Name (name), m_Destination (destination), - m_DestinationIdentHash (nullptr), m_DestinationPort (destinationPort) + I2PClientTunnel::I2PClientTunnel (const std::string& name, const std::string& destination, + const std::string& address, int port, std::shared_ptr localDestination, int destinationPort): + TCPIPAcceptor (address, port, localDestination), m_Name (name), m_Destination (destination), + m_DestinationIdentHash (nullptr), m_DestinationPort (destinationPort) { - } + } void I2PClientTunnel::Start () { @@ -480,8 +480,8 @@ namespace client return nullptr; } - I2PServerTunnel::I2PServerTunnel (const std::string& name, const std::string& address, - int port, std::shared_ptr localDestination, int inport, bool gzip): + I2PServerTunnel::I2PServerTunnel (const std::string& name, const std::string& address, + int port, std::shared_ptr localDestination, int inport, bool gzip): I2PService (localDestination), m_IsUniqueLocal(true), m_Name (name), m_Address (address), m_Port (port), m_IsAccessList (false) { m_PortDestination = localDestination->CreateStreamingDestination (inport > 0 ? inport : port, gzip); @@ -489,10 +489,10 @@ namespace client void I2PServerTunnel::Start () { - m_Endpoint.port (m_Port); + m_Endpoint.port (m_Port); boost::system::error_code ec; auto addr = boost::asio::ip::address::from_string (m_Address, ec); - if (!ec) + if (!ec) { m_Endpoint.address (addr); Accept (); @@ -500,27 +500,27 @@ namespace client else { auto resolver = std::make_shared(GetService ()); - resolver->async_resolve (boost::asio::ip::tcp::resolver::query (m_Address, ""), - std::bind (&I2PServerTunnel::HandleResolve, this, + resolver->async_resolve (boost::asio::ip::tcp::resolver::query (m_Address, ""), + std::bind (&I2PServerTunnel::HandleResolve, this, std::placeholders::_1, std::placeholders::_2, resolver)); - } + } } void I2PServerTunnel::Stop () { ClearHandlers (); - } + } - void I2PServerTunnel::HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, + void I2PServerTunnel::HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, std::shared_ptr resolver) - { + { if (!ecode) - { + { auto addr = (*it).endpoint ().address (); LogPrint (eLogInfo, "I2PTunnel: server tunnel ", (*it).host_name (), " has been resolved to ", addr); m_Endpoint.address (addr); - Accept (); - } + Accept (); + } else LogPrint (eLogError, "I2PTunnel: Unable to resolve server tunnel address: ", ecode.message ()); } @@ -528,7 +528,7 @@ namespace client void I2PServerTunnel::SetAccessList (const std::set& accessList) { m_AccessList = accessList; - m_IsAccessList = true; + m_IsAccessList = true; } void I2PServerTunnel::Accept () @@ -536,7 +536,7 @@ namespace client if (m_PortDestination) m_PortDestination->SetAcceptor (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1)); - auto localDestination = GetLocalDestination (); + auto localDestination = GetLocalDestination (); if (localDestination) { if (!localDestination->IsAcceptingStreams ()) // set it as default if not set yet @@ -549,7 +549,7 @@ namespace client void I2PServerTunnel::HandleAccept (std::shared_ptr stream) { if (stream) - { + { if (m_IsAccessList) { if (!m_AccessList.count (stream->GetRemoteIdentity ()->GetIdentHash ())) @@ -563,53 +563,53 @@ namespace client auto conn = CreateI2PConnection (stream); AddHandler (conn); conn->Connect (m_IsUniqueLocal); - } + } } std::shared_ptr I2PServerTunnel::CreateI2PConnection (std::shared_ptr stream) { return std::make_shared (this, stream, std::make_shared (GetService ()), GetEndpoint ()); - + } - I2PServerTunnelHTTP::I2PServerTunnelHTTP (const std::string& name, const std::string& address, - int port, std::shared_ptr localDestination, - const std::string& host, int inport, bool gzip): - I2PServerTunnel (name, address, port, localDestination, inport, gzip), + I2PServerTunnelHTTP::I2PServerTunnelHTTP (const std::string& name, const std::string& address, + int port, std::shared_ptr localDestination, + const std::string& host, int inport, bool gzip): + I2PServerTunnel (name, address, port, localDestination, inport, gzip), m_Host (host) { } std::shared_ptr I2PServerTunnelHTTP::CreateI2PConnection (std::shared_ptr stream) { - return std::make_shared (this, stream, + return std::make_shared (this, stream, std::make_shared (GetService ()), GetEndpoint (), m_Host); } - I2PServerTunnelIRC::I2PServerTunnelIRC (const std::string& name, const std::string& address, - int port, std::shared_ptr localDestination, - const std::string& webircpass, int inport, bool gzip): - I2PServerTunnel (name, address, port, localDestination, inport, gzip), - m_WebircPass (webircpass) - { - } + I2PServerTunnelIRC::I2PServerTunnelIRC (const std::string& name, const std::string& address, + int port, std::shared_ptr localDestination, + const std::string& webircpass, int inport, bool gzip): + I2PServerTunnel (name, address, port, localDestination, inport, gzip), + m_WebircPass (webircpass) + { + } - std::shared_ptr I2PServerTunnelIRC::CreateI2PConnection (std::shared_ptr stream) - { - return std::make_shared (this, stream, std::make_shared (GetService ()), GetEndpoint (), this->m_WebircPass); - } + std::shared_ptr I2PServerTunnelIRC::CreateI2PConnection (std::shared_ptr stream) + { + return std::make_shared (this, stream, std::make_shared (GetService ()), GetEndpoint (), this->m_WebircPass); + } - void I2PUDPServerTunnel::HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) - { - std::lock_guard lock(m_SessionsMutex); - auto session = ObtainUDPSession(from, toPort, fromPort); - session->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint); - session->LastActivity = i2p::util::GetMillisecondsSinceEpoch(); - } + void I2PUDPServerTunnel::HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) + { + std::lock_guard lock(m_SessionsMutex); + auto session = ObtainUDPSession(from, toPort, fromPort); + session->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint); + session->LastActivity = i2p::util::GetMillisecondsSinceEpoch(); + } - void I2PUDPServerTunnel::ExpireStale(const uint64_t delta) { - std::lock_guard lock(m_SessionsMutex); - uint64_t now = i2p::util::GetMillisecondsSinceEpoch(); + void I2PUDPServerTunnel::ExpireStale(const uint64_t delta) { + std::lock_guard lock(m_SessionsMutex); + uint64_t now = i2p::util::GetMillisecondsSinceEpoch(); auto itr = m_Sessions.begin(); while(itr != m_Sessions.end()) { if(now - (*itr)->LastActivity >= delta ) @@ -617,11 +617,11 @@ namespace client else ++itr; } - } + } void I2PUDPClientTunnel::ExpireStale(const uint64_t delta) { std::lock_guard lock(m_SessionsMutex); - uint64_t now = i2p::util::GetMillisecondsSinceEpoch(); + uint64_t now = i2p::util::GetMillisecondsSinceEpoch(); std::vector removePorts; for (const auto & s : m_Sessions) { if (now - s.second.second >= delta) @@ -630,40 +630,40 @@ namespace client for(auto port : removePorts) { m_Sessions.erase(port); } - } - + } + UDPSessionPtr I2PUDPServerTunnel::ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort) - { - auto ih = from.GetIdentHash(); - for (auto & s : m_Sessions ) - { - if ( s->Identity == ih) - { - /** found existing session */ - LogPrint(eLogDebug, "UDPServer: found session ", s->IPSocket.local_endpoint(), " ", ih.ToBase32()); - return s; - } - } + { + auto ih = from.GetIdentHash(); + for (auto & s : m_Sessions ) + { + if ( s->Identity == ih) + { + /** found existing session */ + LogPrint(eLogDebug, "UDPServer: found session ", s->IPSocket.local_endpoint(), " ", ih.ToBase32()); + return s; + } + } boost::asio::ip::address addr; /** create new udp session */ - if(m_IsUniqueLocal && m_LocalAddress.is_loopback()) + if(m_IsUniqueLocal && m_LocalAddress.is_loopback()) { auto ident = from.GetIdentHash(); addr = GetLoopbackAddressFor(ident); - } - else + } + else addr = m_LocalAddress; boost::asio::ip::udp::endpoint ep(addr, 0); - m_Sessions.push_back(std::make_shared(ep, m_LocalDest, m_RemoteEndpoint, &ih, localPort, remotePort)); + m_Sessions.push_back(std::make_shared(ep, m_LocalDest, m_RemoteEndpoint, &ih, localPort, remotePort)); auto & back = m_Sessions.back(); return back; - } + } - UDPSession::UDPSession(boost::asio::ip::udp::endpoint localEndpoint, - const std::shared_ptr & localDestination, - boost::asio::ip::udp::endpoint endpoint, const i2p::data::IdentHash * to, - uint16_t ourPort, uint16_t theirPort) : - m_Destination(localDestination->GetDatagramDestination()), + UDPSession::UDPSession(boost::asio::ip::udp::endpoint localEndpoint, + const std::shared_ptr & localDestination, + boost::asio::ip::udp::endpoint endpoint, const i2p::data::IdentHash * to, + uint16_t ourPort, uint16_t theirPort) : + m_Destination(localDestination->GetDatagramDestination()), IPSocket(localDestination->GetService(), localEndpoint), SendEndpoint(endpoint), LastActivity(i2p::util::GetMillisecondsSinceEpoch()), @@ -674,13 +674,12 @@ namespace client Receive(); } - void UDPSession::Receive() { LogPrint(eLogDebug, "UDPSession: Receive"); IPSocket.async_receive_from(boost::asio::buffer(m_Buffer, I2P_UDP_MAX_MTU), FromEndpoint, std::bind(&UDPSession::HandleReceived, this, std::placeholders::_1, std::placeholders::_2)); } - + void UDPSession::HandleReceived(const boost::system::error_code & ecode, std::size_t len) { if(!ecode) @@ -694,8 +693,6 @@ namespace client } } - - I2PUDPServerTunnel::I2PUDPServerTunnel(const std::string & name, std::shared_ptr localDestination, boost::asio::ip::address localAddress, boost::asio::ip::udp::endpoint forwardTo, uint16_t port) : m_IsUniqueLocal(true), @@ -713,7 +710,7 @@ namespace client { auto dgram = m_LocalDest->GetDatagramDestination(); if (dgram) dgram->ResetReceiver(); - + LogPrint(eLogInfo, "UDPServer: done"); } @@ -742,7 +739,7 @@ namespace client } return sessions; } - + I2PUDPClientTunnel::I2PUDPClientTunnel(const std::string & name, const std::string &remoteDest, boost::asio::ip::udp::endpoint localEndpoint, std::shared_ptr localDestination, @@ -759,13 +756,11 @@ namespace client { auto dgram = m_LocalDest->CreateDatagramDestination(); dgram->SetReceiver(std::bind(&I2PUDPClientTunnel::HandleRecvFromI2P, this, - std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3, std::placeholders::_4, - std::placeholders::_5)); + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4, + std::placeholders::_5)); } - - void I2PUDPClientTunnel::Start() { m_LocalDest->Start(); if (m_ResolveThread == nullptr) @@ -803,14 +798,14 @@ namespace client m_Sessions[remotePort].second = i2p::util::GetMillisecondsSinceEpoch(); RecvFromLocal(); } - + std::vector > I2PUDPClientTunnel::GetSessions() { // TODO: implement std::vector > infos; return infos; } - + void I2PUDPClientTunnel::TryResolving() { LogPrint(eLogInfo, "UDP Tunnel: Trying to resolve ", m_RemoteDest); i2p::data::IdentHash * h = new i2p::data::IdentHash; @@ -846,11 +841,10 @@ namespace client } } else - LogPrint(eLogWarning, "UDP Client: not tracking udp session using port ", (int) toPort); + LogPrint(eLogWarning, "UDP Client: not tracking udp session using port ", (int) toPort); } else LogPrint(eLogWarning, "UDP Client: unwarrented traffic from ", from.GetIdentHash().ToBase32()); - } I2PUDPClientTunnel::~I2PUDPClientTunnel() { @@ -858,7 +852,7 @@ namespace client if (dgram) dgram->ResetReceiver(); m_Sessions.clear(); - + if(m_LocalSocket.is_open()) m_LocalSocket.close(); diff --git a/libi2pd_client/I2PTunnel.h b/libi2pd_client/I2PTunnel.h index dd78d0fe..1bdf8bb5 100644 --- a/libi2pd_client/I2PTunnel.h +++ b/libi2pd_client/I2PTunnel.h @@ -29,7 +29,6 @@ namespace client class I2PTunnelConnection: public I2PServiceHandler, public std::enable_shared_from_this { public: - I2PTunnelConnection (I2PService * owner, std::shared_ptr socket, std::shared_ptr leaseSet, int port = 0); // to I2P I2PTunnelConnection (I2PService * owner, std::shared_ptr socket, @@ -41,7 +40,6 @@ namespace client void Connect (bool isUniqueLocal = true); protected: - void Terminate (); void Receive (); @@ -56,7 +54,6 @@ namespace client std::shared_ptr GetSocket () const { return m_Socket; }; private: - uint8_t m_Buffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE], m_StreamBuffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE]; std::shared_ptr m_Socket; std::shared_ptr m_Stream; @@ -67,18 +64,15 @@ namespace client class I2PClientTunnelConnectionHTTP: public I2PTunnelConnection { public: - I2PClientTunnelConnectionHTTP (I2PService * owner, std::shared_ptr socket, std::shared_ptr stream): I2PTunnelConnection (owner, socket, stream), m_HeaderSent (false), m_ConnectionSent (false), m_ProxyConnectionSent (false) {}; protected: - void Write (const uint8_t * buf, size_t len); private: - std::stringstream m_InHeader, m_OutHeader; bool m_HeaderSent, m_ConnectionSent, m_ProxyConnectionSent; }; @@ -86,17 +80,14 @@ namespace client class I2PServerTunnelConnectionHTTP: public I2PTunnelConnection { public: - I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr stream, std::shared_ptr socket, const boost::asio::ip::tcp::endpoint& target, const std::string& host); protected: - void Write (const uint8_t * buf, size_t len); private: - std::string m_Host; std::stringstream m_InHeader, m_OutHeader; bool m_HeaderSent; @@ -104,35 +95,30 @@ namespace client }; class I2PTunnelConnectionIRC: public I2PTunnelConnection - { - public: + { + public: + I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr stream, + std::shared_ptr socket, + const boost::asio::ip::tcp::endpoint& target, const std::string& m_WebircPass); - I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr stream, - std::shared_ptr socket, - const boost::asio::ip::tcp::endpoint& target, const std::string& m_WebircPass); + protected: + void Write (const uint8_t * buf, size_t len); - protected: - - void Write (const uint8_t * buf, size_t len); - - private: - - std::shared_ptr m_From; - std::stringstream m_OutPacket, m_InPacket; + private: + std::shared_ptr m_From; + std::stringstream m_OutPacket, m_InPacket; bool m_NeedsWebIrc; - std::string m_WebircPass; - }; + std::string m_WebircPass; + }; class I2PClientTunnel: public TCPIPAcceptor { protected: - // Implements TCPIPAcceptor std::shared_ptr CreateHandler(std::shared_ptr socket); public: - I2PClientTunnel (const std::string& name, const std::string& destination, const std::string& address, int port, std::shared_ptr localDestination, int destinationPort = 0); ~I2PClientTunnel () {} @@ -143,11 +129,9 @@ namespace client const char* GetName() { return m_Name.c_str (); } private: - const i2p::data::IdentHash * GetIdentHash (); private: - std::string m_Name, m_Destination; const i2p::data::IdentHash * m_DestinationIdentHash; int m_DestinationPort; @@ -208,11 +192,11 @@ namespace client /** server side udp tunnel, many i2p inbound to 1 ip outbound */ class I2PUDPServerTunnel - { + { public: I2PUDPServerTunnel(const std::string & name, std::shared_ptr localDestination, - boost::asio::ip::address localAddress, + boost::asio::ip::address localAddress, boost::asio::ip::udp::endpoint forwardTo, uint16_t port); ~I2PUDPServerTunnel(); /** expire stale udp conversations */ @@ -225,7 +209,6 @@ namespace client void SetUniqueLocal(bool isUniqueLocal = true) { m_IsUniqueLocal = isUniqueLocal; } private: - void HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); UDPSessionPtr ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort); @@ -256,22 +239,22 @@ namespace client void ExpireStale(const uint64_t delta=I2P_UDP_SESSION_TIMEOUT); private: - typedef std::pair UDPConvo; - void RecvFromLocal(); - void HandleRecvFromLocal(const boost::system::error_code & e, std::size_t transferred); + typedef std::pair UDPConvo; + void RecvFromLocal(); + void HandleRecvFromLocal(const boost::system::error_code & e, std::size_t transferred); void HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); void TryResolving(); const std::string m_Name; - std::mutex m_SessionsMutex; - std::map m_Sessions; // maps i2p port -> local udp convo + std::mutex m_SessionsMutex; + std::map m_Sessions; // maps i2p port -> local udp convo const std::string m_RemoteDest; std::shared_ptr m_LocalDest; const boost::asio::ip::udp::endpoint m_LocalEndpoint; i2p::data::IdentHash * m_RemoteIdent; std::thread * m_ResolveThread; - boost::asio::ip::udp::socket m_LocalSocket; - boost::asio::ip::udp::endpoint m_RecvEndpoint; - uint8_t m_RecvBuff[I2P_UDP_MAX_MTU]; + boost::asio::ip::udp::socket m_LocalSocket; + boost::asio::ip::udp::endpoint m_RecvEndpoint; + uint8_t m_RecvBuff[I2P_UDP_MAX_MTU]; uint16_t RemotePort; bool m_cancel_resolve; }; @@ -279,7 +262,6 @@ namespace client class I2PServerTunnel: public I2PService { public: - I2PServerTunnel (const std::string& name, const std::string& address, int port, std::shared_ptr localDestination, int inport = 0, bool gzip = true); @@ -298,10 +280,9 @@ namespace client const char* GetName() { return m_Name.c_str (); } - void SetMaxConnsPerMinute(const uint32_t conns) { m_PortDestination->SetMaxConnsPerMinute(conns); } - - private: + void SetMaxConnsPerMinute(const uint32_t conns) { m_PortDestination->SetMaxConnsPerMinute(conns); } + private: void HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, std::shared_ptr resolver); @@ -310,7 +291,6 @@ namespace client virtual std::shared_ptr CreateI2PConnection (std::shared_ptr stream); private: - bool m_IsUniqueLocal; std::string m_Name, m_Address; int m_Port; @@ -323,37 +303,30 @@ namespace client class I2PServerTunnelHTTP: public I2PServerTunnel { public: - I2PServerTunnelHTTP (const std::string& name, const std::string& address, int port, std::shared_ptr localDestination, const std::string& host, - int inport = 0, bool gzip = true); + int inport = 0, bool gzip = true); private: - std::shared_ptr CreateI2PConnection (std::shared_ptr stream); private: - std::string m_Host; }; - class I2PServerTunnelIRC: public I2PServerTunnel - { - public: + class I2PServerTunnelIRC: public I2PServerTunnel + { + public: + I2PServerTunnelIRC (const std::string& name, const std::string& address, int port, + std::shared_ptr localDestination, const std::string& webircpass, + int inport = 0, bool gzip = true); - I2PServerTunnelIRC (const std::string& name, const std::string& address, int port, - std::shared_ptr localDestination, const std::string& webircpass, - int inport = 0, bool gzip = true); - - private: - - std::shared_ptr CreateI2PConnection (std::shared_ptr stream); - - private: - - std::string m_WebircPass; - }; + private: + std::shared_ptr CreateI2PConnection (std::shared_ptr stream); + private: + std::string m_WebircPass; + }; } } diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 7fcf8fbf..25aec108 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -692,8 +692,9 @@ namespace client } else { - boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred), - std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1)); + if (m_SocketType != eSAMSocketTypeTerminated) // check for possible race condition with Terminate() + boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred), + std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1)); } } diff --git a/qt/i2pd_qt/ClientTunnelPane.cpp b/qt/i2pd_qt/ClientTunnelPane.cpp index 9fc00509..256d0510 100644 --- a/qt/i2pd_qt/ClientTunnelPane.cpp +++ b/qt/i2pd_qt/ClientTunnelPane.cpp @@ -3,14 +3,15 @@ #include "SignatureTypeComboboxFactory.h" #include "QVBoxLayout" -ClientTunnelPane::ClientTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ClientTunnelConfig* tunconf): - TunnelPane(tunnelsPageUpdateListener, tunconf) {} +ClientTunnelPane::ClientTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ClientTunnelConfig* tunconf, QWidget* wrongInputPane_, QLabel* wrongInputLabel_, MainWindow* mainWindow): + TunnelPane(tunnelsPageUpdateListener, tunconf, wrongInputPane_, wrongInputLabel_, mainWindow) {} void ClientTunnelPane::setGroupBoxTitle(const QString & title) { clientTunnelNameGroupBox->setTitle(title); } void ClientTunnelPane::deleteClientTunnelForm() { + TunnelPane::deleteTunnelForm(); delete clientTunnelNameGroupBox; clientTunnelNameGroupBox=nullptr; @@ -179,6 +180,9 @@ int ClientTunnelPane::appendClientTunnelForm( QObject::connect(sigTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updated())); horizontalLayout_2->addWidget(sigTypeComboBox); + QPushButton * lockButton2 = new QPushButton(gridLayoutWidget_2); + horizontalLayout_2->addWidget(lockButton2); + widgetlocks.add(new widgetlock(sigTypeComboBox, lockButton2)); QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); horizontalLayout_2->addItem(horizontalSpacer); tunnelGridLayout->addLayout(horizontalLayout_2); diff --git a/qt/i2pd_qt/ClientTunnelPane.h b/qt/i2pd_qt/ClientTunnelPane.h index 7052211a..c2e076b7 100644 --- a/qt/i2pd_qt/ClientTunnelPane.h +++ b/qt/i2pd_qt/ClientTunnelPane.h @@ -14,7 +14,7 @@ class TunnelPane; class ClientTunnelPane : public TunnelPane { Q_OBJECT public: - ClientTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ClientTunnelConfig* tunconf); + ClientTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ClientTunnelConfig* tunconf, QWidget* wrongInputPane_, QLabel* wrongInputLabel_, MainWindow* mainWindow); virtual ~ClientTunnelPane(){} virtual ServerTunnelPane* asServerTunnelPane(); virtual ClientTunnelPane* asClientTunnelPane(); @@ -68,6 +68,7 @@ private: } protected: virtual bool applyDataFromUIToTunnelConfig() { + QString cannotSaveSettings = QApplication::tr("Cannot save settings."); bool ok=TunnelPane::applyDataFromUIToTunnelConfig(); if(!ok)return false; ClientTunnelConfig* ctc=tunnelConfig->asClientTunnelConfig(); @@ -78,16 +79,23 @@ protected: auto portStr=portLineEdit->text(); int portInt=portStr.toInt(&ok); - if(!ok)return false; + + if(!ok){ + highlightWrongInput(QApplication::tr("Bad port, must be int.")+" "+cannotSaveSettings,portLineEdit); + return false; + } ctc->setport(portInt); ctc->setkeys(keysLineEdit->text().toStdString()); ctc->setaddress(addressLineEdit->text().toStdString()); - auto dportStr=portLineEdit->text(); + auto dportStr=destinationPortLineEdit->text(); int dportInt=dportStr.toInt(&ok); - if(!ok)return false; + if(!ok){ + highlightWrongInput(QApplication::tr("Bad destinationPort, must be int.")+" "+cannotSaveSettings,destinationPortLineEdit); + return false; + } ctc->setdestinationPort(dportInt); ctc->setsigType(readSigTypeComboboxUI(sigTypeComboBox)); diff --git a/qt/i2pd_qt/ServerTunnelPane.cpp b/qt/i2pd_qt/ServerTunnelPane.cpp index d185be28..029a3ea2 100644 --- a/qt/i2pd_qt/ServerTunnelPane.cpp +++ b/qt/i2pd_qt/ServerTunnelPane.cpp @@ -2,8 +2,8 @@ #include "ClientContext.h" #include "SignatureTypeComboboxFactory.h" -ServerTunnelPane::ServerTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ServerTunnelConfig* tunconf): - TunnelPane(tunnelsPageUpdateListener, tunconf) {} +ServerTunnelPane::ServerTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ServerTunnelConfig* tunconf, QWidget* wrongInputPane_, QLabel* wrongInputLabel_, MainWindow* mainWindow): + TunnelPane(tunnelsPageUpdateListener, tunconf, wrongInputPane_, wrongInputLabel_, mainWindow) {} void ServerTunnelPane::setGroupBoxTitle(const QString & title) { serverTunnelNameGroupBox->setTitle(title); @@ -197,6 +197,9 @@ int ServerTunnelPane::appendServerTunnelForm( QObject::connect(sigTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updated())); horizontalLayout_2->addWidget(sigTypeComboBox); + QPushButton * lockButton2 = new QPushButton(gridLayoutWidget_2); + horizontalLayout_2->addWidget(lockButton2); + widgetlocks.add(new widgetlock(sigTypeComboBox, lockButton2)); QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); horizontalLayout_2->addItem(horizontalSpacer); tunnelGridLayout->addLayout(horizontalLayout_2); @@ -263,6 +266,7 @@ int ServerTunnelPane::appendServerTunnelForm( } void ServerTunnelPane::deleteServerTunnelForm() { + TunnelPane::deleteTunnelForm(); delete serverTunnelNameGroupBox;//->deleteLater(); serverTunnelNameGroupBox=nullptr; diff --git a/qt/i2pd_qt/ServerTunnelPane.h b/qt/i2pd_qt/ServerTunnelPane.h index 4069e339..556c8473 100644 --- a/qt/i2pd_qt/ServerTunnelPane.h +++ b/qt/i2pd_qt/ServerTunnelPane.h @@ -1,9 +1,6 @@ #ifndef SERVERTUNNELPANE_H #define SERVERTUNNELPANE_H -#include "TunnelPane.h" -#include "TunnelsPageUpdateListener.h" - #include #include #include @@ -23,6 +20,9 @@ #include "assert.h" +#include "TunnelPane.h" +#include "TunnelsPageUpdateListener.h" + class ServerTunnelConfig; class ClientTunnelPane; @@ -31,7 +31,7 @@ class ServerTunnelPane : public TunnelPane { Q_OBJECT public: - ServerTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ServerTunnelConfig* tunconf); + ServerTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ServerTunnelConfig* tunconf, QWidget* wrongInputPane_, QLabel* wrongInputLabel_, MainWindow* mainWindow); virtual ~ServerTunnelPane(){} virtual ServerTunnelPane* asServerTunnelPane(); @@ -119,6 +119,7 @@ private: protected: virtual bool applyDataFromUIToTunnelConfig() { + QString cannotSaveSettings = QApplication::tr("Cannot save settings."); bool ok=TunnelPane::applyDataFromUIToTunnelConfig(); if(!ok)return false; ServerTunnelConfig* stc=tunnelConfig->asServerTunnelConfig(); @@ -127,14 +128,20 @@ protected: auto portStr=portLineEdit->text(); int portInt=portStr.toInt(&ok); - if(!ok)return false; + if(!ok){ + highlightWrongInput(QApplication::tr("Bad port, must be int.")+" "+cannotSaveSettings,portLineEdit); + return false; + } stc->setport(portInt); stc->setkeys(keysLineEdit->text().toStdString()); auto str=inPortLineEdit->text(); int inPortInt=str.toInt(&ok); - if(!ok)return false; + if(!ok){ + highlightWrongInput(QApplication::tr("Bad inPort, must be int.")+" "+cannotSaveSettings,inPortLineEdit); + return false; + } stc->setinPort(inPortInt); stc->setaccessList(accessListLineEdit->text().toStdString()); @@ -147,7 +154,10 @@ protected: auto mcStr=maxConnsLineEdit->text(); uint32_t mcInt=(uint32_t)mcStr.toInt(&ok); - if(!ok)return false; + if(!ok){ + highlightWrongInput(QApplication::tr("Bad maxConns, must be int.")+" "+cannotSaveSettings,maxConnsLineEdit); + return false; + } stc->setmaxConns(mcInt); stc->setgzip(gzipCheckBox->isChecked()); diff --git a/qt/i2pd_qt/TunnelConfig.cpp b/qt/i2pd_qt/TunnelConfig.cpp index 0de17486..81216c0b 100644 --- a/qt/i2pd_qt/TunnelConfig.cpp +++ b/qt/i2pd_qt/TunnelConfig.cpp @@ -6,12 +6,25 @@ void TunnelConfig::saveHeaderToStringStream(std::stringstream& out) { } void TunnelConfig::saveI2CPParametersToStringStream(std::stringstream& out) { - out << "inbound.length=" << i2cpParameters.getInbound_length().toStdString() << "\n" - << "outbound.length=" << i2cpParameters.getOutbound_length().toStdString() << "\n" - << "inbound.quantity=" << i2cpParameters.getInbound_quantity().toStdString() << "\n" - << "outbound.quantity=" << i2cpParameters.getOutbound_quantity().toStdString() << "\n" - << "crypto.tagsToSend=" << i2cpParameters.getCrypto_tagsToSend().toStdString() << "\n" - << "explicitPeers=" << i2cpParameters.getExplicitPeers().toStdString() << "\n\n"; + if (i2cpParameters.getInbound_length().toUShort() != i2p::client::DEFAULT_INBOUND_TUNNEL_LENGTH) + out << i2p::client::I2CP_PARAM_INBOUND_TUNNEL_LENGTH << "=" + << i2cpParameters.getInbound_length().toStdString() << "\n"; + if (i2cpParameters.getOutbound_length().toUShort() != i2p::client::DEFAULT_OUTBOUND_TUNNEL_LENGTH) + out << i2p::client::I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH << "=" + << i2cpParameters.getOutbound_length().toStdString() << "\n"; + if (i2cpParameters.getInbound_quantity().toUShort() != i2p::client::DEFAULT_INBOUND_TUNNELS_QUANTITY) + out << i2p::client::I2CP_PARAM_INBOUND_TUNNELS_QUANTITY << "=" + << i2cpParameters.getInbound_quantity().toStdString() << "\n"; + if (i2cpParameters.getOutbound_quantity().toUShort() != i2p::client::DEFAULT_OUTBOUND_TUNNELS_QUANTITY) + out << i2p::client::I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY << "=" + << i2cpParameters.getOutbound_quantity().toStdString() << "\n"; + if (i2cpParameters.getCrypto_tagsToSend().toUShort() != i2p::client::DEFAULT_TAGS_TO_SEND) + out << i2p::client::I2CP_PARAM_TAGS_TO_SEND << "=" + << i2cpParameters.getCrypto_tagsToSend().toStdString() << "\n"; + if (!i2cpParameters.getExplicitPeers().isEmpty()) //todo #947 + out << i2p::client::I2CP_PARAM_EXPLICIT_PEERS << "=" + << i2cpParameters.getExplicitPeers().toStdString() << "\n"; + out << "\n"; } void ClientTunnelConfig::saveToStringStream(std::stringstream& out) { diff --git a/qt/i2pd_qt/TunnelConfig.h b/qt/i2pd_qt/TunnelConfig.h index 087ec30b..c714a4f5 100644 --- a/qt/i2pd_qt/TunnelConfig.h +++ b/qt/i2pd_qt/TunnelConfig.h @@ -5,6 +5,7 @@ #include #include "../../libi2pd_client/ClientContext.h" +#include "../../libi2pd/Destination.h" #include "TunnelsPageUpdateListener.h" diff --git a/qt/i2pd_qt/TunnelPane.cpp b/qt/i2pd_qt/TunnelPane.cpp index 0dda5185..fb840276 100644 --- a/qt/i2pd_qt/TunnelPane.cpp +++ b/qt/i2pd_qt/TunnelPane.cpp @@ -1,8 +1,14 @@ #include "TunnelPane.h" -#include "QMessageBox" -TunnelPane::TunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener_, TunnelConfig* tunnelConfig_): +#include "QMessageBox" +#include "mainwindow.h" +#include "ui_mainwindow.h" + +TunnelPane::TunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener_, TunnelConfig* tunnelConfig_, QWidget* wrongInputPane_, QLabel* wrongInputLabel_, MainWindow* mainWindow_): QObject(), + mainWindow(mainWindow_), + wrongInputPane(wrongInputPane_), + wrongInputLabel(wrongInputLabel_), tunnelConfig(tunnelConfig_), tunnelsPageUpdateListener(tunnelsPageUpdateListener_), gridLayoutWidget_2(nullptr) {} @@ -65,6 +71,9 @@ void TunnelPane::setupTunnelPane( typeLabel->setObjectName(QStringLiteral("typeLabel")); horizontalLayout_->addWidget(typeLabel); horizontalLayout_->addWidget(tunnelTypeComboBox); + QPushButton * lockButton1 = new QPushButton(gridLayoutWidget_2); + horizontalLayout_->addWidget(lockButton1); + widgetlocks.add(new widgetlock(tunnelTypeComboBox, lockButton1)); this->tunnelTypeComboBox=tunnelTypeComboBox; QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); horizontalLayout_->addItem(horizontalSpacer); @@ -176,7 +185,9 @@ void TunnelPane::appendControlsForI2CPParameters(I2CPParameters& i2cpParameters, void TunnelPane::updated() { std::string oldName=tunnelConfig->getName(); - if(!applyDataFromUIToTunnelConfig())return;//TODO visualise bad input + //validate and show red if invalid + hideWrongInputLabel(); + if(!mainWindow->applyTunnelsUiToConfigs())return; tunnelsPageUpdateListener->updated(oldName, tunnelConfig); } @@ -189,6 +200,7 @@ void TunnelPane::deleteButtonReleased() { switch (ret) { case QMessageBox::Ok: // OK was clicked + hideWrongInputLabel(); tunnelsPageUpdateListener->needsDeleting(tunnelConfig->getName()); break; case QMessageBox::Cancel: @@ -215,3 +227,23 @@ QString TunnelPane::readTunnelTypeComboboxData() { i2p::data::SigningKeyType TunnelPane::readSigTypeComboboxUI(QComboBox* sigTypeComboBox) { return (i2p::data::SigningKeyType) sigTypeComboBox->currentData().toInt(); } + +void TunnelPane::deleteTunnelForm() { + widgetlocks.deleteListeners(); +} + +void TunnelPane::highlightWrongInput(QString warningText, QWidget* controlWithWrongInput) { + wrongInputPane->setVisible(true); + wrongInputLabel->setText(warningText); + mainWindow->adjustSizesAccordingToWrongLabel(); + if(controlWithWrongInput){ + mainWindow->ui->tunnelsScrollArea->ensureWidgetVisible(controlWithWrongInput); + controlWithWrongInput->setFocus(); + } + mainWindow->showTunnelsPage(); +} + +void TunnelPane::hideWrongInputLabel() const { + wrongInputPane->setVisible(false); + mainWindow->adjustSizesAccordingToWrongLabel(); +} diff --git a/qt/i2pd_qt/TunnelPane.h b/qt/i2pd_qt/TunnelPane.h index b7744555..a7012810 100644 --- a/qt/i2pd_qt/TunnelPane.h +++ b/qt/i2pd_qt/TunnelPane.h @@ -14,25 +14,39 @@ #include "TunnelConfig.h" +#include +#include + class ServerTunnelPane; class ClientTunnelPane; class TunnelConfig; class I2CPParameters; +class MainWindow; + class TunnelPane : public QObject { Q_OBJECT public: - TunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener_, TunnelConfig* tunconf); + TunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener_, TunnelConfig* tunconf, QWidget* wrongInputPane_, QLabel* wrongInputLabel_, MainWindow* mainWindow_); virtual ~TunnelPane(){} + void deleteTunnelForm(); + + void hideWrongInputLabel() const; + void highlightWrongInput(QString warningText, QWidget* controlWithWrongInput); + virtual ServerTunnelPane* asServerTunnelPane()=0; virtual ClientTunnelPane* asClientTunnelPane()=0; protected: + MainWindow* mainWindow; + QWidget * wrongInputPane; + QLabel* wrongInputLabel; TunnelConfig* tunnelConfig; + widgetlockregistry widgetlocks; TunnelsPageUpdateListener* tunnelsPageUpdateListener; QVBoxLayout *tunnelGridLayout; QGroupBox *tunnelGroupBox; @@ -78,6 +92,7 @@ protected: //should be created by factory i2p::data::SigningKeyType readSigTypeComboboxUI(QComboBox* sigTypeComboBox); +public: //returns false when invalid data at UI virtual bool applyDataFromUIToTunnelConfig() { tunnelConfig->setName(nameLineEdit->text().toStdString()); @@ -90,7 +105,7 @@ protected: i2cpParams.setCrypto_tagsToSend(crypto_tagsToSendLineEdit->text()); return true; } - +protected: void setupTunnelPane( TunnelConfig* tunnelConfig, QGroupBox *tunnelGroupBox, diff --git a/qt/i2pd_qt/generalsettingswidget.ui b/qt/i2pd_qt/generalsettingswidget.ui new file mode 100644 index 00000000..a7f07e5d --- /dev/null +++ b/qt/i2pd_qt/generalsettingswidget.ui @@ -0,0 +1,2875 @@ + + + GeneralSettingsContentsForm + + + + 0 + 0 + 679 + 3033 + + + + + 0 + 0 + + + + GeneralSettingsContentsForm + + + + + 0 + 0 + 679 + 3052 + + + + + QLayout::SetMinAndMaxSize + + + + + + 0 + 0 + + + + + 0 + 51 + + + + + 16777215 + 51 + + + + Configuration file: + + + + + 0 + 18 + 661 + 31 + + + + + QLayout::SetMaximumSize + + + + + + + + + 0 + 0 + + + + + 0 + 27 + + + + + 16777215 + 27 + + + + Browse… + + + + + + + + + + + + 0 + 0 + + + + + 0 + 51 + + + + + 16777215 + 51 + + + + Tunnels configuration file: + + + + + 0 + 18 + 661 + 31 + + + + + QLayout::SetMaximumSize + + + + + + + + + 0 + 0 + + + + + 0 + 27 + + + + + 16777215 + 27 + + + + Browse… + + + + + + + + + + + + 0 + 0 + + + + + 0 + 51 + + + + + 16777215 + 51 + + + + Pid file: + + + + + 0 + 18 + 661 + 31 + + + + + QLayout::SetMaximumSize + + + + + + + + + 0 + 0 + + + + + 0 + 27 + + + + + 16777215 + 27 + + + + Browse… + + + + + + + + + + + + 0 + 98 + + + + + 16777215 + 98 + + + + SAM interface + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 60 + + + + + 16777215 + 60 + + + + + 13 + + + + Windows-specific options + + + + + + + + 0 + 44 + + + + + 16777215 + 44 + + + + Cryptography + + + + + 0 + 20 + 661 + 22 + + + + Use ElGamal precomputed tables + + + + + + + + + 0 + 107 + + + + + 16777215 + 107 + + + + Logging + + + Qt::AlignJustify|Qt::AlignTop + + + + + -1 + 19 + 661 + 91 + + + + + QLayout::SetMinimumSize + + + + + QLayout::SetMaximumSize + + + + + Destination: + + + + + + + + + + Edit + + + + + + + Log file: + + + + + + + + + + Browse… + + + + + + + + + QLayout::SetMinimumSize + + + + + + 0 + 0 + + + + Log level: + + + + + + + + Error + + + + + Warn + + + + + Info + + + + + Debug + + + + + + + + Edit + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 0 + 68 + + + + + 16777215 + 68 + + + + UPnP + + + + + 0 + 20 + 97 + 22 + + + + Enable + + + + + + 0 + 40 + 661 + 31 + + + + + + + Name i2pd appears in UPnP forwardings list: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 98 + + + + + 16777215 + 98 + + + + I2CP interface + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 98 + + + + + 16777215 + 98 + + + + BOB interface + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 60 + + + + + 16777215 + 60 + + + + + 13 + + + + General options + + + + + + + + 0 + 0 + + + + + 0 + 98 + + + + + 16777215 + 98 + + + + Router external address (for incoming connections) + + + Qt::AlignJustify|Qt::AlignTop + + + + + 0 + 20 + 661 + 81 + + + + + QLayout::SetMinAndMaxSize + + + + + QLayout::SetMinAndMaxSize + + + + + Host: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + QLayout::SetMinAndMaxSize + + + + + Port (leave 0 to auto-assign): + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 0 + 78 + + + + + 16777215 + 78 + + + + Addressbook settings + + + + + 0 + 20 + 661 + 31 + + + + + + + Addressbook default subscription URL for initial setup: + + + + + + + + + + + + 0 + 50 + 661 + 31 + + + + + + + Addressbook subscriptions URLs, separated by comma: + + + + + + + + + + + + + + + 0 + 280 + + + + + 16777215 + 280 + + + + HTTP proxy + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 100 + 661 + 31 + + + + + + + Keys file: + + + + + + + + + + Browse… + + + + + + + + + 0 + 160 + 661 + 31 + + + + + + + Inbound tunnels length: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 190 + 661 + 31 + + + + + + + Inbound tunnels quantity: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 220 + 661 + 31 + + + + + + + Outbound tunnels length: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 250 + 661 + 31 + + + + + + + Outbound tunnels quantity: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 130 + 661 + 31 + + + + + + + Signature type: + + + + + + + + + + Edit + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 60 + + + + + 16777215 + 60 + + + + + 13 + + + + Various options + + + + + + + + 0 + 51 + + + + + 16777215 + 51 + + + + Data folder (for storage of i2pd data — RI, keys, peer profiles, …): + + + + + 0 + 20 + 661 + 31 + + + + + QLayout::SetMaximumSize + + + + + + + + Browse… + + + + + + + + + + + + 0 + 0 + + + + + 0 + 215 + + + + + 16777215 + 215 + + + + Router options + + + + + 0 + 20 + 661 + 188 + + + + + + + Enable communication through ipv6 + + + + + + + Router will not accept transit tunnels at startup + + + + + + + Router will be floodfill + + + + + + + + + Bandwidth limit (integer or a letter): + + + + + + + + + + KBps + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Family (name of a family router belongs to): + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + QLayout::SetMaximumSize + + + + + NetID (network ID router belongs to. The main I2P ID is 2): + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 0 + 108 + + + + + 16777215 + 108 + + + + Limits + + + + + 0 + 20 + 661 + 31 + + + + + + + Maximum number of transit tunnels: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 50 + 661 + 31 + + + + + + + Maximum number of open files (0 — use system limit): + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 80 + 661 + 31 + + + + + + + Maximum size of core file in Kb (0 — use system limit): + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 98 + + + + + 16777215 + 98 + + + + Reseeding + + + + + 0 + 20 + 661 + 22 + + + + Request SU3 signature verification + + + + + + 0 + 40 + 661 + 31 + + + + + + + SU3 file to reseed from: + + + + + + + + + + Browse… + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Reseed URLs, separated by comma: + + + + + + + + + + + + + + + 0 + 170 + + + + + 16777215 + 170 + + + + Trust options + + + + + 0 + 20 + 661 + 21 + + + + Enable explicit trust options + + + + + + 390 + 40 + 271 + 23 + + + + + + + 0 + 40 + 391 + 42 + + + + Make direct I2P connections only to +routers in specified Family: + + + + + + 0 + 82 + 661 + 42 + + + + Make direct I2P connections only to routers specified here. +Comma separated list of base64 identities: + + + + + + 0 + 124 + 661 + 23 + + + + + + + 0 + 147 + 661 + 21 + + + + Should we hide our router from other routers? + + + + + + + + + 0 + 60 + + + + + 16777215 + 60 + + + + + 13 + + + + Ports + + + + + + + + 0 + 22 + + + + + 16777215 + 22 + + + + Insomnia (prevent system from sleeping) + + + + + + + + 0 + 189 + + + + + 16777215 + 189 + + + + I2PControl interface + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 100 + 661 + 31 + + + + + + + Password: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 130 + 661 + 31 + + + + + + + Certificate file: + + + + + + + + + + Browse… + + + + + + + + + 0 + 160 + 661 + 31 + + + + + + + Key file: + + + + + + + + + + Browse… + + + + + + + + + + + + 0 + 0 + + + + + 0 + 105 + + + + + 16777215 + 105 + + + + Websockets server + + + + + 0 + 20 + 85 + 21 + + + + Enable + + + + + + 0 + 40 + 661 + 31 + + + + + + + Address to bind websocket server on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to bind websocket server on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 179 + + + + + 16777215 + 179 + + + + HTTP webconsole + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 100 + 321 + 22 + + + + Enable basic HTTP auth + + + + + + 60 + 120 + 601 + 31 + + + + + + + Username: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 60 + 150 + 601 + 31 + + + + + + + Password: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 335 + + + + + 16777215 + 335 + + + + Socks proxy + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 100 + 661 + 31 + + + + + + + Keys file: + + + + + + + + + + Browse… + + + + + + + + + 0 + 160 + 661 + 31 + + + + + + + Inbound tunnels length: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 190 + 661 + 31 + + + + + + + Inbound tunnels quantity: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 220 + 661 + 31 + + + + + + + Outbound tunnels length: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 250 + 661 + 31 + + + + + + + Outbound tunnels quantity: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 280 + 661 + 31 + + + + + + + Outproxy address: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 310 + 661 + 31 + + + + + + + Outproxy port: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 130 + 661 + 31 + + + + + + + Signature type: + + + + + + + + + + Edit + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 66839ff5..78078904 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -87,7 +87,11 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \ ../../daemon/i2pd.cpp \ ../../daemon/I2PControl.cpp \ ../../daemon/UnixDaemon.cpp \ - ../../daemon/UPnP.cpp + ../../daemon/UPnP.cpp \ + textbrowsertweaked1.cpp \ + pagewithbackbutton.cpp \ + widgetlock.cpp \ + widgetlockregistry.cpp #qt creator does not handle this well #SOURCES += $$files(../../libi2pd/*.cpp) @@ -166,7 +170,11 @@ HEADERS += DaemonQT.h mainwindow.h \ ../../daemon/Daemon.h \ ../../daemon/HTTPServer.h \ ../../daemon/I2PControl.h \ - ../../daemon/UPnP.h + ../../daemon/UPnP.h \ + textbrowsertweaked1.h \ + pagewithbackbutton.h \ + widgetlock.h \ + widgetlockregistry.h INCLUDEPATH += ../../libi2pd INCLUDEPATH += ../../libi2pd_client @@ -174,10 +182,31 @@ INCLUDEPATH += ../../daemon INCLUDEPATH += . FORMS += mainwindow.ui \ - tunnelform.ui + tunnelform.ui \ + statusbuttons.ui \ + routercommandswidget.ui \ + generalsettingswidget.ui LIBS += -lz +macx { + message("using mac os x target") + BREWROOT=/usr/local + BOOSTROOT=$$BREWROOT/opt/boost + SSLROOT=$$BREWROOT/opt/libressl + UPNPROOT=$$BREWROOT/opt/miniupnpc + INCLUDEPATH += $$BOOSTROOT/include + INCLUDEPATH += $$SSLROOT/include + INCLUDEPATH += $$UPNPROOT/include + LIBS += $$SSLROOT/lib/libcrypto.a + LIBS += $$SSLROOT/lib/libssl.a + LIBS += $$BOOSTROOT/lib/libboost_system.a + LIBS += $$BOOSTROOT/lib/libboost_date_time.a + LIBS += $$BOOSTROOT/lib/libboost_filesystem.a + LIBS += $$BOOSTROOT/lib/libboost_program_options.a + LIBS += $$UPNPROOT/lib/libminiupnpc.a +} + android { message("Using Android settings") DEFINES += ANDROID=1 diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index 9d312fa0..93da099a 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -1,5 +1,12 @@ +#include +#include #include "mainwindow.h" #include "ui_mainwindow.h" +#include "ui_statusbuttons.h" +#include "ui_routercommandswidget.h" +#include "ui_generalsettingswidget.h" +#include +#include #include #include #include @@ -8,15 +15,15 @@ #include "Config.h" #include "FS.h" #include "Log.h" +#include "RouterContext.h" +#include "Transports.h" + +#include "HTTPServer.h" #ifndef ANDROID # include #endif -#include - -#include - #include "DaemonQT.h" #include "SignatureTypeComboboxFactory.h" @@ -27,7 +34,14 @@ MainWindow::MainWindow(QWidget *parent) : #ifndef ANDROID ,quitting(false) #endif + ,wasSelectingAtStatusMainPage(false) + ,showHiddenInfoStatusMainPage(false) ,ui(new Ui::MainWindow) + ,statusButtonsUI(new Ui::StatusButtonsForm) + ,routerCommandsUI(new Ui::routerCommandsWidget) + ,uiSettings(new Ui::GeneralSettingsContentsForm) + ,routerCommandsParent(new QWidget(this)) + ,widgetlocks() ,i2pController(nullptr) ,configItems() ,datadir() @@ -37,21 +51,31 @@ MainWindow::MainWindow(QWidget *parent) : { ui->setupUi(this); + statusButtonsUI->setupUi(ui->statusButtonsPane); + routerCommandsUI->setupUi(routerCommandsParent); + uiSettings->setupUi(ui->settingsContents); + routerCommandsParent->hide(); + ui->verticalLayout_2->addWidget(routerCommandsParent); + //,statusHtmlUI(new Ui::StatusHtmlPaneForm) + //statusHtmlUI->setupUi(lastStatusWidgetui->statusWidget); + ui->statusButtonsPane->setFixedSize(171,300); + ui->verticalLayout->setGeometry(QRect(0,0,171,ui->verticalLayout->geometry().height())); + //ui->statusButtonsPane->adjustSize(); + //ui->centralWidget->adjustSize(); setWindowTitle(QApplication::translate("AppTitle","I2PD")); //TODO handle resizes and change the below into resize() call - setFixedSize(width(), 480); - ui->centralWidget->setMinimumHeight(480); - ui->centralWidget->setMaximumHeight(480); + setFixedHeight(550); + ui->centralWidget->setFixedHeight(550); onResize(); ui->stackedWidget->setCurrentIndex(0); - ui->settingsScrollArea->resize(ui->settingsContentsGridLayout->sizeHint().width()+10,380); + ui->settingsScrollArea->resize(uiSettings->settingsContentsGridLayout->sizeHint().width()+10,380); QScrollBar* const barSett = ui->settingsScrollArea->verticalScrollBar(); - //QSize szSettContents = ui->settingsContentsGridLayout->minimumSize(); int w = 683; int h = 3060; ui->settingsContents->setFixedSize(w, h); + ui->settingsContents->setGeometry(QRect(0,0,w,h)); /* QPalette pal(palette()); @@ -59,17 +83,55 @@ MainWindow::MainWindow(QWidget *parent) : ui->settingsContents->setAutoFillBackground(true); ui->settingsContents->setPalette(pal); */ + QPalette pal(palette()); + pal.setColor(QPalette::Background, Qt::red); + ui->wrongInputLabel->setAutoFillBackground(true); + ui->wrongInputLabel->setPalette(pal); + ui->wrongInputLabel->setMaximumHeight(ui->wrongInputLabel->sizeHint().height()); + ui->wrongInputLabel->setVisible(false); - //ui->settingsScrollArea->adjustSize(); - /*ui->tunnelsScrollAreaWidgetContents->setFixedSize( - ui->tunnelsScrollArea->width() - barSett->width(), 0);*/ - + settingsTitleLabelNominalHeight = ui->settingsTitleLabel->height(); #ifndef ANDROID createActions(); createTrayIcon(); #endif - QObject::connect(ui->statusPagePushButton, SIGNAL(released()), this, SLOT(showStatusPage())); + textBrowser = new TextBrowserTweaked1(this); + //textBrowser->setOpenExternalLinks(false); + textBrowser->setOpenLinks(false); + /*textBrowser->setTextInteractionFlags(textBrowser->textInteractionFlags()| + Qt::LinksAccessibleByMouse|Qt::LinksAccessibleByKeyboard| + Qt::TextSelectableByMouse|Qt::TextSelectableByKeyboard);*/ + ui->verticalLayout_2->addWidget(textBrowser); + childTextBrowser = new TextBrowserTweaked1(this); + //childTextBrowser->setOpenExternalLinks(false); + childTextBrowser->setOpenLinks(false); + connect(textBrowser, SIGNAL(anchorClicked(const QUrl&)), this, SLOT(anchorClickedHandler(const QUrl&))); + pageWithBackButton = new PageWithBackButton(this, childTextBrowser); + ui->verticalLayout_2->addWidget(pageWithBackButton); + pageWithBackButton->hide(); + connect(pageWithBackButton, SIGNAL(backReleased()), this, SLOT(backClickedFromChild())); + scheduleStatusPageUpdates(); + + QObject::connect(ui->statusPagePushButton, SIGNAL(released()), this, SLOT(showStatusMainPage())); + showStatusMainPage(); + QObject::connect(statusButtonsUI->mainPagePushButton, SIGNAL(released()), this, SLOT(showStatusMainPage())); + QObject::connect(statusButtonsUI->routerCommandsPushButton, SIGNAL(released()), this, SLOT(showStatus_commands_Page())); + QObject::connect(statusButtonsUI->localDestinationsPushButton, SIGNAL(released()), this, SLOT(showStatus_local_destinations_Page())); + QObject::connect(statusButtonsUI->leasesetsPushButton, SIGNAL(released()), this, SLOT(showStatus_leasesets_Page())); + QObject::connect(statusButtonsUI->tunnelsPushButton, SIGNAL(released()), this, SLOT(showStatus_tunnels_Page())); + QObject::connect(statusButtonsUI->transitTunnelsPushButton, SIGNAL(released()), this, SLOT(showStatus_transit_tunnels_Page())); + QObject::connect(statusButtonsUI->transportsPushButton, SIGNAL(released()), this, SLOT(showStatus_transports_Page())); + QObject::connect(statusButtonsUI->i2pTunnelsPushButton, SIGNAL(released()), this, SLOT(showStatus_i2p_tunnels_Page())); + QObject::connect(statusButtonsUI->samSessionsPushButton, SIGNAL(released()), this, SLOT(showStatus_sam_sessions_Page())); + + QObject::connect(textBrowser, SIGNAL(mouseReleased()), this, SLOT(statusHtmlPageMouseReleased())); + QObject::connect(textBrowser, SIGNAL(selectionChanged()), this, SLOT(statusHtmlPageSelectionChanged())); + + QObject::connect(routerCommandsUI->runPeerTestPushButton, SIGNAL(released()), this, SLOT(runPeerTest())); + QObject::connect(routerCommandsUI->acceptTransitTunnelsPushButton, SIGNAL(released()), this, SLOT(enableTransit())); + QObject::connect(routerCommandsUI->declineTransitTunnelsPushButton, SIGNAL(released()), this, SLOT(disableTransit())); + QObject::connect(ui->settingsPagePushButton, SIGNAL(released()), this, SLOT(showSettingsPage())); QObject::connect(ui->tunnelsPagePushButton, SIGNAL(released()), this, SLOT(showTunnelsPage())); @@ -83,132 +145,145 @@ MainWindow::MainWindow(QWidget *parent) : # define OPTION(section,option,defaultValueGetter) ConfigOption(QString(section),QString(option)) - initFileChooser( OPTION("","conf",[](){return "";}), ui->configFileLineEdit, ui->configFileBrowsePushButton); - initFolderChooser( OPTION("","datadir",[]{return "";}), ui->dataFolderLineEdit, ui->dataFolderBrowsePushButton); - initFileChooser( OPTION("","tunconf",[](){return "";}), ui->tunnelsConfigFileLineEdit, ui->tunnelsConfigFileBrowsePushButton); + initFileChooser( OPTION("","conf",[](){return "";}), uiSettings->configFileLineEdit, uiSettings->configFileBrowsePushButton); + initFolderChooser( OPTION("","datadir",[]{return "";}), uiSettings->dataFolderLineEdit, uiSettings->dataFolderBrowsePushButton); + initFileChooser( OPTION("","tunconf",[](){return "";}), uiSettings->tunnelsConfigFileLineEdit, uiSettings->tunnelsConfigFileBrowsePushButton); - initFileChooser( OPTION("","pidfile",[]{return "";}), ui->pidFileLineEdit, ui->pidFileBrowsePushButton); - logOption=initNonGUIOption( OPTION("","log",[]{return "";})); + initFileChooser( OPTION("","pidfile",[]{return "";}), uiSettings->pidFileLineEdit, uiSettings->pidFileBrowsePushButton); daemonOption=initNonGUIOption( OPTION("","daemon",[]{return "";})); serviceOption=initNonGUIOption( OPTION("","service",[]{return "";})); - logFileNameOption=initFileChooser( OPTION("","logfile",[]{return "";}), ui->logFileLineEdit, ui->logFileBrowsePushButton); - initLogLevelCombobox(OPTION("","loglevel",[]{return "";}), ui->logLevelComboBox); + uiSettings->logDestinationComboBox->clear(); + uiSettings->logDestinationComboBox->insertItems(0, QStringList() + << QApplication::translate("MainWindow", "stdout", 0) + << QApplication::translate("MainWindow", "file", 0) + ); + initLogDestinationCombobox( OPTION("","log",[]{return "";}), uiSettings->logDestinationComboBox); - initIPAddressBox( OPTION("","host",[]{return "";}), ui->routerExternalHostLineEdit, tr("Router external address -> Host")); - initTCPPortBox( OPTION("","port",[]{return "";}), ui->routerExternalPortLineEdit, tr("Router external address -> Port")); + logFileNameOption=initFileChooser( OPTION("","logfile",[]{return "";}), uiSettings->logFileLineEdit, uiSettings->logFileBrowsePushButton); + initLogLevelCombobox(OPTION("","loglevel",[]{return "";}), uiSettings->logLevelComboBox); - initCheckBox( OPTION("","ipv6",[]{return "false";}), ui->ipv6CheckBox); - initCheckBox( OPTION("","notransit",[]{return "false";}), ui->notransitCheckBox); - initCheckBox( OPTION("","floodfill",[]{return "false";}), ui->floodfillCheckBox); - initStringBox( OPTION("","bandwidth",[]{return "";}), ui->bandwidthLineEdit); - initStringBox( OPTION("","family",[]{return "";}), ui->familyLineEdit); - initIntegerBox( OPTION("","netid",[]{return "2";}), ui->netIdLineEdit, tr("NetID")); + initIPAddressBox( OPTION("","host",[]{return "";}), uiSettings->routerExternalHostLineEdit, tr("Router external address -> Host")); + initTCPPortBox( OPTION("","port",[]{return "";}), uiSettings->routerExternalPortLineEdit, tr("Router external address -> Port")); + + initCheckBox( OPTION("","ipv6",[]{return "false";}), uiSettings->ipv6CheckBox); + initCheckBox( OPTION("","notransit",[]{return "false";}), uiSettings->notransitCheckBox); + initCheckBox( OPTION("","floodfill",[]{return "false";}), uiSettings->floodfillCheckBox); + initStringBox( OPTION("","bandwidth",[]{return "";}), uiSettings->bandwidthLineEdit); + initStringBox( OPTION("","family",[]{return "";}), uiSettings->familyLineEdit); + initIntegerBox( OPTION("","netid",[]{return "2";}), uiSettings->netIdLineEdit, tr("NetID")); #ifdef Q_OS_WIN - initCheckBox( OPTION("","insomnia",[]{return "";}), ui->insomniaCheckBox); + initCheckBox( OPTION("","insomnia",[]{return "";}), uiSettings->insomniaCheckBox); initNonGUIOption( OPTION("","svcctl",[]{return "";})); initNonGUIOption( OPTION("","close",[]{return "";})); #else - ui->insomniaCheckBox->setEnabled(false); + uiSettings->insomniaCheckBox->setEnabled(false); #endif - initCheckBox( OPTION("http","enabled",[]{return "true";}), ui->webconsoleEnabledCheckBox); - initIPAddressBox( OPTION("http","address",[]{return "";}), ui->webconsoleAddrLineEdit, tr("HTTP webconsole -> IP address")); - initTCPPortBox( OPTION("http","port",[]{return "7070";}), ui->webconsolePortLineEdit, tr("HTTP webconsole -> Port")); - initCheckBox( OPTION("http","auth",[]{return "";}), ui->webconsoleBasicAuthCheckBox); - initStringBox( OPTION("http","user",[]{return "i2pd";}), ui->webconsoleUserNameLineEditBasicAuth); - initStringBox( OPTION("http","pass",[]{return "";}), ui->webconsolePasswordLineEditBasicAuth); + initCheckBox( OPTION("http","enabled",[]{return "true";}), uiSettings->webconsoleEnabledCheckBox); + initIPAddressBox( OPTION("http","address",[]{return "";}), uiSettings->webconsoleAddrLineEdit, tr("HTTP webconsole -> IP address")); + initTCPPortBox( OPTION("http","port",[]{return "7070";}), uiSettings->webconsolePortLineEdit, tr("HTTP webconsole -> Port")); + initCheckBox( OPTION("http","auth",[]{return "";}), uiSettings->webconsoleBasicAuthCheckBox); + initStringBox( OPTION("http","user",[]{return "i2pd";}), uiSettings->webconsoleUserNameLineEditBasicAuth); + initStringBox( OPTION("http","pass",[]{return "";}), uiSettings->webconsolePasswordLineEditBasicAuth); - initCheckBox( OPTION("httpproxy","enabled",[]{return "";}), ui->httpProxyEnabledCheckBox); - initIPAddressBox( OPTION("httpproxy","address",[]{return "";}), ui->httpProxyAddressLineEdit, tr("HTTP proxy -> IP address")); - initTCPPortBox( OPTION("httpproxy","port",[]{return "4444";}), ui->httpProxyPortLineEdit, tr("HTTP proxy -> Port")); - initFileChooser( OPTION("httpproxy","keys",[]{return "";}), ui->httpProxyKeyFileLineEdit, ui->httpProxyKeyFilePushButton); + initCheckBox( OPTION("httpproxy","enabled",[]{return "";}), uiSettings->httpProxyEnabledCheckBox); + initIPAddressBox( OPTION("httpproxy","address",[]{return "";}), uiSettings->httpProxyAddressLineEdit, tr("HTTP proxy -> IP address")); + initTCPPortBox( OPTION("httpproxy","port",[]{return "4444";}), uiSettings->httpProxyPortLineEdit, tr("HTTP proxy -> Port")); + initFileChooser( OPTION("httpproxy","keys",[]{return "";}), uiSettings->httpProxyKeyFileLineEdit, uiSettings->httpProxyKeyFilePushButton); - initSignatureTypeCombobox(OPTION("httpproxy","signaturetype",[]{return "7";}), ui->comboBox_httpPorxySignatureType); - initStringBox( OPTION("httpproxy","inbound.length",[]{return "3";}), ui->httpProxyInboundTunnelsLenLineEdit); - initStringBox( OPTION("httpproxy","inbound.quantity",[]{return "5";}), ui->httpProxyInboundTunnQuantityLineEdit); - initStringBox( OPTION("httpproxy","outbound.length",[]{return "3";}), ui->httpProxyOutBoundTunnLenLineEdit); - initStringBox( OPTION("httpproxy","outbound.quantity",[]{return "5";}), ui->httpProxyOutboundTunnQuantityLineEdit); + initSignatureTypeCombobox(OPTION("httpproxy","signaturetype",[]{return "7";}), uiSettings->comboBox_httpPorxySignatureType); + initStringBox( OPTION("httpproxy","inbound.length",[]{return "3";}), uiSettings->httpProxyInboundTunnelsLenLineEdit); + initStringBox( OPTION("httpproxy","inbound.quantity",[]{return "5";}), uiSettings->httpProxyInboundTunnQuantityLineEdit); + initStringBox( OPTION("httpproxy","outbound.length",[]{return "3";}), uiSettings->httpProxyOutBoundTunnLenLineEdit); + initStringBox( OPTION("httpproxy","outbound.quantity",[]{return "5";}), uiSettings->httpProxyOutboundTunnQuantityLineEdit); - initCheckBox( OPTION("socksproxy","enabled",[]{return "";}), ui->socksProxyEnabledCheckBox); - initIPAddressBox( OPTION("socksproxy","address",[]{return "";}), ui->socksProxyAddressLineEdit, tr("Socks proxy -> IP address")); - initTCPPortBox( OPTION("socksproxy","port",[]{return "4447";}), ui->socksProxyPortLineEdit, tr("Socks proxy -> Port")); - initFileChooser( OPTION("socksproxy","keys",[]{return "";}), ui->socksProxyKeyFileLineEdit, ui->socksProxyKeyFilePushButton); - initSignatureTypeCombobox(OPTION("socksproxy","signaturetype",[]{return "7";}), ui->comboBox_socksProxySignatureType); - initStringBox( OPTION("socksproxy","inbound.length",[]{return "";}), ui->socksProxyInboundTunnelsLenLineEdit); - initStringBox( OPTION("socksproxy","inbound.quantity",[]{return "";}), ui->socksProxyInboundTunnQuantityLineEdit); - initStringBox( OPTION("socksproxy","outbound.length",[]{return "";}), ui->socksProxyOutBoundTunnLenLineEdit); - initStringBox( OPTION("socksproxy","outbound.quantity",[]{return "";}), ui->socksProxyOutboundTunnQuantityLineEdit); - initIPAddressBox( OPTION("socksproxy","outproxy",[]{return "";}), ui->outproxyAddressLineEdit, tr("Socks proxy -> Outproxy address")); - initTCPPortBox( OPTION("socksproxy","outproxyport",[]{return "";}), ui->outproxyPortLineEdit, tr("Socks proxy -> Outproxy port")); + initCheckBox( OPTION("socksproxy","enabled",[]{return "";}), uiSettings->socksProxyEnabledCheckBox); + initIPAddressBox( OPTION("socksproxy","address",[]{return "";}), uiSettings->socksProxyAddressLineEdit, tr("Socks proxy -> IP address")); + initTCPPortBox( OPTION("socksproxy","port",[]{return "4447";}), uiSettings->socksProxyPortLineEdit, tr("Socks proxy -> Port")); + initFileChooser( OPTION("socksproxy","keys",[]{return "";}), uiSettings->socksProxyKeyFileLineEdit, uiSettings->socksProxyKeyFilePushButton); + initSignatureTypeCombobox(OPTION("socksproxy","signaturetype",[]{return "7";}), uiSettings->comboBox_socksProxySignatureType); + initStringBox( OPTION("socksproxy","inbound.length",[]{return "";}), uiSettings->socksProxyInboundTunnelsLenLineEdit); + initStringBox( OPTION("socksproxy","inbound.quantity",[]{return "";}), uiSettings->socksProxyInboundTunnQuantityLineEdit); + initStringBox( OPTION("socksproxy","outbound.length",[]{return "";}), uiSettings->socksProxyOutBoundTunnLenLineEdit); + initStringBox( OPTION("socksproxy","outbound.quantity",[]{return "";}), uiSettings->socksProxyOutboundTunnQuantityLineEdit); + initIPAddressBox( OPTION("socksproxy","outproxy",[]{return "";}), uiSettings->outproxyAddressLineEdit, tr("Socks proxy -> Outproxy address")); + initTCPPortBox( OPTION("socksproxy","outproxyport",[]{return "";}), uiSettings->outproxyPortLineEdit, tr("Socks proxy -> Outproxy port")); - initCheckBox( OPTION("sam","enabled",[]{return "false";}), ui->samEnabledCheckBox); - initIPAddressBox( OPTION("sam","address",[]{return "";}), ui->samAddressLineEdit, tr("SAM -> IP address")); - initTCPPortBox( OPTION("sam","port",[]{return "7656";}), ui->samPortLineEdit, tr("SAM -> Port")); + initCheckBox( OPTION("sam","enabled",[]{return "false";}), uiSettings->samEnabledCheckBox); + initIPAddressBox( OPTION("sam","address",[]{return "";}), uiSettings->samAddressLineEdit, tr("SAM -> IP address")); + initTCPPortBox( OPTION("sam","port",[]{return "7656";}), uiSettings->samPortLineEdit, tr("SAM -> Port")); - initCheckBox( OPTION("bob","enabled",[]{return "false";}), ui->bobEnabledCheckBox); - initIPAddressBox( OPTION("bob","address",[]{return "";}), ui->bobAddressLineEdit, tr("BOB -> IP address")); - initTCPPortBox( OPTION("bob","port",[]{return "2827";}), ui->bobPortLineEdit, tr("BOB -> Port")); + initCheckBox( OPTION("bob","enabled",[]{return "false";}), uiSettings->bobEnabledCheckBox); + initIPAddressBox( OPTION("bob","address",[]{return "";}), uiSettings->bobAddressLineEdit, tr("BOB -> IP address")); + initTCPPortBox( OPTION("bob","port",[]{return "2827";}), uiSettings->bobPortLineEdit, tr("BOB -> Port")); - initCheckBox( OPTION("i2cp","enabled",[]{return "false";}), ui->i2cpEnabledCheckBox); - initIPAddressBox( OPTION("i2cp","address",[]{return "";}), ui->i2cpAddressLineEdit, tr("I2CP -> IP address")); - initTCPPortBox( OPTION("i2cp","port",[]{return "7654";}), ui->i2cpPortLineEdit, tr("I2CP -> Port")); + initCheckBox( OPTION("i2cp","enabled",[]{return "false";}), uiSettings->i2cpEnabledCheckBox); + initIPAddressBox( OPTION("i2cp","address",[]{return "";}), uiSettings->i2cpAddressLineEdit, tr("I2CP -> IP address")); + initTCPPortBox( OPTION("i2cp","port",[]{return "7654";}), uiSettings->i2cpPortLineEdit, tr("I2CP -> Port")); - initCheckBox( OPTION("i2pcontrol","enabled",[]{return "false";}), ui->i2pControlEnabledCheckBox); - initIPAddressBox( OPTION("i2pcontrol","address",[]{return "";}), ui->i2pControlAddressLineEdit, tr("I2PControl -> IP address")); - initTCPPortBox( OPTION("i2pcontrol","port",[]{return "7650";}), ui->i2pControlPortLineEdit, tr("I2PControl -> Port")); - initStringBox( OPTION("i2pcontrol","password",[]{return "";}), ui->i2pControlPasswordLineEdit); - initFileChooser( OPTION("i2pcontrol","cert",[]{return "i2pcontrol.crt.pem";}), ui->i2pControlCertFileLineEdit, ui->i2pControlCertFileBrowsePushButton); - initFileChooser( OPTION("i2pcontrol","key",[]{return "i2pcontrol.key.pem";}), ui->i2pControlKeyFileLineEdit, ui->i2pControlKeyFileBrowsePushButton); + initCheckBox( OPTION("i2pcontrol","enabled",[]{return "false";}), uiSettings->i2pControlEnabledCheckBox); + initIPAddressBox( OPTION("i2pcontrol","address",[]{return "";}), uiSettings->i2pControlAddressLineEdit, tr("I2PControl -> IP address")); + initTCPPortBox( OPTION("i2pcontrol","port",[]{return "7650";}), uiSettings->i2pControlPortLineEdit, tr("I2PControl -> Port")); + initStringBox( OPTION("i2pcontrol","password",[]{return "";}), uiSettings->i2pControlPasswordLineEdit); + initFileChooser( OPTION("i2pcontrol","cert",[]{return "i2pcontrol.crt.pem";}), uiSettings->i2pControlCertFileLineEdit, uiSettings->i2pControlCertFileBrowsePushButton); + initFileChooser( OPTION("i2pcontrol","key",[]{return "i2pcontrol.key.pem";}), uiSettings->i2pControlKeyFileLineEdit, uiSettings->i2pControlKeyFileBrowsePushButton); - initCheckBox( OPTION("upnp","enabled",[]{return "true";}), ui->enableUPnPCheckBox); - initStringBox( OPTION("upnp","name",[]{return "I2Pd";}), ui->upnpNameLineEdit); + initCheckBox( OPTION("upnp","enabled",[]{return "true";}), uiSettings->enableUPnPCheckBox); + initStringBox( OPTION("upnp","name",[]{return "I2Pd";}), uiSettings->upnpNameLineEdit); - initCheckBox( OPTION("precomputation","elgamal",[]{return "false";}), ui->useElGamalPrecomputedTablesCheckBox); + initCheckBox( OPTION("precomputation","elgamal",[]{return "false";}), uiSettings->useElGamalPrecomputedTablesCheckBox); - initCheckBox( OPTION("reseed","verify",[]{return "";}), ui->reseedVerifyCheckBox); - initFileChooser( OPTION("reseed","file",[]{return "";}), ui->reseedFileLineEdit, ui->reseedFileBrowsePushButton); - initStringBox( OPTION("reseed","urls",[]{return "";}), ui->reseedURLsLineEdit); + initCheckBox( OPTION("reseed","verify",[]{return "";}), uiSettings->reseedVerifyCheckBox); + initFileChooser( OPTION("reseed","file",[]{return "";}), uiSettings->reseedFileLineEdit, uiSettings->reseedFileBrowsePushButton); + initStringBox( OPTION("reseed","urls",[]{return "";}), uiSettings->reseedURLsLineEdit); - initStringBox( OPTION("addressbook","defaulturl",[]{return "";}), ui->addressbookDefaultURLLineEdit); - initStringBox( OPTION("addressbook","subscriptions",[]{return "";}), ui->addressbookSubscriptionsURLslineEdit); + initStringBox( OPTION("addressbook","defaulturl",[]{return "";}), uiSettings->addressbookDefaultURLLineEdit); + initStringBox( OPTION("addressbook","subscriptions",[]{return "";}), uiSettings->addressbookSubscriptionsURLslineEdit); - initUInt16Box( OPTION("limits","transittunnels",[]{return "2500";}), ui->maxNumOfTransitTunnelsLineEdit, tr("maxNumberOfTransitTunnels")); - initUInt16Box( OPTION("limits","openfiles",[]{return "0";}), ui->maxNumOfOpenFilesLineEdit, tr("maxNumberOfOpenFiles")); - initUInt32Box( OPTION("limits","coresize",[]{return "0";}), ui->coreFileMaxSizeNumberLineEdit, tr("coreFileMaxSize")); + initUInt16Box( OPTION("limits","transittunnels",[]{return "2500";}), uiSettings->maxNumOfTransitTunnelsLineEdit, tr("maxNumberOfTransitTunnels")); + initUInt16Box( OPTION("limits","openfiles",[]{return "0";}), uiSettings->maxNumOfOpenFilesLineEdit, tr("maxNumberOfOpenFiles")); + initUInt32Box( OPTION("limits","coresize",[]{return "0";}), uiSettings->coreFileMaxSizeNumberLineEdit, tr("coreFileMaxSize")); - initCheckBox( OPTION("trust","enabled",[]{return "false";}), ui->checkBoxTrustEnable); - initStringBox( OPTION("trust","family",[]{return "";}), ui->lineEditTrustFamily); - initStringBox( OPTION("trust","routers",[]{return "";}), ui->lineEditTrustRouters); - initCheckBox( OPTION("trust","hidden",[]{return "false";}), ui->checkBoxTrustHidden); + initCheckBox( OPTION("trust","enabled",[]{return "false";}), uiSettings->checkBoxTrustEnable); + initStringBox( OPTION("trust","family",[]{return "";}), uiSettings->lineEditTrustFamily); + initStringBox( OPTION("trust","routers",[]{return "";}), uiSettings->lineEditTrustRouters); + initCheckBox( OPTION("trust","hidden",[]{return "false";}), uiSettings->checkBoxTrustHidden); - initCheckBox( OPTION("websockets","enabled",[]{return "false";}), ui->checkBoxWebsocketsEnable); - initIPAddressBox( OPTION("websockets","address",[]{return "127.0.0.1";}), ui->lineEdit_webSock_addr, tr("Websocket server -> IP address")); - initTCPPortBox( OPTION("websockets","port",[]{return "7666";}), ui->lineEdit_webSock_port, tr("Websocket server -> Port")); + 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)); + widgetlocks.add(new widgetlock(uiSettings->logDestinationComboBox,uiSettings->logDestComboEditPushButton)); + widgetlocks.add(new widgetlock(uiSettings->logLevelComboBox,uiSettings->logLevelComboEditPushButton)); + widgetlocks.add(new widgetlock(uiSettings->comboBox_httpPorxySignatureType,uiSettings->httpProxySignTypeComboEditPushButton)); + widgetlocks.add(new widgetlock(uiSettings->comboBox_socksProxySignatureType,uiSettings->socksProxySignTypeComboEditPushButton)); + loadAllConfigs(); - //tunnelsFormGridLayoutWidget = new QWidget(ui->tunnelsScrollAreaWidgetContents); - //tunnelsFormGridLayoutWidget->setObjectName(QStringLiteral("tunnelsFormGridLayoutWidget")); - //tunnelsFormGridLayoutWidget->setGeometry(QRect(0, 0, 621, 451)); + QObject::connect(uiSettings->logDestinationComboBox, SIGNAL(currentIndexChanged(const QString &)), + this, SLOT(logDestinationComboBoxValueChanged(const QString &))); + logDestinationComboBoxValueChanged(uiSettings->logDestinationComboBox->currentText()); + ui->tunnelsScrollAreaWidgetContents->setGeometry(QRect(0, 0, 621, 451)); appendTunnelForms(""); - ui->configFileLineEdit->setEnabled(false); - ui->configFileBrowsePushButton->setEnabled(false); - ui->configFileLineEdit->setText(confpath); - ui->tunnelsConfigFileLineEdit->setText(tunconfpath); + uiSettings->configFileLineEdit->setEnabled(false); + uiSettings->configFileBrowsePushButton->setEnabled(false); + uiSettings->configFileLineEdit->setText(confpath); + uiSettings->tunnelsConfigFileLineEdit->setText(tunconfpath); for(QList::iterator it = configItems.begin(); it!= configItems.end(); ++it) { MainWindowItem* item = *it; item->installListeners(this); } - QObject::connect(ui->tunnelsConfigFileLineEdit, SIGNAL(textChanged(const QString &)), + QObject::connect(uiSettings->tunnelsConfigFileLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(reloadTunnelsConfigAndUI())); QObject::connect(ui->addServerTunnelPushButton, SIGNAL(released()), this, SLOT(addServerTunnelPushButtonReleased())); @@ -226,11 +301,104 @@ MainWindow::MainWindow(QWidget *parent) : //QMetaObject::connectSlotsByName(this); } -void MainWindow::showStatusPage(){ui->stackedWidget->setCurrentIndex(0);} -void MainWindow::showSettingsPage(){ui->stackedWidget->setCurrentIndex(1);} -void MainWindow::showTunnelsPage(){ui->stackedWidget->setCurrentIndex(2);} -void MainWindow::showRestartPage(){ui->stackedWidget->setCurrentIndex(3);} -void MainWindow::showQuitPage(){ui->stackedWidget->setCurrentIndex(4);} +void MainWindow::logDestinationComboBoxValueChanged(const QString & text) { + bool stdout = text==QString("stdout"); + uiSettings->logFileLineEdit->setEnabled(!stdout); + uiSettings->logFileBrowsePushButton->setEnabled(!stdout); +} + + +void MainWindow::updateRouterCommandsButtons() { + bool acceptsTunnels = i2p::context.AcceptsTunnels (); + routerCommandsUI->declineTransitTunnelsPushButton->setEnabled(acceptsTunnels); + routerCommandsUI->acceptTransitTunnelsPushButton->setEnabled(!acceptsTunnels); +} + +void MainWindow::showStatusPage(StatusPage newStatusPage){ + ui->stackedWidget->setCurrentIndex(0); + setStatusButtonsVisible(true); + statusPage=newStatusPage; + showHiddenInfoStatusMainPage=false; + if(newStatusPage!=StatusPage::commands){ + textBrowser->setHtml(getStatusPageHtml(false)); + textBrowser->show(); + routerCommandsParent->hide(); + pageWithBackButton->hide(); + }else{ + routerCommandsParent->show(); + textBrowser->hide(); + pageWithBackButton->hide(); + updateRouterCommandsButtons(); + } + wasSelectingAtStatusMainPage=false; +} +void MainWindow::showSettingsPage(){ui->stackedWidget->setCurrentIndex(1);setStatusButtonsVisible(false);} +void MainWindow::showTunnelsPage(){ui->stackedWidget->setCurrentIndex(2);setStatusButtonsVisible(false);} +void MainWindow::showRestartPage(){ui->stackedWidget->setCurrentIndex(3);setStatusButtonsVisible(false);} +void MainWindow::showQuitPage(){ui->stackedWidget->setCurrentIndex(4);setStatusButtonsVisible(false);} + +void MainWindow::setStatusButtonsVisible(bool visible) { + ui->statusButtonsPane->setVisible(visible); +} + +// see also: HTTPServer.cpp +QString MainWindow::getStatusPageHtml(bool showHiddenInfo) { + std::stringstream s; + + s << ""; + + switch (statusPage) { + case main_page: i2p::http::ShowStatus(s, showHiddenInfo);break; + case commands: break; + case local_destinations: i2p::http::ShowLocalDestinations(s);break; + case leasesets: i2p::http::ShowLeasesSets(s); break; + case tunnels: i2p::http::ShowTunnels(s); break; + case transit_tunnels: i2p::http::ShowTransitTunnels(s); break; + case transports: i2p::http::ShowTransports(s); break; + case i2p_tunnels: i2p::http::ShowI2PTunnels(s); break; + case sam_sessions: i2p::http::ShowSAMSessions(s); break; + default: assert(false); break; + } + + std::string str = s.str(); + return QString::fromStdString(str); +} + +void MainWindow::showStatusMainPage() { showStatusPage(StatusPage::main_page); } +void MainWindow::showStatus_commands_Page() { showStatusPage(StatusPage::commands); } +void MainWindow::showStatus_local_destinations_Page() { showStatusPage(StatusPage::local_destinations); } +void MainWindow::showStatus_leasesets_Page() { showStatusPage(StatusPage::leasesets); } +void MainWindow::showStatus_tunnels_Page() { showStatusPage(StatusPage::tunnels); } +void MainWindow::showStatus_transit_tunnels_Page() { showStatusPage(StatusPage::transit_tunnels); } +void MainWindow::showStatus_transports_Page() { showStatusPage(StatusPage::transports); } +void MainWindow::showStatus_i2p_tunnels_Page() { showStatusPage(StatusPage::i2p_tunnels); } +void MainWindow::showStatus_sam_sessions_Page() { showStatusPage(StatusPage::sam_sessions); } + + +void MainWindow::scheduleStatusPageUpdates() { + statusPageUpdateTimer = new QTimer(this); + connect(statusPageUpdateTimer, SIGNAL(timeout()), this, SLOT(updateStatusPage())); + statusPageUpdateTimer->start(10*1000/*millis*/); +} + +void MainWindow::statusHtmlPageMouseReleased() { + if(wasSelectingAtStatusMainPage){ + QString selection = textBrowser->textCursor().selectedText(); + if(!selection.isEmpty()&&!selection.isNull())return; + } + showHiddenInfoStatusMainPage=!showHiddenInfoStatusMainPage; + textBrowser->setHtml(getStatusPageHtml(showHiddenInfoStatusMainPage)); +} + +void MainWindow::statusHtmlPageSelectionChanged() { + wasSelectingAtStatusMainPage=true; +} + +void MainWindow::updateStatusPage() { + showHiddenInfoStatusMainPage=false; + textBrowser->setHtml(getStatusPageHtml(showHiddenInfoStatusMainPage)); +} + //TODO void MainWindow::resizeEvent(QResizeEvent *event) @@ -352,6 +520,7 @@ void MainWindow::handleGracefulQuitTimerEvent() { MainWindow::~MainWindow() { qDebug("Destroying main window"); + delete statusPageUpdateTimer; for(QList::iterator it = configItems.begin(); it!= configItems.end(); ++it) { MainWindowItem* item = *it; item->deleteLater(); @@ -376,6 +545,9 @@ void MainWindow::initFolderChooser(ConfigOption option, QLineEdit* folderLineEdi configItems.append(new ComboBoxItem(option, comboBox)); QObject::connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(saveAllConfigs())); }*/ +void MainWindow::initLogDestinationCombobox(ConfigOption option, QComboBox* comboBox){ + configItems.append(new LogDestinationComboBoxItem(option, comboBox)); +} void MainWindow::initLogLevelCombobox(ConfigOption option, QComboBox* comboBox){ configItems.append(new LogLevelComboBoxItem(option, comboBox)); } @@ -401,7 +573,7 @@ void MainWindow::initUInt16Box(ConfigOption option, QLineEdit* numberLineEdit, Q configItems.append(new UInt16StringItem(option, numberLineEdit, fieldNameTranslated)); } void MainWindow::initStringBox(ConfigOption option, QLineEdit* lineEdit){ - configItems.append(new BaseStringItem(option, lineEdit)); + configItems.append(new BaseStringItem(option, lineEdit, QString())); } NonGUIOptionItem* MainWindow::initNonGUIOption(ConfigOption option) { NonGUIOptionItem * retValue; @@ -430,10 +602,7 @@ void MainWindow::loadAllConfigs(){ LogPrint(eLogWarning, "Daemon: please rename i2p.conf to i2pd.conf here: ", config); } else { config = i2p::fs::DataDirPath("i2pd.conf"); - if (!i2p::fs::Exists (config)) { - // use i2pd.conf only if exists - config = ""; /* reset */ - } + /*if (!i2p::fs::Exists (config)) {}*/ } } @@ -462,16 +631,20 @@ void MainWindow::loadAllConfigs(){ } /** returns false iff not valid items present and save was aborted */ bool MainWindow::saveAllConfigs(){ + QString cannotSaveSettings = QApplication::tr("Cannot save settings."); programOptionsWriterCurrentSection=""; - if(!logFileNameOption->lineEdit->text().trimmed().isEmpty())logOption->optionValue=boost::any(std::string("file")); - else logOption->optionValue=boost::any(std::string("stdout")); + /*if(!logFileNameOption->lineEdit->text().trimmed().isEmpty())logOption->optionValue=boost::any(std::string("file")); + else logOption->optionValue=boost::any(std::string("stdout"));*/ daemonOption->optionValue=boost::any(false); serviceOption->optionValue=boost::any(false); std::stringstream out; for(QList::iterator it = configItems.begin(); it!= configItems.end(); ++it) { MainWindowItem* item = *it; - if(!item->isValid()) return false; + if(!item->isValid()){ + highlightWrongInput(QApplication::tr("Invalid value for")+" "+item->getConfigOption().section+"::"+item->getConfigOption().option+". "+item->getRequirementToBeValid()+" "+cannotSaveSettings, item->getWidgetToFocus()); + return false; + } } for(QList::iterator it = configItems.begin(); it!= configItems.end(); ++it) { @@ -481,9 +654,10 @@ bool MainWindow::saveAllConfigs(){ using namespace std; + QString backup=confpath+"~"; if(QFile::exists(backup)) QFile::remove(backup);//TODO handle errors - QFile::rename(confpath, 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(); @@ -506,15 +680,22 @@ void FolderChooserItem::pushButtonReleased() { } void BaseStringItem::installListeners(MainWindow *mainWindow) { - QObject::connect(lineEdit, SIGNAL(textChanged(const QString &)), mainWindow, SLOT(saveAllConfigs())); + QObject::connect(lineEdit, SIGNAL(textChanged(const QString &)), mainWindow, SLOT(updated())); } void ComboBoxItem::installListeners(MainWindow *mainWindow) { - QObject::connect(comboBox, SIGNAL(currentIndexChanged(int)), mainWindow, SLOT(saveAllConfigs())); + QObject::connect(comboBox, SIGNAL(currentIndexChanged(int)), mainWindow, SLOT(updated())); } void CheckBoxItem::installListeners(MainWindow *mainWindow) { - QObject::connect(checkBox, SIGNAL(stateChanged(int)), mainWindow, SLOT(saveAllConfigs())); + QObject::connect(checkBox, SIGNAL(stateChanged(int)), mainWindow, SLOT(updated())); } +void MainWindow::updated() { + ui->wrongInputLabel->setVisible(false); + adjustSizesAccordingToWrongLabel(); + + applyTunnelsUiToConfigs(); + saveAllConfigs(); +} void MainWindowItem::installListeners(MainWindow *mainWindow) {} @@ -526,27 +707,33 @@ void MainWindow::appendTunnelForms(std::string tunnelNameToFocus) { TunnelConfig* tunconf = it->second; ServerTunnelConfig* stc = tunconf->asServerTunnelConfig(); if(stc){ - ServerTunnelPane * tunnelPane=new ServerTunnelPane(&tunnelsPageUpdateListener, stc); + ServerTunnelPane * tunnelPane=new ServerTunnelPane(&tunnelsPageUpdateListener, stc, ui->wrongInputLabel, ui->wrongInputLabel, this); int h=tunnelPane->appendServerTunnelForm(stc, ui->tunnelsScrollAreaWidgetContents, tunnelPanes.size(), height); height+=h; - qDebug() << "tun.height:" << height << "sz:" << tunnelPanes.size(); + //qDebug() << "tun.height:" << height << "sz:" << tunnelPanes.size(); tunnelPanes.push_back(tunnelPane); - if(name==tunnelNameToFocus)tunnelPane->getNameLineEdit()->setFocus(); + if(name==tunnelNameToFocus){ + tunnelPane->getNameLineEdit()->setFocus(); + ui->tunnelsScrollArea->ensureWidgetVisible(tunnelPane->getNameLineEdit()); + } continue; } ClientTunnelConfig* ctc = tunconf->asClientTunnelConfig(); if(ctc){ - ClientTunnelPane * tunnelPane=new ClientTunnelPane(&tunnelsPageUpdateListener, ctc); + ClientTunnelPane * tunnelPane=new ClientTunnelPane(&tunnelsPageUpdateListener, ctc, ui->wrongInputLabel, ui->wrongInputLabel, this); int h=tunnelPane->appendClientTunnelForm(ctc, ui->tunnelsScrollAreaWidgetContents, tunnelPanes.size(), height); height+=h; - qDebug() << "tun.height:" << height << "sz:" << tunnelPanes.size(); + //qDebug() << "tun.height:" << height << "sz:" << tunnelPanes.size(); tunnelPanes.push_back(tunnelPane); - if(name==tunnelNameToFocus)tunnelPane->getNameLineEdit()->setFocus(); + if(name==tunnelNameToFocus){ + tunnelPane->getNameLineEdit()->setFocus(); + ui->tunnelsScrollArea->ensureWidgetVisible(tunnelPane->getNameLineEdit()); + } continue; } throw "unknown TunnelConfig subtype"; } - qDebug() << "tun.setting height:" << height; + //qDebug() << "tun.setting height:" << height; ui->tunnelsScrollAreaWidgetContents->setGeometry(QRect(0, 0, 621, height)); QList childWidgets = ui->tunnelsScrollAreaWidgetContents->findChildren(); foreach(QWidget* widget, childWidgets) @@ -572,6 +759,14 @@ void MainWindow::deleteTunnelForms() { tunnelPanes.clear(); } +bool MainWindow::applyTunnelsUiToConfigs() { + for(std::list::iterator it = tunnelPanes.begin(); it != tunnelPanes.end(); ++it) { + TunnelPane* tp = *it; + if(!tp->applyDataFromUIToTunnelConfig())return false; + } + return true; +} + void MainWindow::reloadTunnelsConfigAndUI(std::string tunnelNameToFocus) { deleteTunnelForms(); for (std::map::iterator it=tunnelConfigs.begin(); it!=tunnelConfigs.end(); ++it) { @@ -598,12 +793,14 @@ void MainWindow::SaveTunnelsConfig() { QString backup=tunconfpath+"~"; if(QFile::exists(backup)) QFile::remove(backup);//TODO handle errors - QFile::rename(tunconfpath, 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) { @@ -613,7 +810,7 @@ void MainWindow::TunnelsPageUpdateListenerMainWindowImpl::updated(std::string ol if(it!=mainWindow->tunnelConfigs.end())mainWindow->tunnelConfigs.erase(it); mainWindow->tunnelConfigs[tunConf->getName()]=tunConf; } - mainWindow->SaveTunnelsConfig(); + mainWindow->saveAllConfigs(); } void MainWindow::TunnelsPageUpdateListenerMainWindowImpl::needsDeleting(std::string oldName){ @@ -631,3 +828,79 @@ void MainWindow::addClientTunnelPushButtonReleased() { void MainWindow::setI2PController(i2p::qt::Controller* controller_) { this->i2pController = controller_; } + +void MainWindow::runPeerTest() { + i2p::transport::transports.PeerTest(); +} + +void MainWindow::enableTransit() { + i2p::context.SetAcceptsTunnels(true); + updateRouterCommandsButtons(); +} + +void MainWindow::disableTransit() { + i2p::context.SetAcceptsTunnels(false); + updateRouterCommandsButtons(); +} + +void MainWindow::anchorClickedHandler(const QUrl & link) { + QString debugStr=QString()+"anchorClicked: "+"\""+link.toString()+"\""; + qDebug()<show(); + textBrowser->hide(); + std::stringstream s; + i2p::http::ShowLocalDestination(s,str.toStdString()); + childTextBrowser->setHtml(QString::fromStdString(s.str())); + } +} + +void MainWindow::backClickedFromChild() { + showStatusPage(statusPage); +} + +void MainWindow::adjustSizesAccordingToWrongLabel() { + if(ui->wrongInputLabel->isVisible()) { + int dh = ui->wrongInputLabel->height()+ui->verticalLayout_7->layout()->spacing(); + ui->verticalLayout_7->invalidate(); + ui->wrongInputLabel->adjustSize(); + ui->stackedWidget->adjustSize(); + ui->stackedWidget->setFixedHeight(531-dh); + ui->settingsPage->setFixedHeight(531-dh); + ui->verticalLayoutWidget_4->setGeometry(QRect(0, 0, 711, 531-dh)); + ui->stackedWidget->setFixedHeight(531-dh); + ui->settingsScrollArea->setFixedHeight(531-dh-settingsTitleLabelNominalHeight-ui->verticalLayout_4->spacing()); + ui->settingsTitleLabel->setFixedHeight(settingsTitleLabelNominalHeight); + ui->tunnelsScrollArea->setFixedHeight(531-dh-settingsTitleLabelNominalHeight-ui->horizontalLayout_42->geometry().height()-2*ui->verticalLayout_4->spacing()); + ui->tunnelsTitleLabel->setFixedHeight(settingsTitleLabelNominalHeight); + }else{ + ui->verticalLayout_7->invalidate(); + ui->wrongInputLabel->adjustSize(); + ui->stackedWidget->adjustSize(); + ui->stackedWidget->setFixedHeight(531); + ui->settingsPage->setFixedHeight(531); + ui->verticalLayoutWidget_4->setGeometry(QRect(0, 0, 711, 531)); + ui->stackedWidget->setFixedHeight(531); + ui->settingsScrollArea->setFixedHeight(531-settingsTitleLabelNominalHeight-ui->verticalLayout_4->spacing()); + ui->settingsTitleLabel->setFixedHeight(settingsTitleLabelNominalHeight); + ui->tunnelsScrollArea->setFixedHeight(531-settingsTitleLabelNominalHeight-ui->horizontalLayout_42->geometry().height()-2*ui->verticalLayout_4->spacing()); + ui->tunnelsTitleLabel->setFixedHeight(settingsTitleLabelNominalHeight); + } +} + +void MainWindow::highlightWrongInput(QString warningText, QWidget* widgetToFocus) { + bool redVisible = ui->wrongInputLabel->isVisible(); + ui->wrongInputLabel->setVisible(true); + ui->wrongInputLabel->setText(warningText); + if(!redVisible)adjustSizesAccordingToWrongLabel(); + if(widgetToFocus){ui->settingsScrollArea->ensureWidgetVisible(widgetToFocus);widgetToFocus->setFocus();} + showSettingsPage(); +} diff --git a/qt/i2pd_qt/mainwindow.h b/qt/i2pd_qt/mainwindow.h index 05cb7151..7e55a65f 100644 --- a/qt/i2pd_qt/mainwindow.h +++ b/qt/i2pd_qt/mainwindow.h @@ -24,6 +24,7 @@ #include #include #include "QVBoxLayout" +#include "QUrl" #ifndef ANDROID # include @@ -40,6 +41,7 @@ #include "ServerTunnelPane.h" #include "ClientTunnelPane.h" #include "TunnelConfig.h" +#include "textbrowsertweaked1.h" #include "Config.h" #include "FS.h" @@ -53,6 +55,12 @@ #include "DaemonQT.h" #include "SignatureTypeComboboxFactory.h" +#include "pagewithbackbutton.h" + +#include + +#include "widgetlockregistry.h" +#include "widgetlock.h" template bool isType(boost::any& a) { @@ -85,8 +93,13 @@ class MainWindow; class MainWindowItem : public QObject { Q_OBJECT ConfigOption option; + QWidget* widgetToFocus; + QString requirementToBeValid; public: - MainWindowItem(ConfigOption option_) : option(option_) {} + MainWindowItem(ConfigOption option_, QWidget* widgetToFocus_, QString requirementToBeValid_) : option(option_), widgetToFocus(widgetToFocus_), requirementToBeValid(requirementToBeValid_) {} + QWidget* getWidgetToFocus(){return widgetToFocus;} + QString& getRequirementToBeValid() { return requirementToBeValid; } + ConfigOption& getConfigOption() { return option; } boost::any optionValue; virtual ~MainWindowItem(){} virtual void installListeners(MainWindow *mainWindow); @@ -94,7 +107,7 @@ public: std::string optName=""; if(!option.section.isEmpty())optName=option.section.toStdString()+std::string("."); optName+=option.option.toStdString(); - qDebug() << "loadFromConfigOption[" << optName.c_str() << "]"; + //qDebug() << "loadFromConfigOption[" << optName.c_str() << "]"; boost::any programOption; i2p::config::GetOptionAsAny(optName, programOption); optionValue=programOption.empty()?boost::any(std::string("")) @@ -137,7 +150,7 @@ public: }; class NonGUIOptionItem : public MainWindowItem { public: - NonGUIOptionItem(ConfigOption option_) : MainWindowItem(option_) {}; + NonGUIOptionItem(ConfigOption option_) : MainWindowItem(option_, nullptr, QString()) {}; virtual ~NonGUIOptionItem(){} virtual bool isValid() { return true; } }; @@ -145,7 +158,7 @@ class BaseStringItem : public MainWindowItem { Q_OBJECT public: QLineEdit* lineEdit; - BaseStringItem(ConfigOption option_, QLineEdit* lineEdit_) : MainWindowItem(option_), lineEdit(lineEdit_){}; + BaseStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString requirementToBeValid_) : MainWindowItem(option_, lineEdit_, requirementToBeValid_), lineEdit(lineEdit_){}; virtual ~BaseStringItem(){} virtual void installListeners(MainWindow *mainWindow); virtual QString toString(){ @@ -167,7 +180,7 @@ class FileOrFolderChooserItem : public BaseStringItem { public: QPushButton* browsePushButton; FileOrFolderChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_) : - BaseStringItem(option_, lineEdit_), browsePushButton(browsePushButton_) {} + BaseStringItem(option_, lineEdit_, QString()), browsePushButton(browsePushButton_) {} virtual ~FileOrFolderChooserItem(){} }; class FileChooserItem : public FileOrFolderChooserItem { @@ -193,13 +206,30 @@ public: class ComboBoxItem : public MainWindowItem { public: QComboBox* comboBox; - ComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : MainWindowItem(option_), comboBox(comboBox_){}; + ComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : MainWindowItem(option_,comboBox_,QString()), comboBox(comboBox_){}; virtual ~ComboBoxItem(){} virtual void installListeners(MainWindow *mainWindow); virtual void loadFromConfigOption()=0; virtual void saveToStringStream(std::stringstream& out)=0; virtual bool isValid() { return true; } }; +class LogDestinationComboBoxItem : public ComboBoxItem { +public: + LogDestinationComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : ComboBoxItem(option_, comboBox_) {}; + virtual ~LogDestinationComboBoxItem(){} + virtual void loadFromConfigOption(){ + MainWindowItem::loadFromConfigOption(); + const char * ld = boost::any_cast(optionValue).c_str(); + comboBox->setCurrentText(QString(ld)); + } + virtual void saveToStringStream(std::stringstream& out){ + std::string logDest = comboBox->currentText().toStdString(); + if(logDest==std::string("stdout"))logDest=""; + optionValue=logDest; + MainWindowItem::saveToStringStream(out); + } + virtual bool isValid() { return true; } +}; class LogLevelComboBoxItem : public ComboBoxItem { public: LogLevelComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : ComboBoxItem(option_, comboBox_) {}; @@ -235,7 +265,7 @@ public: class CheckBoxItem : public MainWindowItem { public: QCheckBox* checkBox; - CheckBoxItem(ConfigOption option_, QCheckBox* checkBox_) : MainWindowItem(option_), checkBox(checkBox_){}; + CheckBoxItem(ConfigOption option_, QCheckBox* checkBox_) : MainWindowItem(option_,checkBox_,QString()), checkBox(checkBox_){}; virtual ~CheckBoxItem(){} virtual void installListeners(MainWindow *mainWindow); virtual void loadFromConfigOption(){ @@ -251,62 +281,84 @@ public: class BaseFormattedStringItem : public BaseStringItem { public: QString fieldNameTranslated; - BaseFormattedStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : - BaseStringItem(option_, lineEdit_), fieldNameTranslated(fieldNameTranslated_) {}; + BaseFormattedStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, QString requirementToBeValid_) : + BaseStringItem(option_, lineEdit_, requirementToBeValid_), fieldNameTranslated(fieldNameTranslated_) {}; virtual ~BaseFormattedStringItem(){} virtual bool isValid()=0; }; class IntegerStringItem : public BaseFormattedStringItem { public: IntegerStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : - BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_) {}; + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be a valid integer.")) {}; virtual ~IntegerStringItem(){} - virtual bool isValid(){return true;} + virtual bool isValid(){ + auto str=lineEdit->text(); + bool ok; + str.toInt(&ok); + return ok; + } virtual QString toString(){return QString::number(boost::any_cast(optionValue));} virtual boost::any fromString(QString s){return boost::any(std::stoi(s.toStdString()));} }; class UShortStringItem : public BaseFormattedStringItem { public: UShortStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : - BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_) {}; + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be unsigned short integer.")) {}; virtual ~UShortStringItem(){} - virtual bool isValid(){return true;} + virtual bool isValid(){ + auto str=lineEdit->text(); + bool ok; + str.toUShort(&ok); + return ok; + } virtual QString toString(){return QString::number(boost::any_cast(optionValue));} virtual boost::any fromString(QString s){return boost::any((unsigned short)std::stoi(s.toStdString()));} }; class UInt32StringItem : public BaseFormattedStringItem { public: UInt32StringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : - BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_) {}; + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be unsigned 32-bit integer.")) {}; virtual ~UInt32StringItem(){} - virtual bool isValid(){return true;} + virtual bool isValid(){ + auto str=lineEdit->text(); + bool ok; + str.toUInt(&ok); + return ok; + } virtual QString toString(){return QString::number(boost::any_cast(optionValue));} virtual boost::any fromString(QString s){return boost::any((uint32_t)std::stoi(s.toStdString()));} }; class UInt16StringItem : public BaseFormattedStringItem { public: UInt16StringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : - BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_) {}; + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be unsigned 16-bit integer.")) {}; virtual ~UInt16StringItem(){} - virtual bool isValid(){return true;} + virtual bool isValid(){ + auto str=lineEdit->text(); + bool ok; + str.toUShort(&ok); + return ok; + } virtual QString toString(){return QString::number(boost::any_cast(optionValue));} virtual boost::any fromString(QString s){return boost::any((uint16_t)std::stoi(s.toStdString()));} }; class IPAddressStringItem : public BaseFormattedStringItem { public: IPAddressStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : - BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_) {}; - virtual bool isValid(){return true;} + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be an IPv4 address")) {}; + virtual bool isValid(){return true;}//todo }; class TCPPortStringItem : public UShortStringItem { public: TCPPortStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : UShortStringItem(option_, lineEdit_, fieldNameTranslated_) {}; - virtual bool isValid(){return true;} }; namespace Ui { -class MainWindow; + class MainWindow; + class StatusButtonsForm; + class routerCommandsWidget; + class GeneralSettingsContentsForm; } using namespace i2p::client; @@ -326,13 +378,20 @@ public: void setI2PController(i2p::qt::Controller* controller_); + void highlightWrongInput(QString warningText, QWidget* widgetToFocus); + //typedef std::function DefaultValueGetter; //#ifndef ANDROID // void setVisible(bool visible); //#endif +private: + enum StatusPage {main_page, commands, local_destinations, leasesets, tunnels, transit_tunnels, + transports, i2p_tunnels, sam_sessions}; private slots: + void updated(); + void handleQuitButton(); void handleGracefulQuitButton(); void handleDoRestartButton(); @@ -342,13 +401,37 @@ private slots: void iconActivated(QSystemTrayIcon::ActivationReason reason); void toggleVisibilitySlot(); #endif - void showStatusPage(); + void scheduleStatusPageUpdates(); + void statusHtmlPageMouseReleased(); + void statusHtmlPageSelectionChanged(); + void updateStatusPage(); + + void showStatusMainPage(); + void showStatus_commands_Page(); + void runPeerTest(); + void enableTransit(); + void disableTransit(); +public slots: + void showStatus_local_destinations_Page(); + void showStatus_leasesets_Page(); + void showStatus_tunnels_Page(); + void showStatus_transit_tunnels_Page(); + void showStatus_transports_Page(); + void showStatus_i2p_tunnels_Page(); + void showStatus_sam_sessions_Page(); + void showSettingsPage(); void showTunnelsPage(); void showRestartPage(); void showQuitPage(); private: + StatusPage statusPage; + QTimer * statusPageUpdateTimer; + bool wasSelectingAtStatusMainPage; + bool showHiddenInfoStatusMainPage; + + void showStatusPage(StatusPage newStatusPage); #ifndef ANDROID void createActions(); void createTrayIcon(); @@ -358,26 +441,48 @@ private: QMenu *trayIconMenu; #endif +public: Ui::MainWindow* ui; + Ui::StatusButtonsForm* statusButtonsUI; + Ui::routerCommandsWidget* routerCommandsUI; + Ui::GeneralSettingsContentsForm* uiSettings; + void adjustSizesAccordingToWrongLabel(); + bool applyTunnelsUiToConfigs(); +private: + int settingsTitleLabelNominalHeight; + TextBrowserTweaked1 * textBrowser; + QWidget * routerCommandsParent; + PageWithBackButton * pageWithBackButton; + TextBrowserTweaked1 * childTextBrowser; + + widgetlockregistry widgetlocks; i2p::qt::Controller* i2pController; protected: + + void updateRouterCommandsButtons(); + #ifndef ANDROID void closeEvent(QCloseEvent *event); #endif void resizeEvent(QResizeEvent* event); void onResize(); + void setStatusButtonsVisible(bool visible); + + QString getStatusPageHtml(bool showHiddenInfo); + QList configItems; - NonGUIOptionItem* logOption; NonGUIOptionItem* daemonOption; NonGUIOptionItem* serviceOption; + //LogDestinationComboBoxItem* logOption; FileChooserItem* logFileNameOption; FileChooserItem* initFileChooser(ConfigOption option, QLineEdit* fileNameLineEdit, QPushButton* fileBrowsePushButton); void initFolderChooser(ConfigOption option, QLineEdit* folderLineEdit, QPushButton* folderBrowsePushButton); //void initCombobox(ConfigOption option, QComboBox* comboBox); + void initLogDestinationCombobox(ConfigOption option, QComboBox* comboBox); void initLogLevelCombobox(ConfigOption option, QComboBox* comboBox); void initSignatureTypeCombobox(ConfigOption option, QComboBox* comboBox); void initIPAddressBox(ConfigOption option, QLineEdit* addressLineEdit, QString fieldNameTranslated); @@ -402,6 +507,11 @@ public slots: void addServerTunnelPushButtonReleased(); void addClientTunnelPushButtonReleased(); + void anchorClickedHandler(const QUrl & link); + void backClickedFromChild(); + + void logDestinationComboBoxValueChanged(const QString & text); + private: QString datadir; QString confpath; @@ -466,9 +576,9 @@ private: TunnelConfig* tc=it->second; tunnelConfigs.erase(it); delete tc; - SaveTunnelsConfig(); - reloadTunnelsConfigAndUI(""); } + saveAllConfigs(); + reloadTunnelsConfigAndUI(""); } std::string GenerateNewTunnelName() { @@ -503,7 +613,7 @@ private: destinationPort, sigType); - SaveTunnelsConfig(); + saveAllConfigs(); reloadTunnelsConfigAndUI(name); } @@ -542,7 +652,7 @@ private: isUniqueLocal); - SaveTunnelsConfig(); + saveAllConfigs(); reloadTunnelsConfigAndUI(name); } @@ -584,13 +694,17 @@ private: { // mandatory params std::string dest; - if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT || type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) + if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT || type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) { dest = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION); + std::cout << "had read tunnel dest: " << dest << std::endl; + } int port = section.second.get (I2P_CLIENT_TUNNEL_PORT); + std::cout << "had read tunnel port: " << port << std::endl; // optional params std::string keys = section.second.get (I2P_CLIENT_TUNNEL_KEYS, ""); std::string address = section.second.get (I2P_CLIENT_TUNNEL_ADDRESS, "127.0.0.1"); - int destinationPort = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0); + int destinationPort = section.second.get(I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0); + std::cout << "had read tunnel destinationPort: " << destinationPort << std::endl; i2p::data::SigningKeyType sigType = section.second.get (I2P_CLIENT_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); // I2CP std::map options; diff --git a/qt/i2pd_qt/mainwindow.ui b/qt/i2pd_qt/mainwindow.ui index 0b3071e9..9b463f44 100644 --- a/qt/i2pd_qt/mainwindow.ui +++ b/qt/i2pd_qt/mainwindow.ui @@ -6,10 +6,22 @@ 0 0 - 816 - 516 + 908 + 554 + + + 908 + 0 + + + + + 908 + 16777215 + + MainWindow @@ -22,14 +34,14 @@ - 0 - 516 + 908 + 550 - 16777215 - 516 + 908 + 550 @@ -37,19 +49,27 @@ 10 10 - 796 - 496 + 888 + 531 - QLayout::SetDefaultConstraint + QLayout::SetMaximumSize - + QLayout::SetMinimumSize + + + 0 + 0 + 170 + 496 + + @@ -60,13 +80,29 @@ + + + + + 0 + 0 + + + + + 172 + 0 + + + + true - Settings + General settings @@ -76,7 +112,7 @@ true - Tunnels + Tunnels settings @@ -100,6 +136,22 @@ + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 171 + 0 + + + + @@ -116,3072 +168,779 @@ - - - - 0 - 0 - + + + QLayout::SetMinAndMaxSize - - - 0 - 496 - - - - - 16777215 - 496 - - - - 4 - - - - - - 0 - 0 - 686 - 496 - + + + + + 0 + 30 + + + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 63 + 63 + + + + + + + 127 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 63 + 63 + + + + + + + 127 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 127 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 63 + 63 + + + + + + + 127 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 127 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 127 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + TextLabel + + + true + + + 10 - - - QLayout::SetMinAndMaxSize - - - - - - 15 - - - - Status - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - 0 - 0 - - - - - - 0 - 0 - 706 - 461 - + + + + + + 0 + 0 + - - - QLayout::SetMinAndMaxSize - - - - - - 15 - - - - Settings - - - - - - - Qt::ScrollBarAlwaysOn - - - Qt::ScrollBarAsNeeded - - - QAbstractScrollArea::AdjustIgnored - - - true - - - - - 0 - 0 - 679 - 3000 - - - - - 0 - 0 - - - - - - 10 - 10 - 679 - 3000 - - - - - - - - 0 - 98 - - - - - 16777215 - 98 - - - - SAM interface - - - - - 0 - 20 - 97 - 22 - - - - Enabled - - - - - - 0 - 40 - 661 - 31 - - - - - - - IP address to listen on: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 70 - 661 - 31 - - - - - - - Port to listen on: - - - - - - - - 80 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - 0 - 60 - - - - - 16777215 - 60 - - - - - 13 - - - - Windows-specific options - - - - - - - - 0 - 44 - - - - - 16777215 - 44 - - - - Cryptography - - - - - 0 - 20 - 661 - 22 - - - - Use ElGamal precomputed tables - - - - - - - - - 0 - 107 - - - - - 16777215 - 107 - - - - Logging - - - Qt::AlignJustify|Qt::AlignTop - - - - - -1 - 19 - 661 - 91 - - - - - QLayout::SetMinimumSize - - - - - QLayout::SetMaximumSize - - - - - Log file: - - - - - - - - - - Browse… - - - - - - - - - QLayout::SetMinimumSize - - - - - - 0 - 0 - - - - Log level: - - - - - - - - Error - - - - - Warn - - - - - Info - - - - - Debug - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - 0 - 68 - - - - - 16777215 - 68 - - - - UPnP - - - - - 0 - 20 - 97 - 22 - - - - Enable - - - - - - 0 - 40 - 661 - 31 - - - - - - - Name i2pd appears in UPnP forwardings list: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - 0 - 98 - - - - - 16777215 - 98 - - - - I2CP interface - - - - - 0 - 20 - 97 - 22 - - - - Enabled - - - - - - 0 - 40 - 661 - 31 - - - - - - - IP address to listen on: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 70 - 661 - 31 - - - - - - - Port to listen on: - - - - - - - - 80 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - 0 - 0 - - - - - 0 - 48 - - - - - 16777215 - 48 - - - - Tunnels configuration file: - - - - - 0 - 20 - 661 - 31 - - - - - QLayout::SetMaximumSize - - - - - - - - Browse… - - - - - - - - - - - - 0 - 98 - - - - - 16777215 - 98 - - - - BOB interface - - - - - 0 - 20 - 97 - 22 - - - - Enabled - - - - - - 0 - 40 - 661 - 31 - - - - - - - IP address to listen on: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 70 - 661 - 31 - - - - - - - Port to listen on: - - - - - - - - 80 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - 0 - 60 - - - - - 16777215 - 60 - - - - - 13 - - - - General options - - - - - - - - 0 - 0 - - - - - 0 - 98 - - - - - 16777215 - 98 - - - - Router external address (for incoming connections) - - - Qt::AlignJustify|Qt::AlignTop - - - - - 0 - 20 - 661 - 81 - - - - - QLayout::SetMinAndMaxSize - - - - - QLayout::SetMinAndMaxSize - - - - - Host: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - QLayout::SetMinAndMaxSize - - - - - Port (leave empty to auto-assign): - - - - - - - - 80 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - 0 - 78 - - - - - 16777215 - 78 - - - - Addressbook settings - - - - - 0 - 20 - 661 - 31 - - - - - - - Addressbook default subscription URL for initial setup: - - - - - - - - - - - - 0 - 50 - 661 - 31 - - - - - - - Addressbook subscriptions URLs, separated by comma: - - - - - - - - - - - - - - - 0 - 280 - - - - - 16777215 - 280 - - - - HTTP proxy - - - - - 0 - 20 - 97 - 22 - - - - Enabled - - - - - - 0 - 40 - 661 - 31 - - - - - - - IP address to listen on: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 70 - 661 - 31 - - - - - - - Port to listen on: - - - - - - - - 80 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 100 - 661 - 31 - - - - - - - Keys file: - - - - - - - - - - Browse… - - - - - - - - - 0 - 160 - 661 - 31 - - - - - - - Inbound tunnels length: - - - - - - - - 80 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 190 - 661 - 31 - - - - - - - Inbound tunnels quantity: - - - - - - - - 80 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 220 - 661 - 31 - - - - - - - Outbound tunnels length: - - - - - - - - 80 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 250 - 661 - 31 - - - - - - - Outbound tunnels quantity: - - - - - - - - 80 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 130 - 661 - 31 - - - - - - - Signature type: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - 0 - 60 - - - - - 16777215 - 60 - - - - - 13 - - - - Various options - - - - - - - - 0 - 48 - - - - - 16777215 - 48 - - - - Data folder (for storage of i2pd data — RI, keys, peer profiles, …): - - - - - 0 - 20 - 661 - 31 - - - - - QLayout::SetMaximumSize - - - - - - - - Browse… - - - - - - - - - - - - 0 - 0 - - - - - 0 - 215 - - - - - 16777215 - 215 - - - - Router options - - - - - 0 - 20 - 661 - 188 - - - - - - - Enable communication through ipv6 - - - - - - - Router will not accept transit tunnels at startup - - - - - - - Router will be floodfill - - - - - - - - - Bandwidth limit (integer): - - - - - - - - - - KBps - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - Family (name of a family router belongs to): - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - QLayout::SetMaximumSize - - - - - NetID (network ID router belongs to. The main I2P ID is 2): - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - 0 - 108 - - - - - 16777215 - 108 - - - - Limits - - - - - 0 - 20 - 661 - 31 - - - - - - - Maximum number of transit tunnels: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 50 - 661 - 31 - - - - - - - Maximum number of open files (0 — use system limit): - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 80 - 661 - 31 - - - - - - - Maximum size of core file in Kb (0 — use system limit): - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - 0 - 48 - - - - - 16777215 - 48 - - - - Pid file: - - - - - 0 - 20 - 661 - 31 - - - - - - - - - - Browse… - - - - - - - - - - - - 0 - 98 - - - - - 16777215 - 98 - - - - Reseeding - - - - - 0 - 20 - 661 - 22 - - - - Request SU3 signature verification - - - - - - 0 - 40 - 661 - 31 - - - - - - - SU3 file to reseed from: - - - - - - - - - - Browse… - - - - - - - - - 0 - 70 - 661 - 31 - - - - - - - Reseed URLs, separated by comma: - - - - - - - - - - - - - - - 0 - 180 - - - - - 16777215 - 180 - - - - Trust options - - - - - 0 - 20 - 661 - 21 - - - - Enable explicit trust options - - - - - - 390 - 40 - 271 - 23 - - - - - - - 0 - 40 - 391 - 42 - - - - Make direct I2P connections only to -routers in specified Family: - - - - - - 0 - 82 - 661 - 42 - - - - Make direct I2P connections only to routers specified here. -Comma separated list of base64 identities: - - - - - - 0 - 124 - 661 - 23 - - - - - - - 0 - 147 - 661 - 21 - - - - Should we hide our router from other routers? - - - - - - - - - 0 - 60 - - - - - 16777215 - 60 - - - - - 13 - - - - Ports - - - - - - - - 0 - 22 - - - - - 16777215 - 22 - - - - Insomnia (prevent system from sleeping) - - - - - - - - 0 - 189 - - - - - 16777215 - 189 - - - - I2PControl interface - - - - - 0 - 20 - 97 - 22 - - - - Enabled - - - - - - 0 - 40 - 661 - 31 - - - - - - - IP address to listen on: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 70 - 661 - 31 - - - - - - - Port to listen on: - - - - - - - - 80 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 100 - 661 - 31 - - - - - - - Password: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 130 - 661 - 31 - - - - - - - Certificate file: - - - - - - - - - - Browse… - - - - - - - - - 0 - 160 - 661 - 31 - - - - - - - Key file: - - - - - - - - - - Browse… - - - - - - - - - - - - 0 - 0 - - - - - 0 - 46 - - - - - 16777215 - 46 - - - - Configuration file: - - - - - 0 - 18 - 661 - 31 - - - - - QLayout::SetMinimumSize - - - - - - - - Browse… - - - - - - - - - - - - 0 - 110 - - - - - 16777215 - 110 - - - - Websockets server - - - - - 0 - 20 - 85 - 21 - - - - Enable - - - - - - 0 - 40 - 661 - 31 - - - - - - - Address to bind websocket server on: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 70 - 661 - 31 - - - - - - - Port to bind websocket server on: - - - - - - - - 80 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - 0 - 179 - - - - - 16777215 - 179 - - - - HTTP webconsole - - - - - 0 - 20 - 97 - 22 - - - - Enabled - - - - - - 0 - 40 - 661 - 31 - - - - - - - IP address to listen on: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 70 - 661 - 31 - - - - - - - Port to listen on: - - - - - - - - 80 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 100 - 321 - 22 - - - - Enable basic HTTP auth - - - - - - 60 - 120 - 601 - 31 - - - - - - - Username: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 60 - 150 - 601 - 31 - - - - - - - Password: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - 0 - 400 - - - - - 16777215 - 400 - - - - Socks proxy - - - - - 0 - 20 - 97 - 22 - - - - Enabled - - - - - - 0 - 40 - 661 - 31 - - - - - - - IP address to listen on: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 70 - 661 - 31 - - - - - - - Port to listen on: - - - - - - - - 80 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 100 - 661 - 31 - - - - - - - Keys file: - - - - - - - - - - Browse… - - - - - - - - - 0 - 160 - 661 - 31 - - - - - - - Inbound tunnels length: - - - - - - - - 80 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 190 - 661 - 31 - - - - - - - Inbound tunnels quantity: - - - - - - - - 80 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 220 - 661 - 31 - - - - - - - Outbound tunnels length: - - - - - - - - 80 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 250 - 661 - 31 - - - - - - - Outbound tunnels quantity: - - - - - - - - 80 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 280 - 661 - 31 - - - - - - - Outproxy address: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 310 - 661 - 31 - - - - - - - Outproxy port: - - - - - - - - 80 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 130 - 661 - 31 - - - - - - - SIgnature type: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - - - - - - - 0 - 0 - 706 - 461 - + + + 0 + 0 + - - - QLayout::SetMinAndMaxSize + + + 713 + 713 + + + + 2 + + + + + 0 + 0 + - - - - - 15 - + + + + 0 + 0 + 713 + 531 + + + + + QLayout::SetMaximumSize - - Tunnels - - - - - - + + + + 15 + + - Add Client Tunnel + Status - + + + QLayout::SetMaximumSize + + + + + + + + + + 0 + 0 + + + + + + 0 + 0 + 711 + 531 + + + + + QLayout::SetMinAndMaxSize + + + + + + 15 + + - Add Server Tunnel + General settings - + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAsNeeded + + + QAbstractScrollArea::AdjustIgnored + + + true + + + + + 0 + 0 + 689 + 496 + + + + + 0 + 0 + + + + + + + + + + + + + 0 + 0 + 711 + 531 + + + + + QLayout::SetMinAndMaxSize + + + + + + 15 + + + + Tunnels settings + + + + + + + + + Add Client Tunnel + + + + + + + Add Server Tunnel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::ScrollBarAlwaysOn + + + false + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + 0 + 0 + 699 + 425 + + + + + + + + + + + + + 0 + 0 + 711 + 531 + + + + + QLayout::SetMinAndMaxSize + + + + + + 15 + + + + Restart + + + + + + + Restart i2pd + + + + + - Qt::Horizontal + Qt::Vertical - 40 - 20 + 20 + 40 - - - - - Qt::ScrollBarAlwaysOn - - - false - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - 0 - 0 - 699 - 425 - - - - - - - - - - - - - 0 - 0 - 686 - 496 - - - - - QLayout::SetMinAndMaxSize + + + + + + 0 + 0 + - - - - - 15 - + + + + 0 + 0 + 711 + 531 + + + + + QLayout::SetMinAndMaxSize - - Restart - - - - - - - Restart i2pd - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - + + + + + 15 + + + + Quit + + + + + + + Quit Now + + + + + + + Graceful Quit + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + - - - - - 0 - 0 - - - - - - 0 - 0 - 686 - 496 - - - - - QLayout::SetMinAndMaxSize - - - - - - 15 - - - - Quit - - - - - - - Quit Now - - - - - - - Graceful Quit - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - + + diff --git a/qt/i2pd_qt/pagewithbackbutton.cpp b/qt/i2pd_qt/pagewithbackbutton.cpp new file mode 100644 index 00000000..bc297ac2 --- /dev/null +++ b/qt/i2pd_qt/pagewithbackbutton.cpp @@ -0,0 +1,24 @@ +#include "pagewithbackbutton.h" +#include "QVBoxLayout" +#include "QHBoxLayout" +#include "QPushButton" + +PageWithBackButton::PageWithBackButton(QWidget *parent, QWidget* child) : QWidget(parent) +{ + QVBoxLayout * layout = new QVBoxLayout(); + setLayout(layout); + QWidget * topBar = new QWidget(); + QHBoxLayout * topBarLayout = new QHBoxLayout(); + topBar->setLayout(topBarLayout); + layout->addWidget(topBar); + layout->addWidget(child); + + QPushButton * backButton = new QPushButton(topBar); + backButton->setText("< Back"); + topBarLayout->addWidget(backButton); + connect(backButton, SIGNAL(released()), this, SLOT(backReleasedSlot())); +} + +void PageWithBackButton::backReleasedSlot() { + emit backReleased(); +} diff --git a/qt/i2pd_qt/pagewithbackbutton.h b/qt/i2pd_qt/pagewithbackbutton.h new file mode 100644 index 00000000..60779f80 --- /dev/null +++ b/qt/i2pd_qt/pagewithbackbutton.h @@ -0,0 +1,21 @@ +#ifndef PAGEWITHBACKBUTTON_H +#define PAGEWITHBACKBUTTON_H + +#include + +class PageWithBackButton : public QWidget +{ + Q_OBJECT +public: + explicit PageWithBackButton(QWidget *parent, QWidget* child); + +signals: + + void backReleased(); + +private slots: + + void backReleasedSlot(); +}; + +#endif // PAGEWITHBACKBUTTON_H diff --git a/qt/i2pd_qt/routercommandswidget.ui b/qt/i2pd_qt/routercommandswidget.ui new file mode 100644 index 00000000..c5098e8e --- /dev/null +++ b/qt/i2pd_qt/routercommandswidget.ui @@ -0,0 +1,127 @@ + + + routerCommandsWidget + + + + 0 + 0 + 711 + 300 + + + + + 0 + 0 + + + + Form + + + + + 0 + 0 + 711 + 301 + + + + + QLayout::SetMaximumSize + + + + + + 0 + 0 + + + + + 75 + true + + + + Router Commands + + + + + + + + 0 + 0 + + + + Run peer test + + + + + + + + 0 + 0 + + + + Decline transit tunnels + + + + + + + + 0 + 0 + + + + Accept transit tunnels + + + + + + + false + + + + 0 + 0 + + + + Cancel graceful quit + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + diff --git a/qt/i2pd_qt/statusbuttons.ui b/qt/i2pd_qt/statusbuttons.ui new file mode 100644 index 00000000..edf5a90c --- /dev/null +++ b/qt/i2pd_qt/statusbuttons.ui @@ -0,0 +1,163 @@ + + + StatusButtonsForm + + + + 0 + 0 + 171 + 295 + + + + + 0 + 0 + + + + + 171 + 295 + + + + Form + + + + + 21 + 0 + 171 + 300 + + + + + QLayout::SetDefaultConstraint + + + + + + 150 + 16777215 + + + + Main page + + + + + + + + 150 + 16777215 + + + + Router commands + + + + + + + + 150 + 16777215 + + + + Local destinations + + + + + + + + 150 + 16777215 + + + + Leasesets + + + + + + + + 150 + 16777215 + + + + Tunnels + + + + + + + + 150 + 16777215 + + + + Transit tunnels + + + + + + + + 150 + 16777215 + + + + Transports + + + + + + + + 150 + 16777215 + + + + I2P tunnels + + + + + + + + 150 + 16777215 + + + + SAM sessions + + + + + + + + + diff --git a/qt/i2pd_qt/textbrowsertweaked1.cpp b/qt/i2pd_qt/textbrowsertweaked1.cpp new file mode 100644 index 00000000..f8802061 --- /dev/null +++ b/qt/i2pd_qt/textbrowsertweaked1.cpp @@ -0,0 +1,9 @@ +#include "textbrowsertweaked1.h" + +TextBrowserTweaked1::TextBrowserTweaked1(QWidget * parent): QTextBrowser(parent) +{ +} + +/*void TextBrowserTweaked1::setSource(const QUrl & url) { + emit navigatedTo(url); +}*/ diff --git a/qt/i2pd_qt/textbrowsertweaked1.h b/qt/i2pd_qt/textbrowsertweaked1.h new file mode 100644 index 00000000..288a3c32 --- /dev/null +++ b/qt/i2pd_qt/textbrowsertweaked1.h @@ -0,0 +1,26 @@ +#ifndef TEXTBROWSERTWEAKED1_H +#define TEXTBROWSERTWEAKED1_H + +#include +#include + +class TextBrowserTweaked1 : public QTextBrowser +{ + Q_OBJECT + +public: + TextBrowserTweaked1(QWidget * parent); + //virtual void setSource(const QUrl & url); + +signals: + void mouseReleased(); + //void navigatedTo(const QUrl & link); + +protected: + void mouseReleaseEvent(QMouseEvent *event) { + QTextBrowser::mouseReleaseEvent(event); + emit mouseReleased(); + } +}; + +#endif // TEXTBROWSERTWEAKED1_H diff --git a/qt/i2pd_qt/widgetlock.cpp b/qt/i2pd_qt/widgetlock.cpp new file mode 100644 index 00000000..a601fb36 --- /dev/null +++ b/qt/i2pd_qt/widgetlock.cpp @@ -0,0 +1 @@ +#include "widgetlock.h" diff --git a/qt/i2pd_qt/widgetlock.h b/qt/i2pd_qt/widgetlock.h new file mode 100644 index 00000000..5b21125c --- /dev/null +++ b/qt/i2pd_qt/widgetlock.h @@ -0,0 +1,35 @@ +#ifndef WIDGETLOCK_H +#define WIDGETLOCK_H + +#include +#include +#include +#include + +class widgetlock : public QObject { + Q_OBJECT + +private: + QWidget* widget; + QPushButton* lockButton; + +public slots: + void lockButtonClicked(bool) { + bool wasEnabled = widget->isEnabled(); + widget->setEnabled(!wasEnabled); + lockButton->setText(widget->isEnabled()?lockButton->tr("Lock"):lockButton->tr("Edit")); + } + +public: + widgetlock(QWidget* widget_, QPushButton* lockButton_): widget(widget_),lockButton(lockButton_) { + widget->setEnabled(false); + lockButton->setText(lockButton->tr("Edit")); + QObject::connect(lockButton,SIGNAL(clicked(bool)), this, SLOT(lockButtonClicked(bool))); + } + virtual ~widgetlock() {} + void deleteListener() { + QObject::disconnect(lockButton,SIGNAL(clicked(bool)), this, SLOT(lockButtonClicked(bool))); + } +}; + +#endif // WIDGETLOCK_H diff --git a/qt/i2pd_qt/widgetlockregistry.cpp b/qt/i2pd_qt/widgetlockregistry.cpp new file mode 100644 index 00000000..0d66d327 --- /dev/null +++ b/qt/i2pd_qt/widgetlockregistry.cpp @@ -0,0 +1,2 @@ +#include "widgetlockregistry.h" + diff --git a/qt/i2pd_qt/widgetlockregistry.h b/qt/i2pd_qt/widgetlockregistry.h new file mode 100644 index 00000000..78ee142a --- /dev/null +++ b/qt/i2pd_qt/widgetlockregistry.h @@ -0,0 +1,27 @@ +#ifndef WIDGETLOCKREGISTRY_H +#define WIDGETLOCKREGISTRY_H + +#include +#include + +class widgetlockregistry { + std::vector locks; + +public: + widgetlockregistry() : locks() {} + virtual ~widgetlockregistry() {} + void add(widgetlock* lock) { + locks.push_back(lock); + } + + void deleteListeners() { + while(!locks.empty()) { + widgetlock* lock = locks.back(); + lock->deleteListener(); + delete lock; + locks.pop_back(); + } + } +}; + +#endif // WIDGETLOCKREGISTRY_H