Merge pull request #986 from PurpleI2P/openssl

recent changes
This commit is contained in:
orignal 2017-11-02 14:45:47 -04:00 committed by GitHub
commit 42483b6f32
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
71 changed files with 6849 additions and 4347 deletions

2
.gitignore vendored
View file

@ -262,3 +262,5 @@ qt/i2pd_qt/*.ui.autosave
qt/i2pd_qt/*.ui.bk*
qt/i2pd_qt/*.ui_*
#unknown android stuff
android/libs/

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -9,6 +9,7 @@
#include "Tunnel.h"
#include "version.h"
#include "resource.h"
#include "Daemon.h"
#include "Win32App.h"
#include <stdio.h>
@ -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;
}
}
}

View file

@ -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__

View file

@ -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);

View file

@ -4,7 +4,6 @@
#include <thread>
#include <windows.h>
#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__

View file

@ -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

View file

@ -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

View file

@ -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-----

View file

@ -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";

View file

@ -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__

View file

@ -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 << "<b>ERROR:</b>&nbsp;" << string << "<br>\r\n";
}
static void ShowStatus (std::stringstream& s)
void ShowStatus (std::stringstream& s, bool includeHiddenContent)
{
s << "<b>Uptime:</b> ";
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 << "<br>Clock skew";
s << "<br>Clock skew";
break;
default: ;
}
default: ;
}
break;
}
}
default: s << "Unknown";
}
}
s << "<br>\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)<br>\r\n";
s << "<b>Transit:</b> ";
ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ());
s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " KiB/s)<br>\r\n";
s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " KiB/s)<br>\r\n";
s << "<b>Data path:</b> " << i2p::fs::GetDataDir() << "<br>\r\n";
s << "<div class='slide'\r\n><label for='slide1'>Hidden content. Press on text to see.</label>\r\n<input type='checkbox' id='slide1'/>\r\n<p class='content'>\r\n";
s << "<b>Router Ident:</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
s << "<b>Router Family:</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n";
s << "<b>Router Caps:</b> " << i2p::context.GetRouterInfo().GetProperty("caps") << "<br>\r\n";
s << "<b>Our external address:</b>" << "<br>\r\n" ;
for (const auto& address : i2p::context.GetRouterInfo().GetAddresses())
{
switch (address->transportStyle)
if(includeHiddenContent) {
s << "<b>Router Ident:</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
s << "<b>Router Family:</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n";
s << "<b>Router Caps:</b> " << i2p::context.GetRouterInfo().GetProperty("caps") << "<br>\r\n";
s << "<b>Our external address:</b>" << "<br>\r\n" ;
for (const auto& address : i2p::context.GetRouterInfo().GetAddresses())
{
case i2p::data::RouterInfo::eTransportNTCP:
if (address->host.is_v6 ())
s << "NTCP6&nbsp;&nbsp;";
else
s << "NTCP&nbsp;&nbsp;";
break;
case i2p::data::RouterInfo::eTransportSSU:
if (address->host.is_v6 ())
s << "SSU6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
else
s << "SSU&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
break;
default:
s << "Unknown&nbsp;&nbsp;";
switch (address->transportStyle)
{
case i2p::data::RouterInfo::eTransportNTCP:
if (address->host.is_v6 ())
s << "NTCP6&nbsp;&nbsp;";
else
s << "NTCP&nbsp;&nbsp;";
break;
case i2p::data::RouterInfo::eTransportSSU:
if (address->host.is_v6 ())
s << "SSU6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
else
s << "SSU&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
break;
default:
s << "Unknown&nbsp;&nbsp;";
}
s << address->host.to_string() << ":" << address->port << "<br>\r\n";
}
s << address->host.to_string() << ":" << address->port << "<br>\r\n";
}
s << "</p>\r\n</div>\r\n";
s << "<b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " ";
@ -271,13 +273,13 @@ namespace http {
s << "<b>Transit Tunnels:</b> " << std::to_string(transitTunnelCount) << "<br>\r\n";
}
static void ShowLocalDestinations (std::stringstream& s)
void ShowLocalDestinations (std::stringstream& s)
{
s << "<b>Local Destinations:</b><br>\r\n<br>\r\n";
for (auto& it: i2p::client::context.GetDestinations ())
{
auto ident = it.second->GetIdentHash ();
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
auto ident = it.second->GetIdentHash ();
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n" << std::endl;
}
@ -289,11 +291,11 @@ namespace http {
{
auto dest = it.second->GetDestination ();
if (dest)
{
auto ident = dest->GetIdentHash ();
s << "<a href=\"/?page=" << HTTP_PAGE_I2CP_LOCAL_DESTINATION << "&i2cp_id=" << it.first << "\">";
{
auto ident = dest->GetIdentHash ();
s << "<a href=\"/?page=" << HTTP_PAGE_I2CP_LOCAL_DESTINATION << "&i2cp_id=" << it.first << "\">";
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n" << std::endl;
}
}
}
}
}
@ -339,7 +341,7 @@ namespace http {
s << "<br>" << std::endl;
}
static void ShowLocalDestination (std::stringstream& s, const std::string& b32)
void ShowLocalDestination (std::stringstream& s, const std::string& b32)
{
s << "<b>Local Destination:</b><br>\r\n<br>\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 << "<br>\r\n<table><caption>Streams</caption><tr>";
s << "<th>StreamID</th>";
@ -375,35 +377,35 @@ namespace http {
s << "<td>" << it->GetRTT () << "</td>";
s << "<td>" << it->GetWindowSize () << "</td>";
s << "<td>" << (int)it->GetStatus () << "</td>";
s << "</tr><br>\r\n" << std::endl;
}
s << "</tr><br>\r\n" << std::endl;
}
s << "</table>";
}
}
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 << "<b>I2CP Local Destination:</b><br>\r\n<br>\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 << "<div id='leasesets'><b>LeaseSets (click on to show info):</b></div><br>\r\n";
int counter = 1;
// for each lease set
i2p::data::netdb.VisitLeaseSets(
[&s, &counter](const i2p::data::IdentHash dest, std::shared_ptr<i2p::data::LeaseSet> leaseSet)
[&s, &counter](const i2p::data::IdentHash dest, std::shared_ptr<i2p::data::LeaseSet> 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 << "<b>Queue size:</b> " << i2p::tunnel::tunnels.GetQueueSize () << "<br>\r\n";
@ -463,18 +465,20 @@ namespace http {
else
s << " <a href=\"/?cmd=" << HTTP_COMMAND_ENABLE_TRANSIT << "&token=" << token << "\">Accept transit tunnels</a><br>\r\n";
#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID))
if (Daemon.gracefulShutdownInterval)
if (Daemon.gracefulShutdownInterval)
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">Cancel graceful shutdown</a><br>";
else
else
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Start graceful shutdown</a><br>\r\n";
#endif
#ifdef WIN32_APP
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Graceful shutdown</a><br>\r\n";
#elif defined(WIN32_APP)
if (i2p::util::DaemonWin32::Instance().isGraceful)
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">Cancel graceful shutdown</a><br>";
else
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Graceful shutdown</a><br>\r\n";
#endif
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "&token=" << token << "\">Force shutdown</a><br>\r\n";
}
static void ShowTransitTunnels (std::stringstream& s)
void ShowTransitTunnels (std::stringstream& s)
{
s << "<b>Transit tunnels:</b><br>\r\n<br>\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 << "<b>Transports:</b><br>\r\n<br>\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 << "<b>SAM Sessions:</b><br>\r\n<br>\r\n";
for (auto& it: sam->GetSessions ())
{
auto& name = it.second->localDestination->GetNickname ();
s << "<a href=\"/?page=" << HTTP_PAGE_SAM_SESSION << "&sam_id=" << it.first << "\">";
s << it.first << "</a><br>\r\n" << std::endl;
s << name << " (" << it.first << ")</a><br>\r\n" << std::endl;
}
}
@ -622,13 +627,13 @@ namespace http {
}
}
static void ShowI2PTunnels (std::stringstream& s)
void ShowI2PTunnels (std::stringstream& s)
{
s << "<b>Client Tunnels:</b><br>\r\n<br>\r\n";
for (auto& it: i2p::client::context.GetClientTunnels ())
{
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << it.second->GetName () << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "<br>\r\n"<< std::endl;
@ -637,29 +642,32 @@ namespace http {
if (httpProxy)
{
auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash();
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << "HTTP Proxy" << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "<br>\r\n"<< std::endl;
}
}
auto socksProxy = i2p::client::context.GetSocksProxy ();
if (socksProxy)
{
auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash();
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << "SOCKS Proxy" << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "<br>\r\n"<< std::endl;
}
s << "<br>\r\n<b>Server Tunnels:</b><br>\r\n<br>\r\n";
for (auto& it: i2p::client::context.GetServerTunnels ())
{
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << it.second->GetName () << "</a> &#8658; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << ":" << it.second->GetLocalPort ();
s << "</a><br>\r\n"<< std::endl;
}
auto& serverTunnels = i2p::client::context.GetServerTunnels ();
if (!serverTunnels.empty ()) {
s << "<br>\r\n<b>Server Tunnels:</b><br>\r\n<br>\r\n";
for (auto& it: serverTunnels)
{
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << it.second->GetName () << "</a> &#8658; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << ":" << it.second->GetLocalPort ();
s << "</a><br>\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 << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << it.second->GetName () << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "<br>\r\n"<< std::endl;
@ -681,7 +689,7 @@ namespace http {
for (auto& it: serverForwards)
{
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << it.second->GetName () << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "<br>\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<uint32_t, uint32_t> HTTPConnection::m_Tokens;
void HTTPConnection::HandlePage (const HTTPReq& req, HTTPRes& res, std::stringstream& s)
{
{
std::map<std::string, std::string> 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<boost::asio::ip::tcp::socket> 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);

View file

@ -7,6 +7,7 @@
#include <map>
#include <thread>
#include <boost/asio.hpp>
#include <sstream>
#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

View file

@ -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);

4
debian/control vendored
View file

@ -2,7 +2,7 @@ Source: i2pd
Section: net
Priority: optional
Maintainer: R4SAS <r4sas@i2pmail.org>
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

1
debian/i2pd.install vendored
View file

@ -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

1
debian/rules vendored
View file

@ -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

View file

@ -38,6 +38,7 @@ namespace config {
("log", value<std::string>()->default_value(""), "Logs destination: stdout, file, syslog (stdout if not set)")
("logfile", value<std::string>()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)")
("loglevel", value<std::string>()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error)")
("logclftime", value<bool>()->default_value(false), "Write full CLF-formatted date and time to log (default: write only time)")
("family", value<std::string>()->default_value(""), "Specify a family, router belongs to")
("datadir", value<std::string>()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)")
("host", value<std::string>()->default_value("0.0.0.0"), "External IP")
@ -70,6 +71,8 @@ namespace config {
("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)")
("limits.openfiles", value<uint16_t>()->default_value(0), "Maximum number of open files (0 - use system default)")
("limits.transittunnels", value<uint16_t>()->default_value(2500), "Maximum active transit sessions (default:2500)")
("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Threshold to start probabalistic backoff with ntcp sessions (default: use system limit)")
("limits.ntcphard", value<uint16_t>()->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")
;

View file

@ -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;

View file

@ -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);

View file

@ -1,5 +1,6 @@
#include <algorithm>
#include <cassert>
#include <string>
#include "Crypto.h"
#include "Log.h"
#include "FS.h"
@ -13,8 +14,8 @@ namespace i2p
namespace client
{
LeaseSetDestination::LeaseSetDestination (bool isPublic, const std::map<std::string, std::string> * 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<std::vector<i2p::data::IdentHash> > 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<const i2p::data::LeaseSet> LeaseSetDestination::FindLeaseSet (const i2p::data::IdentHash& ident)
{
std::shared_ptr<i2p::data::LeaseSet> 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<std::mutex> _lock(m_RemoteLeaseSetsMutex);
m_RemoteLeaseSets[ident] = ls;
return ls;
}
}
}
return nullptr;
}
@ -215,11 +224,11 @@ namespace client
UpdateLeaseSet ();
std::lock_guard<std::mutex> l(m_LeaseSetMutex);
return m_LeaseSet;
}
}
void LeaseSetDestination::SetLeaseSet (i2p::data::LocalLeaseSet * newLeaseSet)
{
{
{
std::lock_guard<std::mutex> 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<I2NPMessage> 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<I2NPMessage> 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<i2p::tunnel::InboundTunnel> 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<i2p::data::LeaseSet> (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<I2NPMessage> 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<i2p::data::LeaseSet> 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<i2p::data::IdentHash> 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<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> 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<std::string, std::string> * 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<i2p::stream::StreamingDestination> (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<i2p::stream::StreamingDestination> ClientDestination::GetStreamingDestination (int port) const
{
if (port)
std::shared_ptr<i2p::stream::StreamingDestination> 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<i2p::stream::StreamingDestination> ClientDestination::CreateStreamingDestination (int port, bool gzip)
{
auto dest = std::make_shared<i2p::stream::StreamingDestination> (GetSharedFromThis (), port, gzip);
auto dest = std::make_shared<i2p::stream::StreamingDestination> (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<std::shared_ptr<const i2p::stream::Stream> > 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<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels)
{
@ -935,7 +944,7 @@ namespace client
// sign
Sign (leaseSet->GetBuffer (), leaseSet->GetBufferLen () - leaseSet->GetSignatureLen (), leaseSet->GetSignature ()); // TODO
SetLeaseSet (leaseSet);
}
}
void ClientDestination::CleanupDestination ()
{

View file

@ -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<std::string, std::string> * 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:

View file

@ -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;

View file

@ -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<std::string> &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);
}

View file

@ -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 ;

View file

@ -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;

View file

@ -58,6 +58,7 @@ namespace log {
char m_LastDateTime[64];
i2p::util::Queue<std::shared_ptr<LogMsg> > 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<std::ostream> 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

View file

@ -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)
{

View file

@ -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<NTCPSession> conn, const boost::system::error_code& error);
void HandleAcceptV6 (std::shared_ptr<NTCPSession> 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

View file

@ -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<i2p::tunnel::TunnelPool> 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<i2p::tunnel::InboundTunnel> from)
{
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from));
@ -459,22 +460,22 @@ namespace i2p
{
std::unique_lock<std::mutex> l(m_GarlicMutex);
i2p::garlic::GarlicDestination::ProcessGarlicMessage (msg);
}
}
void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
{
std::unique_lock<std::mutex> l(m_GarlicMutex);
i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg);
}
}
void RouterContext::CleanupDestination ()
{
std::unique_lock<std::mutex> l(m_GarlicMutex);
i2p::garlic::GarlicDestination::CleanupExpiredTags ();
}
uint32_t RouterContext::GetUptime () const
{
return i2p::util::GetSecondsSinceEpoch () - m_StartupTime;
}
}
}

View file

@ -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<Address>();
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;

View file

@ -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 ();

View file

@ -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;
}

View file

@ -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:

View file

@ -102,9 +102,14 @@ namespace transport
void DHKeysPairSupplier::Return (std::shared_ptr<i2p::crypto::DHKeys> pair)
{
std::unique_lock<std::mutex>l(m_AcquiredMutex);
if ((int)m_Queue.size () < 2*m_QueueSize)
m_Queue.push (pair);
if (pair)
{
std::unique_lock<std::mutex>l(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<NTCPSession> (*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<NTCPSession> (*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

View file

@ -5,6 +5,7 @@
#include <functional>
#include <memory>
#include <mutex>
#include <utility>
#include <boost/asio.hpp>
#ifdef ANDROID
@ -14,7 +15,7 @@ namespace std
template <typename T>
std::string to_string(T value)
{
return boost::lexical_cast<std::string>(value);
return boost::lexical_cast<std::string>(value);
}
inline int stoi(const std::string& str)
@ -29,12 +30,14 @@ namespace i2p
namespace util
{
template<class T>
template<class T>
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<typename... TArgs>
T * Acquire (TArgs&&... args)
{
if (!m_Head) return new T(args...);
if (!m_Head) return new T(std::forward<TArgs>(args)...);
else
{
auto tmp = m_Head;
m_Head = static_cast<T*>(*(void * *)m_Head); // next
return new (tmp)T(args...);
return new (tmp)T(std::forward<TArgs>(args)...);
}
}
@ -68,14 +71,15 @@ namespace util
template<typename... TArgs>
std::unique_ptr<T, std::function<void(T*)> > AcquireUnique (TArgs&&... args)
{
return std::unique_ptr<T, std::function<void(T*)> >(Acquire (args...),
return std::unique_ptr<T, std::function<void(T*)> >(Acquire (std::forward<TArgs>(args)...),
std::bind (&MemoryPool<T>::Release, this, std::placeholders::_1));
}
template<typename... TArgs>
std::shared_ptr<T> AcquireShared (TArgs&&... args)
{
return std::shared_ptr<T>(Acquire (args...), std::bind (&MemoryPool<T>::Release, this, std::placeholders::_1));
return std::shared_ptr<T>(Acquire (std::forward<TArgs>(args)...),
std::bind (&MemoryPool<T>::Release, this, std::placeholders::_1));
}
protected:
@ -88,13 +92,13 @@ namespace util
{
public:
MemoryPoolMt () {};
MemoryPoolMt () {}
template<typename... TArgs>
T * AcquireMt (TArgs&&... args)
{
if (!this->m_Head) return new T(args...);
if (!this->m_Head) return new T(std::forward<TArgs>(args)...);
std::lock_guard<std::mutex> l(m_Mutex);
return this->Acquire (args...);
return this->Acquire (std::forward<TArgs>(args)...);
}
void ReleaseMt (T * t)

View file

@ -48,12 +48,13 @@ namespace client
std::shared_ptr<ClientDestination> 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<std::mutex> 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<uint32_t>(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<I2PService>(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<I2PServerTunnel>(serverTunnel)));
std::unique_ptr<I2PServerTunnel>(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<typename Visitor>

View file

@ -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";

View file

@ -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<i2p::stream::Stream> 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<void(boost::asio::ip::tcp::endpoint)> 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<boost::asio::ip::tcp::socket> m_sock;
std::shared_ptr<boost::asio::ip::tcp::socket> 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<boost::asio::ip::tcp::socket> sock) :
I2PServiceHandler(parent), m_sock(sock),
m_proxysock(std::make_shared<boost::asio::ip::tcp::socket>(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<i2p::stream::Stream> 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<i2p::client::I2PTunnelConnection>(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<i2p::client::ClientDestination> 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<i2p::client::ClientDestination> localDestination):
TCPIPAcceptor(address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ()),
m_OutproxyUrl(outproxy)
{
}
std::shared_ptr<i2p::client::I2PServiceHandler> HTTPProxy::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
{
return std::make_shared<HTTPReqHandler> (this, socket);

View file

@ -6,14 +6,20 @@ namespace proxy {
class HTTPProxy: public i2p::client::TCPIPAcceptor
{
public:
HTTPProxy(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
HTTPProxy(const std::string& address, int port, const std::string & outproxy, std::shared_ptr<i2p::client::ClientDestination> localDestination);
HTTPProxy(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr) :
HTTPProxy(address, port, "", localDestination) {} ;
~HTTPProxy() {};
std::string GetOutproxyURL() const { return m_OutproxyUrl; }
protected:
// Implements TCPIPAcceptor
std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
const char* GetName() { return "HTTP Proxy"; }
private:
std::string m_OutproxyUrl;
};
} // http
} // i2p

View file

@ -2,6 +2,7 @@
#include "Identity.h"
#include "ClientContext.h"
#include "I2PService.h"
#include <boost/asio/error.hpp>
namespace i2p
{
@ -11,37 +12,99 @@ namespace client
I2PService::I2PService (std::shared_ptr<ClientDestination> 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<std::mutex> 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<boost::asio::ip::tcp::socket> upstream, std::shared_ptr<boost::asio::ip::tcp::socket> 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();
}

View file

@ -14,8 +14,11 @@ namespace i2p
namespace client
{
class I2PServiceHandler;
class I2PService
class I2PService : std::enable_shared_from_this<I2PService>
{
public:
typedef std::function<void(const boost::system::error_code &)> ReadyCallback;
public:
I2PService (std::shared_ptr<ClientDestination> 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<ClientDestination> GetLocalDestination () { return m_LocalDestination; }
inline std::shared_ptr<const ClientDestination> GetLocalDestination () const { return m_LocalDestination; }
inline void SetLocalDestination (std::shared_ptr<ClientDestination> dest) { m_LocalDestination = dest; }
inline void SetLocalDestination (std::shared_ptr<ClientDestination> 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<ClientDestination> m_LocalDestination;
std::unordered_set<std::shared_ptr<I2PServiceHandler> > m_Handlers;
std::mutex m_HandlersMutex;
std::vector<std::pair<ReadyCallback, uint32_t> > 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<I2PServiceHandler> 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<bool> 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<TCPIPPipe> {
public:
TCPIPPipe(I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> upstream, std::shared_ptr<boost::asio::ip::tcp::socket> 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<boost::asio::ip::tcp::socket> m_up, m_down;
class TCPIPPipe: public I2PServiceHandler, public std::enable_shared_from_this<TCPIPPipe>
{
public:
TCPIPPipe(I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> upstream, std::shared_ptr<boost::asio::ip::tcp::socket> 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<boost::asio::ip::tcp::socket> 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<I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket) = 0;
private:
void Accept();
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket);

View file

@ -14,29 +14,29 @@ namespace client
static void I2PTunnelSetSocketOptions(std::shared_ptr<boost::asio::ip::tcp::socket> 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<boost::asio::ip::tcp::socket> socket,
std::shared_ptr<const i2p::data::LeaseSet> leaseSet, int port):
std::shared_ptr<const i2p::data::LeaseSet> 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<boost::asio::ip::tcp::socket> socket, std::shared_ptr<i2p::stream::Stream> stream):
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<i2p::stream::Stream> stream):
I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream),
m_RemoteEndpoint (socket->remote_endpoint ()), m_IsQuiet (true)
{
}
I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
std::shared_ptr<boost::asio::ip::tcp::socket> socket, const boost::asio::ip::tcp::endpoint& target, bool quiet):
std::shared_ptr<boost::asio::ip::tcp::socket> 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<boost::asio::ip::tcp::socket> & 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<i2p::stream::Stream> stream,
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
std::shared_ptr<boost::asio::ip::tcp::socket> 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<i2p::stream::Stream> stream,
std::shared_ptr<boost::asio::ip::tcp::socket> 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<boost::asio::ip::tcp::socket> 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<boost::asio::ip::tcp::socket> 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<ClientDestination> 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<ClientDestination> 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<ClientDestination> localDestination, int inport, bool gzip):
I2PServerTunnel::I2PServerTunnel (const std::string& name, const std::string& address,
int port, std::shared_ptr<ClientDestination> 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<boost::asio::ip::tcp::resolver>(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<boost::asio::ip::tcp::resolver> 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<i2p::data::IdentHash>& 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<i2p::stream::Stream> 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<I2PTunnelConnection> I2PServerTunnel::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
{
return std::make_shared<I2PTunnelConnection> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint ());
}
I2PServerTunnelHTTP::I2PServerTunnelHTTP (const std::string& name, const std::string& address,
int port, std::shared_ptr<ClientDestination> 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<ClientDestination> localDestination,
const std::string& host, int inport, bool gzip):
I2PServerTunnel (name, address, port, localDestination, inport, gzip),
m_Host (host)
{
}
std::shared_ptr<I2PTunnelConnection> I2PServerTunnelHTTP::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
{
return std::make_shared<I2PServerTunnelConnectionHTTP> (this, stream,
return std::make_shared<I2PServerTunnelConnectionHTTP> (this, stream,
std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint (), m_Host);
}
I2PServerTunnelIRC::I2PServerTunnelIRC (const std::string& name, const std::string& address,
int port, std::shared_ptr<ClientDestination> 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<ClientDestination> localDestination,
const std::string& webircpass, int inport, bool gzip):
I2PServerTunnel (name, address, port, localDestination, inport, gzip),
m_WebircPass (webircpass)
{
}
std::shared_ptr<I2PTunnelConnection> I2PServerTunnelIRC::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
{
return std::make_shared<I2PTunnelConnectionIRC> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint (), this->m_WebircPass);
}
std::shared_ptr<I2PTunnelConnection> I2PServerTunnelIRC::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
{
return std::make_shared<I2PTunnelConnectionIRC> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (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<std::mutex> 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<std::mutex> 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<std::mutex> lock(m_SessionsMutex);
uint64_t now = i2p::util::GetMillisecondsSinceEpoch();
void I2PUDPServerTunnel::ExpireStale(const uint64_t delta) {
std::lock_guard<std::mutex> 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<std::mutex> lock(m_SessionsMutex);
uint64_t now = i2p::util::GetMillisecondsSinceEpoch();
uint64_t now = i2p::util::GetMillisecondsSinceEpoch();
std::vector<uint16_t> 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<UDPSession>(ep, m_LocalDest, m_RemoteEndpoint, &ih, localPort, remotePort));
m_Sessions.push_back(std::make_shared<UDPSession>(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<i2p::client::ClientDestination> & 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<i2p::client::ClientDestination> & 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<i2p::client::ClientDestination> 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<i2p::client::ClientDestination> 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<std::shared_ptr<DatagramSessionInfo> > I2PUDPClientTunnel::GetSessions()
{
// TODO: implement
std::vector<std::shared_ptr<DatagramSessionInfo> > 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();

View file

@ -29,7 +29,6 @@ namespace client
class I2PTunnelConnection: public I2PServiceHandler, public std::enable_shared_from_this<I2PTunnelConnection>
{
public:
I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
std::shared_ptr<const i2p::data::LeaseSet> leaseSet, int port = 0); // to I2P
I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> 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<const boost::asio::ip::tcp::socket> 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<boost::asio::ip::tcp::socket> m_Socket;
std::shared_ptr<i2p::stream::Stream> m_Stream;
@ -67,18 +64,15 @@ namespace client
class I2PClientTunnelConnectionHTTP: public I2PTunnelConnection
{
public:
I2PClientTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
std::shared_ptr<i2p::stream::Stream> 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<i2p::stream::Stream> stream,
std::shared_ptr<boost::asio::ip::tcp::socket> 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<i2p::stream::Stream> stream,
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
const boost::asio::ip::tcp::endpoint& target, const std::string& m_WebircPass);
I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
std::shared_ptr<boost::asio::ip::tcp::socket> 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<const i2p::data::IdentityEx> m_From;
std::stringstream m_OutPacket, m_InPacket;
private:
std::shared_ptr<const i2p::data::IdentityEx> 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<I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
public:
I2PClientTunnel (const std::string& name, const std::string& destination,
const std::string& address, int port, std::shared_ptr<ClientDestination> 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<i2p::client::ClientDestination> 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<boost::asio::ip::udp::endpoint, uint64_t> UDPConvo;
void RecvFromLocal();
void HandleRecvFromLocal(const boost::system::error_code & e, std::size_t transferred);
typedef std::pair<boost::asio::ip::udp::endpoint, uint64_t> 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<uint16_t, UDPConvo > m_Sessions; // maps i2p port -> local udp convo
std::mutex m_SessionsMutex;
std::map<uint16_t, UDPConvo > m_Sessions; // maps i2p port -> local udp convo
const std::string m_RemoteDest;
std::shared_ptr<i2p::client::ClientDestination> 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<ClientDestination> 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<boost::asio::ip::tcp::resolver> resolver);
@ -310,7 +291,6 @@ namespace client
virtual std::shared_ptr<I2PTunnelConnection> CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> 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<ClientDestination> localDestination, const std::string& host,
int inport = 0, bool gzip = true);
int inport = 0, bool gzip = true);
private:
std::shared_ptr<I2PTunnelConnection> CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> 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<ClientDestination> 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<ClientDestination> localDestination, const std::string& webircpass,
int inport = 0, bool gzip = true);
private:
std::shared_ptr<I2PTunnelConnection> CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream);
private:
std::string m_WebircPass;
};
private:
std::shared_ptr<I2PTunnelConnection> CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream);
private:
std::string m_WebircPass;
};
}
}

View file

@ -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));
}
}

View file

@ -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);

View file

@ -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));

View file

@ -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;

View file

@ -1,9 +1,6 @@
#ifndef SERVERTUNNELPANE_H
#define SERVERTUNNELPANE_H
#include "TunnelPane.h"
#include "TunnelsPageUpdateListener.h"
#include <QtCore/QVariant>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
@ -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());

View file

@ -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) {

View file

@ -5,6 +5,7 @@
#include <string>
#include "../../libi2pd_client/ClientContext.h"
#include "../../libi2pd/Destination.h"
#include "TunnelsPageUpdateListener.h"

View file

@ -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();
}

View file

@ -14,25 +14,39 @@
#include "TunnelConfig.h"
#include <widgetlock.h>
#include <widgetlockregistry.h>
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,

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -1,5 +1,12 @@
#include <fstream>
#include <assert.h>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "ui_statusbuttons.h"
#include "ui_routercommandswidget.h"
#include "ui_generalsettingswidget.h"
#include <sstream>
#include <QScrollBar>
#include <QMessageBox>
#include <QTimer>
#include <QFile>
@ -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 <QtDebug>
#endif
#include <QScrollBar>
#include <fstream>
#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<MainWindowItem*>::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 << "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">";
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<MainWindowItem*>::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<MainWindowItem*>::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<MainWindowItem*>::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<QWidget*> childWidgets = ui->tunnelsScrollAreaWidgetContents->findChildren<QWidget*>();
foreach(QWidget* widget, childWidgets)
@ -572,6 +759,14 @@ void MainWindow::deleteTunnelForms() {
tunnelPanes.clear();
}
bool MainWindow::applyTunnelsUiToConfigs() {
for(std::list<TunnelPane*>::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<std::string,TunnelConfig*>::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()<<debugStr;
//QMessageBox::information(this, "", debugStr);
/* /?page=local_destination&b32=xx...xx */
QString str=link.toString();
#define LOCAL_DEST_B32_PREFIX "/?page=local_destination&b32="
static size_t LOCAL_DEST_B32_PREFIX_SZ=QString(LOCAL_DEST_B32_PREFIX).size();
if(str.startsWith(LOCAL_DEST_B32_PREFIX)) {
str = str.right(str.size()-LOCAL_DEST_B32_PREFIX_SZ);
qDebug () << "b32:" << str;
pageWithBackButton->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();
}

View file

@ -24,6 +24,7 @@
#include <QtWidgets/QPushButton>
#include <QtWidgets/QSpacerItem>
#include "QVBoxLayout"
#include "QUrl"
#ifndef ANDROID
# include <QSystemTrayIcon>
@ -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 <iostream>
#include "widgetlockregistry.h"
#include "widgetlock.h"
template<typename ValueType>
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<std::string>(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<int>(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<unsigned short>(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<uint32_t>(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<uint16_t>(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<QString ()> 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<MainWindowItem*> 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<std::string> (I2P_CLIENT_TUNNEL_DESTINATION);
std::cout << "had read tunnel dest: " << dest << std::endl;
}
int port = section.second.get<int> (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<int>(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<std::string, std::string> options;

File diff suppressed because it is too large Load diff

View file

@ -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();
}

View file

@ -0,0 +1,21 @@
#ifndef PAGEWITHBACKBUTTON_H
#define PAGEWITHBACKBUTTON_H
#include <QWidget>
class PageWithBackButton : public QWidget
{
Q_OBJECT
public:
explicit PageWithBackButton(QWidget *parent, QWidget* child);
signals:
void backReleased();
private slots:
void backReleasedSlot();
};
#endif // PAGEWITHBACKBUTTON_H

View file

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>routerCommandsWidget</class>
<widget class="QWidget" name="routerCommandsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>711</width>
<height>300</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QWidget" name="verticalLayoutWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>711</width>
<height>301</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMaximumSize</enum>
</property>
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Router Commands</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="runPeerTestPushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Run peer test</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="declineTransitTunnelsPushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Decline transit tunnels</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="acceptTransitTunnelsPushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Accept transit tunnels</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="cancelGracefulQuitPushButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Cancel graceful quit</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

163
qt/i2pd_qt/statusbuttons.ui Normal file
View file

@ -0,0 +1,163 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>StatusButtonsForm</class>
<widget class="QWidget" name="StatusButtonsForm">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>171</width>
<height>295</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>171</width>
<height>295</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QWidget" name="verticalLayoutWidget">
<property name="geometry">
<rect>
<x>21</x>
<y>0</y>
<width>171</width>
<height>300</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<widget class="QPushButton" name="mainPagePushButton">
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Main page</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="routerCommandsPushButton">
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Router commands</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="localDestinationsPushButton">
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Local destinations</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="leasesetsPushButton">
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Leasesets</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="tunnelsPushButton">
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Tunnels</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="transitTunnelsPushButton">
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Transit tunnels</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="transportsPushButton">
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Transports</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="i2pTunnelsPushButton">
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>I2P tunnels</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="samSessionsPushButton">
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>SAM sessions</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -0,0 +1,9 @@
#include "textbrowsertweaked1.h"
TextBrowserTweaked1::TextBrowserTweaked1(QWidget * parent): QTextBrowser(parent)
{
}
/*void TextBrowserTweaked1::setSource(const QUrl & url) {
emit navigatedTo(url);
}*/

View file

@ -0,0 +1,26 @@
#ifndef TEXTBROWSERTWEAKED1_H
#define TEXTBROWSERTWEAKED1_H
#include <QTextBrowser>
#include <QUrl>
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

View file

@ -0,0 +1 @@
#include "widgetlock.h"

35
qt/i2pd_qt/widgetlock.h Normal file
View file

@ -0,0 +1,35 @@
#ifndef WIDGETLOCK_H
#define WIDGETLOCK_H
#include <QWidget>
#include <QObject>
#include <QPushButton>
#include <QApplication>
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

View file

@ -0,0 +1,2 @@
#include "widgetlockregistry.h"

View file

@ -0,0 +1,27 @@
#ifndef WIDGETLOCKREGISTRY_H
#define WIDGETLOCKREGISTRY_H
#include <vector>
#include <widgetlock.h>
class widgetlockregistry {
std::vector<widgetlock*> 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