From dd4f066e95c7120595cc393130865d62a057d4eb Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 27 Sep 2017 23:28:58 +0300 Subject: [PATCH] add graceful shutdown in webconsole for windows add stop graceful shutdown menu item add reload menu item --- Win32/DaemonWin32.cpp | 140 ++++++++++++++--------------- Win32/Win32App.cpp | 40 ++++++++- Win32/Win32App.h | 9 +- daemon/Daemon.h | 70 +++++++-------- daemon/HTTPServer.cpp | 199 +++++++++++++++++++++--------------------- 5 files changed, 248 insertions(+), 210 deletions(-) diff --git a/Win32/DaemonWin32.cpp b/Win32/DaemonWin32.cpp index 698cf390..d36949c3 100644 --- a/Win32/DaemonWin32.cpp +++ b/Win32/DaemonWin32.cpp @@ -14,99 +14,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"); + setlocale(LC_CTYPE, ""); + SetConsoleCP(1251); + SetConsoleOutputCP(1251); + setlocale(LC_ALL, "Russian"); - if (!Daemon_Singleton::init(argc, argv)) - return false; + 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; - } + 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) + if (isDaemon) + { + LogPrint(eLogDebug, "Daemon: running as service"); + I2PService service(SERVICE_NAME); + if (!I2PService::Run(service)) { - 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; - } + LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError()); return false; } - else - LogPrint(eLogDebug, "Daemon: running as user"); - return true; + return false; } + else + LogPrint(eLogDebug, "Daemon: running as user"); + return true; + } - bool DaemonWin32::start() - { - setlocale(LC_CTYPE, ""); - SetConsoleCP(1251); - SetConsoleOutputCP(1251); - setlocale(LC_ALL, "Russian"); + bool DaemonWin32::start() + { + setlocale(LC_CTYPE, ""); + SetConsoleCP(1251); + SetConsoleOutputCP(1251); + setlocale(LC_ALL, "Russian"); #ifdef WIN32_APP - if (!i2p::win32::StartWin32App ()) return false; + if (!i2p::win32::StartWin32App ()) return false; - // override log - i2p::config::SetOption("log", std::string ("file")); + // 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 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 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 diff --git a/Win32/Win32App.cpp b/Win32/Win32App.cpp index e66b5f08..4c7eae03 100644 --- a/Win32/Win32App.cpp +++ b/Win32/Win32App.cpp @@ -9,6 +9,7 @@ #include "Tunnel.h" #include "version.h" #include "resource.h" +#include "Daemon.h" #include "Win32App.h" #include @@ -21,6 +22,8 @@ #define ID_CONSOLE 2002 #define ID_APP 2003 #define ID_GRACEFUL_SHUTDOWN 2004 +#define ID_STOP_GRACEFUL_SHUTDOWN 2005 +#define ID_RELOAD 2006 #define ID_TRAY_ICON 2050 #define WM_TRAYICON (WM_USER + 1) @@ -39,7 +42,11 @@ namespace win32 InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_APP, "Show app"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_ABOUT, "&About..."); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); - InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_GRACEFUL_SHUTDOWN, "&Graceful shutdown"); + InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_RELOAD, "&Reload configs"); + if (!i2p::util::DaemonWin32::Instance ().isGraceful) + InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_GRACEFUL_SHUTDOWN, "&Graceful shutdown"); + else + InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_STOP_GRACEFUL_SHUTDOWN, "&Stop graceful shutdown"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_EXIT, "E&xit"); SetMenuDefaultItem (hPopup, ID_CONSOLE, FALSE); SendMessage (hWnd, WM_INITMENUPOPUP, (WPARAM)hPopup, 0); @@ -68,7 +75,7 @@ namespace win32 nid.uCallbackMessage = WM_TRAYICON; nid.hIcon = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE (MAINICON)); strcpy (nid.szTip, "i2pd"); - strcpy (nid.szInfo, "i2pd is running"); + strcpy (nid.szInfo, "i2pd is starting"); Shell_NotifyIcon(NIM_ADD, &nid ); } @@ -120,6 +127,7 @@ namespace win32 static void PrintMainWindowText (std::stringstream& s) { + s << "\n"; s << "Status: "; switch (i2p::context.GetStatus()) { @@ -153,6 +161,7 @@ namespace win32 s << "In: " << i2p::tunnel::tunnels.CountInboundTunnels() << "; "; s << "Out: " << i2p::tunnel::tunnels.CountOutboundTunnels() << "; "; s << "Transit: " << i2p::tunnel::tunnels.CountTransitTunnels() << "\n"; + s << "\n"; } static LRESULT CALLBACK WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) @@ -192,6 +201,22 @@ namespace win32 { i2p::context.SetAcceptsTunnels (false); SetTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER, 10*60*1000, nullptr); // 10 minutes + i2p::util::DaemonWin32::Instance ().isGraceful = true; + return 0; + } + case ID_STOP_GRACEFUL_SHUTDOWN: + { + i2p::context.SetAcceptsTunnels (true); + KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER); + i2p::util::DaemonWin32::Instance ().isGraceful = false; + return 0; + } + case ID_RELOAD: + { + i2p::client::context.ReloadConfig(); + std::stringstream text; + text << "I2Pd reloading configs..."; + MessageBox( hWnd, TEXT(text.str ().c_str ()), TEXT("i2pd"), MB_ICONINFORMATION | MB_OK ); return 0; } case ID_CONSOLE: @@ -322,7 +347,7 @@ namespace win32 wclx.lpszClassName = I2PD_WIN32_CLASSNAME; RegisterClassEx (&wclx); // create new window - if (!CreateWindow(I2PD_WIN32_CLASSNAME, TEXT("i2pd"), WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, 100, 100, 350, 180, NULL, NULL, hInst, NULL)) + if (!CreateWindow(I2PD_WIN32_CLASSNAME, TEXT("i2pd"), WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, 100, 100, 350, 210, NULL, NULL, hInst, NULL)) { MessageBox(NULL, "Failed to create main window", TEXT("Warning!"), MB_ICONERROR | MB_OK | MB_TOPMOST); return false; @@ -353,5 +378,14 @@ namespace win32 PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_GRACEFUL_SHUTDOWN, 0), 0); return hWnd; } + + bool StopGracefulShutdown () + { + HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")); + if (hWnd) + PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_STOP_GRACEFUL_SHUTDOWN, 0), 0); + return hWnd; + } + } } diff --git a/Win32/Win32App.h b/Win32/Win32App.h index 3babffa9..b230eb06 100644 --- a/Win32/Win32App.h +++ b/Win32/Win32App.h @@ -7,10 +7,11 @@ namespace i2p { namespace win32 { - bool StartWin32App (); - void StopWin32App (); - int RunWin32App (); - bool GracefulShutdown (); + bool StartWin32App (); + void StopWin32App (); + int RunWin32App (); + bool GracefulShutdown (); + bool StopGracefulShutdown (); } } #endif // WIN32APP_H__ diff --git a/daemon/Daemon.h b/daemon/Daemon.h index 2bc05462..48301e73 100644 --- a/daemon/Daemon.h +++ b/daemon/Daemon.h @@ -6,11 +6,11 @@ namespace i2p { - namespace util +namespace util +{ + class Daemon_Singleton_Private; + class Daemon_Singleton { - class Daemon_Singleton_Private; - class Daemon_Singleton - { public: virtual bool init(int argc, char* argv[]); virtual bool start(); @@ -29,40 +29,38 @@ namespace i2p // d-pointer for httpServer, httpProxy, etc. class Daemon_Singleton_Private; Daemon_Singleton_Private &d; - }; + }; #if defined(QT_GUI_LIB) // check if QT #define Daemon i2p::util::DaemonQT::Instance() - // dummy, invoked from RunQT - class DaemonQT: public i2p::util::Daemon_Singleton + // dummy, invoked from RunQT + class DaemonQT: public i2p::util::Daemon_Singleton { public: - static DaemonQT& Instance() { static DaemonQT instance; return instance; } - }; + }; #elif defined(ANDROID) #define Daemon i2p::util::DaemonAndroid::Instance() // dummy, invoked from android/jni/DaemonAndroid.* - class DaemonAndroid: public i2p::util::Daemon_Singleton + class DaemonAndroid: public i2p::util::Daemon_Singleton { public: - static DaemonAndroid& Instance() { static DaemonAndroid instance; return instance; } - }; + }; #elif defined(_WIN32) #define Daemon i2p::util::DaemonWin32::Instance() - class DaemonWin32 : public Daemon_Singleton - { + class DaemonWin32 : public Daemon_Singleton + { public: static DaemonWin32& Instance() { @@ -74,34 +72,36 @@ namespace i2p bool start(); bool stop(); void run (); - }; -#else -#define Daemon i2p::util::DaemonLinux::Instance() - class DaemonLinux : public Daemon_Singleton - { - public: - static DaemonLinux& Instance() - { - static DaemonLinux instance; - return instance; - } - bool start(); - bool stop(); - void run (); + bool isGraceful; - private: + DaemonWin32 ():isGraceful(false) {} + }; - std::string pidfile; - int pidFH; +#else +#define Daemon i2p::util::DaemonLinux::Instance() + class DaemonLinux : public Daemon_Singleton + { + public: + static DaemonLinux& Instance() + { + static DaemonLinux instance; + return instance; + } - public: + bool start(); + bool stop(); + void run (); - int gracefulShutdownInterval; // in seconds + private: + std::string pidfile; + int pidFH; - }; + public: + int gracefulShutdownInterval; // in seconds + }; #endif - } +} } #endif // DAEMON_H__ diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index f3f9bb74..d6a358cf 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -58,9 +58,9 @@ namespace http { " .left { float: left; position: absolute; }\r\n" " .right { float: left; font-size: 1em; margin-left: 13em; max-width: 46em; overflow: auto; }\r\n" " .tunnel.established { color: #56B734; }\r\n" - " .tunnel.expiring { color: #D3AE3F; }\r\n" - " .tunnel.failed { color: #D33F3F; }\r\n" - " .tunnel.another { color: #434343; }\r\n" + " .tunnel.expiring { color: #D3AE3F; }\r\n" + " .tunnel.failed { color: #D33F3F; }\r\n" + " .tunnel.another { color: #434343; }\r\n" " caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n" " table { width: 100%; border-collapse: collapse; text-align: center; }\r\n" " .private { background: black; color: black; } .private:hover { background: black; color: white } \r\n" @@ -89,7 +89,7 @@ namespace http { 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; @@ -125,11 +125,11 @@ namespace http { std::string state; switch (eState) { case i2p::tunnel::eTunnelStateBuildReplyReceived : - case i2p::tunnel::eTunnelStatePending : state = "building"; break; + case i2p::tunnel::eTunnelStatePending : state = "building"; break; case i2p::tunnel::eTunnelStateBuildFailed : case i2p::tunnel::eTunnelStateTestFailed : - case i2p::tunnel::eTunnelStateFailed : state = "failed"; break; - case i2p::tunnel::eTunnelStateExpiring : state = "expiring"; break; + case i2p::tunnel::eTunnelStateFailed : state = "failed"; break; + case i2p::tunnel::eTunnelStateExpiring : state = "expiring"; break; case i2p::tunnel::eTunnelStateEstablished : state = "established"; break; default: state = "unknown"; break; } @@ -185,7 +185,7 @@ namespace http { s << "ERROR: " << string << "
\r\n"; } - void ShowStatus (std::stringstream& s, bool includeHiddenContent) + void ShowStatus (std::stringstream& s, bool includeHiddenContent) { s << "Uptime: "; ShowUptime(s, i2p::context.GetUptime ()); @@ -195,21 +195,21 @@ namespace http { { case eRouterStatusOK: s << "OK"; break; case eRouterStatusTesting: s << "Testing"; break; - case eRouterStatusFirewalled: s << "Firewalled"; break; - case eRouterStatusError: - { - s << "Error"; + case eRouterStatusFirewalled: s << "Firewalled"; break; + case eRouterStatusError: + { + s << "Error"; switch (i2p::context.GetError ()) { case eRouterErrorClockSkew: - s << "
Clock skew"; + s << "
Clock skew"; break; - default: ; - } + default: ; + } break; - } + } default: s << "Unknown"; - } + } s << "
\r\n"; #if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) if (auto remains = Daemon.gracefulShutdownInterval) { @@ -230,38 +230,38 @@ namespace http { s << " (" << (double) i2p::transport::transports.GetOutBandwidth () / 1024 << " KiB/s)
\r\n"; s << "Transit: "; ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ()); - s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " KiB/s)
\r\n"; + s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " KiB/s)
\r\n"; s << "Data path: " << i2p::fs::GetDataDir() << "
\r\n"; s << "
\r\n\r\n

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

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

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

\r\n"; int counter = 1; // for each lease set i2p::data::netdb.VisitLeaseSets( - [&s, &counter](const i2p::data::IdentHash dest, std::shared_ptr leaseSet) + [&s, &counter](const i2p::data::IdentHash dest, std::shared_ptr leaseSet) { // create copy of lease set so we extract leases i2p::data::LeaseSet ls(leaseSet->GetBuffer(), leaseSet->GetBufferLen()); @@ -432,7 +432,7 @@ namespace http { // end for each lease set } - void ShowTunnels (std::stringstream& s) + void ShowTunnels (std::stringstream& s) { s << "Queue size: " << i2p::tunnel::tunnels.GetQueueSize () << "
\r\n"; @@ -454,7 +454,7 @@ namespace http { s << "
\r\n"; } - static void ShowCommands (std::stringstream& s, uint32_t token) + static void ShowCommands (std::stringstream& s, uint32_t token) { /* commands */ s << "Router Commands
\r\n"; @@ -465,18 +465,20 @@ namespace http { else s << " Accept transit tunnels
\r\n"; #if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) - if (Daemon.gracefulShutdownInterval) + if (Daemon.gracefulShutdownInterval) s << " Cancel graceful shutdown
"; - else + else s << " Start graceful shutdown
\r\n"; -#endif -#ifdef WIN32_APP - s << " Graceful shutdown
\r\n"; +#elif defined(WIN32_APP) + if (i2p::util::DaemonWin32::Instance().isGraceful) + s << " Cancel graceful shutdown
"; + else + s << " Graceful shutdown
\r\n"; #endif s << " Force shutdown
\r\n"; } - void ShowTransitTunnels (std::stringstream& s) + void ShowTransitTunnels (std::stringstream& s) { s << "Transit tunnels:
\r\n
\r\n"; for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ()) @@ -491,10 +493,10 @@ namespace http { } } - void ShowTransports (std::stringstream& s) + void ShowTransports (std::stringstream& s) { s << "Transports:
\r\n
\r\n"; - auto ntcpServer = i2p::transport::transports.GetNTCPServer (); + auto ntcpServer = i2p::transport::transports.GetNTCPServer (); if (ntcpServer) { auto sessions = ntcpServer->GetNTCPSessions (); @@ -577,7 +579,7 @@ namespace http { } } - void ShowSAMSessions (std::stringstream& s) + void ShowSAMSessions (std::stringstream& s) { auto sam = i2p::client::context.GetSAMBridge (); if (!sam) { @@ -624,13 +626,13 @@ namespace http { } } - void ShowI2PTunnels (std::stringstream& s) + void ShowI2PTunnels (std::stringstream& s) { s << "Client Tunnels:
\r\n
\r\n"; for (auto& it: i2p::client::context.GetClientTunnels ()) { auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); - s << ""; + s << ""; s << it.second->GetName () << " ⇐ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << "
\r\n"<< std::endl; @@ -639,16 +641,16 @@ namespace http { if (httpProxy) { auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash(); - s << ""; + s << ""; s << "HTTP Proxy" << " ⇐ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << "
\r\n"<< std::endl; - } + } auto socksProxy = i2p::client::context.GetSocksProxy (); if (socksProxy) { auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash(); - s << ""; + s << ""; s << "SOCKS Proxy" << " ⇐ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << "
\r\n"<< std::endl; @@ -659,7 +661,7 @@ namespace http { for (auto& it: serverTunnels) { auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); - s << ""; + s << ""; s << it.second->GetName () << " ⇒ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << ":" << it.second->GetLocalPort (); @@ -673,7 +675,7 @@ namespace http { for (auto& it: clientForwards) { auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); - s << ""; + s << ""; s << it.second->GetName () << " ⇐ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << "
\r\n"<< std::endl; @@ -686,7 +688,7 @@ namespace http { for (auto& it: serverForwards) { auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); - s << ""; + s << ""; s << it.second->GetName () << " ⇐ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << "
\r\n"<< std::endl; @@ -756,10 +758,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]; @@ -802,7 +804,7 @@ namespace http { } else if (req.uri.find("cmd=") != std::string::npos) { HandleCommand (req, res, s); } else { - ShowStatus (s, true); + ShowStatus (s, true); res.add_header("Refresh", "10"); } ShowPageTail (s); @@ -814,7 +816,7 @@ namespace http { std::map HTTPConnection::m_Tokens; void HTTPConnection::HandlePage (const HTTPReq& req, HTTPRes& res, std::stringstream& s) - { + { std::map params; std::string page(""); URL url; @@ -840,13 +842,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) @@ -864,7 +866,7 @@ namespace http { ShowError(s, "Unknown page: " + page); return; } - } + } void HTTPConnection::HandleCommand (const HTTPReq& req, HTTPRes& res, std::stringstream& s) { @@ -881,7 +883,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) @@ -894,14 +896,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; @@ -940,7 +943,7 @@ namespace http { void HTTPServer::Start () { - bool needAuth; i2p::config::GetOption("http.auth", needAuth); + bool needAuth; i2p::config::GetOption("http.auth", needAuth); std::string user; i2p::config::GetOption("http.user", user); std::string pass; i2p::config::GetOption("http.pass", pass); /* generate pass if needed */ @@ -968,7 +971,7 @@ namespace http { m_IsRunning = false; m_Acceptor.close(); m_Service.stop (); - if (m_Thread) + if (m_Thread) { m_Thread->join (); m_Thread = nullptr; @@ -986,7 +989,7 @@ namespace http { catch (std::exception& ex) { LogPrint (eLogError, "HTTPServer: runtime exception: ", ex.what ()); - } + } } } @@ -997,7 +1000,7 @@ namespace http { boost::asio::placeholders::error, newSocket)); } - void HTTPServer::HandleAccept(const boost::system::error_code& ecode, + void HTTPServer::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr newSocket) { if (ecode) @@ -1005,7 +1008,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);