Browse Source

add graceful shutdown in webconsole for windows

add stop graceful shutdown menu item
add reload menu item
pull/966/head
R4SAS 7 years ago
parent
commit
dd4f066e95
  1. 140
      Win32/DaemonWin32.cpp
  2. 40
      Win32/Win32App.cpp
  3. 9
      Win32/Win32App.h
  4. 70
      daemon/Daemon.h
  5. 199
      daemon/HTTPServer.cpp

140
Win32/DaemonWin32.cpp

@ -14,99 +14,99 @@
namespace i2p 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);
setlocale(LC_CTYPE, ""); SetConsoleOutputCP(1251);
SetConsoleCP(1251); setlocale(LC_ALL, "Russian");
SetConsoleOutputCP(1251);
setlocale(LC_ALL, "Russian");
if (!Daemon_Singleton::init(argc, argv)) if (!Daemon_Singleton::init(argc, argv))
return false; return false;
std::string serviceControl; i2p::config::GetOption("svcctl", serviceControl); std::string serviceControl; i2p::config::GetOption("svcctl", serviceControl);
if (serviceControl == "install") if (serviceControl == "install")
{ {
LogPrint(eLogInfo, "WinSVC: installing ", SERVICE_NAME, " as service"); LogPrint(eLogInfo, "WinSVC: installing ", SERVICE_NAME, " as service");
InstallService( InstallService(
SERVICE_NAME, // Name of service SERVICE_NAME, // Name of service
SERVICE_DISPLAY_NAME, // Name to display SERVICE_DISPLAY_NAME, // Name to display
SERVICE_START_TYPE, // Service start type SERVICE_START_TYPE, // Service start type
SERVICE_DEPENDENCIES, // Dependencies SERVICE_DEPENDENCIES, // Dependencies
SERVICE_ACCOUNT, // Service running account SERVICE_ACCOUNT, // Service running account
SERVICE_PASSWORD // Password of the account SERVICE_PASSWORD // Password of the account
); );
return false; return false;
} }
else if (serviceControl == "remove") else if (serviceControl == "remove")
{ {
LogPrint(eLogInfo, "WinSVC: uninstalling ", SERVICE_NAME, " service"); LogPrint(eLogInfo, "WinSVC: uninstalling ", SERVICE_NAME, " service");
UninstallService(SERVICE_NAME); UninstallService(SERVICE_NAME);
return false; 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"); LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError());
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; return false;
} }
else return false;
LogPrint(eLogDebug, "Daemon: running as user");
return true;
} }
else
LogPrint(eLogDebug, "Daemon: running as user");
return true;
}
bool DaemonWin32::start() bool DaemonWin32::start()
{ {
setlocale(LC_CTYPE, ""); setlocale(LC_CTYPE, "");
SetConsoleCP(1251); SetConsoleCP(1251);
SetConsoleOutputCP(1251); SetConsoleOutputCP(1251);
setlocale(LC_ALL, "Russian"); setlocale(LC_ALL, "Russian");
#ifdef WIN32_APP #ifdef WIN32_APP
if (!i2p::win32::StartWin32App ()) return false; if (!i2p::win32::StartWin32App ()) return false;
// override log // override log
i2p::config::SetOption("log", std::string ("file")); i2p::config::SetOption("log", std::string ("file"));
#endif #endif
bool ret = Daemon_Singleton::start(); bool ret = Daemon_Singleton::start();
if (ret && i2p::log::Logger().GetLogType() == eLogFile) if (ret && i2p::log::Logger().GetLogType() == eLogFile)
{ {
// TODO: find out where this garbage to console comes from // TODO: find out where this garbage to console comes from
SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE); SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE);
SetStdHandle(STD_ERROR_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 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 #ifdef WIN32_APP
i2p::win32::StopWin32App (); i2p::win32::StopWin32App ();
#endif #endif
return Daemon_Singleton::stop(); return Daemon_Singleton::stop();
} }
void DaemonWin32::run () void DaemonWin32::run ()
{ {
#ifdef WIN32_APP #ifdef WIN32_APP
i2p::win32::RunWin32App (); i2p::win32::RunWin32App ();
#else #else
while (running) while (running)
{ {
std::this_thread::sleep_for (std::chrono::seconds(1)); std::this_thread::sleep_for (std::chrono::seconds(1));
} }
#endif #endif
}
} }
} }
}
#endif #endif

40
Win32/Win32App.cpp

@ -9,6 +9,7 @@
#include "Tunnel.h" #include "Tunnel.h"
#include "version.h" #include "version.h"
#include "resource.h" #include "resource.h"
#include "Daemon.h"
#include "Win32App.h" #include "Win32App.h"
#include <stdio.h> #include <stdio.h>
@ -21,6 +22,8 @@
#define ID_CONSOLE 2002 #define ID_CONSOLE 2002
#define ID_APP 2003 #define ID_APP 2003
#define ID_GRACEFUL_SHUTDOWN 2004 #define ID_GRACEFUL_SHUTDOWN 2004
#define ID_STOP_GRACEFUL_SHUTDOWN 2005
#define ID_RELOAD 2006
#define ID_TRAY_ICON 2050 #define ID_TRAY_ICON 2050
#define WM_TRAYICON (WM_USER + 1) #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_APP, "Show app");
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_ABOUT, "&About..."); 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_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"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_EXIT, "E&xit");
SetMenuDefaultItem (hPopup, ID_CONSOLE, FALSE); SetMenuDefaultItem (hPopup, ID_CONSOLE, FALSE);
SendMessage (hWnd, WM_INITMENUPOPUP, (WPARAM)hPopup, 0); SendMessage (hWnd, WM_INITMENUPOPUP, (WPARAM)hPopup, 0);
@ -68,7 +75,7 @@ namespace win32
nid.uCallbackMessage = WM_TRAYICON; nid.uCallbackMessage = WM_TRAYICON;
nid.hIcon = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE (MAINICON)); nid.hIcon = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE (MAINICON));
strcpy (nid.szTip, "i2pd"); strcpy (nid.szTip, "i2pd");
strcpy (nid.szInfo, "i2pd is running"); strcpy (nid.szInfo, "i2pd is starting");
Shell_NotifyIcon(NIM_ADD, &nid ); Shell_NotifyIcon(NIM_ADD, &nid );
} }
@ -120,6 +127,7 @@ namespace win32
static void PrintMainWindowText (std::stringstream& s) static void PrintMainWindowText (std::stringstream& s)
{ {
s << "\n";
s << "Status: "; s << "Status: ";
switch (i2p::context.GetStatus()) switch (i2p::context.GetStatus())
{ {
@ -153,6 +161,7 @@ namespace win32
s << "In: " << i2p::tunnel::tunnels.CountInboundTunnels() << "; "; s << "In: " << i2p::tunnel::tunnels.CountInboundTunnels() << "; ";
s << "Out: " << i2p::tunnel::tunnels.CountOutboundTunnels() << "; "; s << "Out: " << i2p::tunnel::tunnels.CountOutboundTunnels() << "; ";
s << "Transit: " << i2p::tunnel::tunnels.CountTransitTunnels() << "\n"; s << "Transit: " << i2p::tunnel::tunnels.CountTransitTunnels() << "\n";
s << "\n";
} }
static LRESULT CALLBACK WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) static LRESULT CALLBACK WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
@ -192,6 +201,22 @@ namespace win32
{ {
i2p::context.SetAcceptsTunnels (false); i2p::context.SetAcceptsTunnels (false);
SetTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER, 10*60*1000, nullptr); // 10 minutes 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; return 0;
} }
case ID_CONSOLE: case ID_CONSOLE:
@ -322,7 +347,7 @@ namespace win32
wclx.lpszClassName = I2PD_WIN32_CLASSNAME; wclx.lpszClassName = I2PD_WIN32_CLASSNAME;
RegisterClassEx (&wclx); RegisterClassEx (&wclx);
// create new window // 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); MessageBox(NULL, "Failed to create main window", TEXT("Warning!"), MB_ICONERROR | MB_OK | MB_TOPMOST);
return false; return false;
@ -353,5 +378,14 @@ namespace win32
PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_GRACEFUL_SHUTDOWN, 0), 0); PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_GRACEFUL_SHUTDOWN, 0), 0);
return hWnd; 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;
}
} }
} }

9
Win32/Win32App.h

@ -7,10 +7,11 @@ namespace i2p
{ {
namespace win32 namespace win32
{ {
bool StartWin32App (); bool StartWin32App ();
void StopWin32App (); void StopWin32App ();
int RunWin32App (); int RunWin32App ();
bool GracefulShutdown (); bool GracefulShutdown ();
bool StopGracefulShutdown ();
} }
} }
#endif // WIN32APP_H__ #endif // WIN32APP_H__

70
daemon/Daemon.h

@ -6,11 +6,11 @@
namespace i2p namespace i2p
{ {
namespace util namespace util
{
class Daemon_Singleton_Private;
class Daemon_Singleton
{ {
class Daemon_Singleton_Private;
class Daemon_Singleton
{
public: public:
virtual bool init(int argc, char* argv[]); virtual bool init(int argc, char* argv[]);
virtual bool start(); virtual bool start();
@ -29,40 +29,38 @@ namespace i2p
// d-pointer for httpServer, httpProxy, etc. // d-pointer for httpServer, httpProxy, etc.
class Daemon_Singleton_Private; class Daemon_Singleton_Private;
Daemon_Singleton_Private &d; Daemon_Singleton_Private &d;
}; };
#if defined(QT_GUI_LIB) // check if QT #if defined(QT_GUI_LIB) // check if QT
#define Daemon i2p::util::DaemonQT::Instance() #define Daemon i2p::util::DaemonQT::Instance()
// dummy, invoked from RunQT // dummy, invoked from RunQT
class DaemonQT: public i2p::util::Daemon_Singleton class DaemonQT: public i2p::util::Daemon_Singleton
{ {
public: public:
static DaemonQT& Instance() static DaemonQT& Instance()
{ {
static DaemonQT instance; static DaemonQT instance;
return instance; return instance;
} }
}; };
#elif defined(ANDROID) #elif defined(ANDROID)
#define Daemon i2p::util::DaemonAndroid::Instance() #define Daemon i2p::util::DaemonAndroid::Instance()
// dummy, invoked from android/jni/DaemonAndroid.* // dummy, invoked from android/jni/DaemonAndroid.*
class DaemonAndroid: public i2p::util::Daemon_Singleton class DaemonAndroid: public i2p::util::Daemon_Singleton
{ {
public: public:
static DaemonAndroid& Instance() static DaemonAndroid& Instance()
{ {
static DaemonAndroid instance; static DaemonAndroid instance;
return instance; return instance;
} }
}; };
#elif defined(_WIN32) #elif defined(_WIN32)
#define Daemon i2p::util::DaemonWin32::Instance() #define Daemon i2p::util::DaemonWin32::Instance()
class DaemonWin32 : public Daemon_Singleton class DaemonWin32 : public Daemon_Singleton
{ {
public: public:
static DaemonWin32& Instance() static DaemonWin32& Instance()
{ {
@ -74,34 +72,36 @@ namespace i2p
bool start(); bool start();
bool stop(); bool stop();
void run (); 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 isGraceful;
bool stop();
void run ();
private: DaemonWin32 ():isGraceful(false) {}
};
std::string pidfile; #else
int pidFH; #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
} }
} }
#endif // DAEMON_H__ #endif // DAEMON_H__

199
daemon/HTTPServer.cpp

@ -58,9 +58,9 @@ namespace http {
" .left { float: left; position: absolute; }\r\n" " .left { float: left; position: absolute; }\r\n"
" .right { float: left; font-size: 1em; margin-left: 13em; max-width: 46em; overflow: auto; }\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.established { color: #56B734; }\r\n"
" .tunnel.expiring { color: #D3AE3F; }\r\n" " .tunnel.expiring { color: #D3AE3F; }\r\n"
" .tunnel.failed { color: #D33F3F; }\r\n" " .tunnel.failed { color: #D33F3F; }\r\n"
" .tunnel.another { color: #434343; }\r\n" " .tunnel.another { color: #434343; }\r\n"
" caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n" " caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n"
" table { width: 100%; border-collapse: collapse; text-align: center; }\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" " .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_SAM_SESSION_ID[] = "id";
const char HTTP_PARAM_ADDRESS[] = "address"; const char HTTP_PARAM_ADDRESS[] = "address";
static void ShowUptime (std::stringstream& s, int seconds) static void ShowUptime (std::stringstream& s, int seconds)
{ {
int num; int num;
@ -125,11 +125,11 @@ namespace http {
std::string state; std::string state;
switch (eState) { switch (eState) {
case i2p::tunnel::eTunnelStateBuildReplyReceived : 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::eTunnelStateBuildFailed :
case i2p::tunnel::eTunnelStateTestFailed : case i2p::tunnel::eTunnelStateTestFailed :
case i2p::tunnel::eTunnelStateFailed : state = "failed"; break; case i2p::tunnel::eTunnelStateFailed : state = "failed"; break;
case i2p::tunnel::eTunnelStateExpiring : state = "expiring"; break; case i2p::tunnel::eTunnelStateExpiring : state = "expiring"; break;
case i2p::tunnel::eTunnelStateEstablished : state = "established"; break; case i2p::tunnel::eTunnelStateEstablished : state = "established"; break;
default: state = "unknown"; break; default: state = "unknown"; break;
} }
@ -185,7 +185,7 @@ namespace http {
s << "<b>ERROR:</b>&nbsp;" << string << "<br>\r\n"; s << "<b>ERROR:</b>&nbsp;" << string << "<br>\r\n";
} }
void ShowStatus (std::stringstream& s, bool includeHiddenContent) void ShowStatus (std::stringstream& s, bool includeHiddenContent)
{ {
s << "<b>Uptime:</b> "; s << "<b>Uptime:</b> ";
ShowUptime(s, i2p::context.GetUptime ()); ShowUptime(s, i2p::context.GetUptime ());
@ -195,21 +195,21 @@ namespace http {
{ {
case eRouterStatusOK: s << "OK"; break; case eRouterStatusOK: s << "OK"; break;
case eRouterStatusTesting: s << "Testing"; break; case eRouterStatusTesting: s << "Testing"; break;
case eRouterStatusFirewalled: s << "Firewalled"; break; case eRouterStatusFirewalled: s << "Firewalled"; break;
case eRouterStatusError: case eRouterStatusError:
{ {
s << "Error"; s << "Error";
switch (i2p::context.GetError ()) switch (i2p::context.GetError ())
{ {
case eRouterErrorClockSkew: case eRouterErrorClockSkew:
s << "<br>Clock skew"; s << "<br>Clock skew";
break; break;
default: ; default: ;
} }
break; break;
} }
default: s << "Unknown"; default: s << "Unknown";
} }
s << "<br>\r\n"; s << "<br>\r\n";
#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) #if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID))
if (auto remains = Daemon.gracefulShutdownInterval) { if (auto remains = Daemon.gracefulShutdownInterval) {
@ -230,38 +230,38 @@ namespace http {
s << " (" << (double) i2p::transport::transports.GetOutBandwidth () / 1024 << " KiB/s)<br>\r\n"; s << " (" << (double) i2p::transport::transports.GetOutBandwidth () / 1024 << " KiB/s)<br>\r\n";
s << "<b>Transit:</b> "; s << "<b>Transit:</b> ";
ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ()); 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 << "<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 << "<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";
if(includeHiddenContent) { if(includeHiddenContent) {
s << "<b>Router Ident:</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\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 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>Router Caps:</b> " << i2p::context.GetRouterInfo().GetProperty("caps") << "<br>\r\n";
s << "<b>Our external address:</b>" << "<br>\r\n" ; s << "<b>Our external address:</b>" << "<br>\r\n" ;
for (const auto& address : i2p::context.GetRouterInfo().GetAddresses()) for (const auto& address : i2p::context.GetRouterInfo().GetAddresses())
{ {
switch (address->transportStyle) switch (address->transportStyle)
{ {
case i2p::data::RouterInfo::eTransportNTCP: case i2p::data::RouterInfo::eTransportNTCP:
if (address->host.is_v6 ()) if (address->host.is_v6 ())
s << "NTCP6&nbsp;&nbsp;"; s << "NTCP6&nbsp;&nbsp;";
else else
s << "NTCP&nbsp;&nbsp;"; s << "NTCP&nbsp;&nbsp;";
break; break;
case i2p::data::RouterInfo::eTransportSSU: case i2p::data::RouterInfo::eTransportSSU:
if (address->host.is_v6 ()) if (address->host.is_v6 ())
s << "SSU6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"; s << "SSU6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
else else
s << "SSU&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"; s << "SSU&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
break; break;
default: default:
s << "Unknown&nbsp;&nbsp;"; 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 << "</p>\r\n</div>\r\n";
s << "<b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " "; s << "<b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " ";
s << "<b>Floodfills:</b> " << i2p::data::netdb.GetNumFloodfills () << " "; s << "<b>Floodfills:</b> " << i2p::data::netdb.GetNumFloodfills () << " ";
s << "<b>LeaseSets:</b> " << i2p::data::netdb.GetNumLeaseSets () << "<br>\r\n"; s << "<b>LeaseSets:</b> " << i2p::data::netdb.GetNumLeaseSets () << "<br>\r\n";
@ -273,13 +273,13 @@ namespace http {
s << "<b>Transit Tunnels:</b> " << std::to_string(transitTunnelCount) << "<br>\r\n"; s << "<b>Transit Tunnels:</b> " << std::to_string(transitTunnelCount) << "<br>\r\n";
} }
void ShowLocalDestinations (std::stringstream& s) void ShowLocalDestinations (std::stringstream& s)
{ {
s << "<b>Local Destinations:</b><br>\r\n<br>\r\n"; s << "<b>Local Destinations:</b><br>\r\n<br>\r\n";
for (auto& it: i2p::client::context.GetDestinations ()) for (auto& it: i2p::client::context.GetDestinations ())
{ {
auto ident = it.second->GetIdentHash (); auto ident = it.second->GetIdentHash ();
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">"; s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n" << std::endl; s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n" << std::endl;
} }
@ -291,11 +291,11 @@ namespace http {
{ {
auto dest = it.second->GetDestination (); auto dest = it.second->GetDestination ();
if (dest) if (dest)
{ {
auto ident = dest->GetIdentHash (); auto ident = dest->GetIdentHash ();
s << "<a href=\"/?page=" << HTTP_PAGE_I2CP_LOCAL_DESTINATION << "&i2cp_id=" << it.first << "\">"; 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; s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n" << std::endl;
} }
} }
} }
} }
@ -341,7 +341,7 @@ namespace http {
s << "<br>" << std::endl; s << "<br>" << std::endl;
} }
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"; s << "<b>Local Destination:</b><br>\r\n<br>\r\n";
i2p::data::IdentHash ident; i2p::data::IdentHash ident;
@ -349,7 +349,7 @@ namespace http {
auto dest = i2p::client::context.FindLocalDestination (ident); auto dest = i2p::client::context.FindLocalDestination (ident);
if (dest) if (dest)
{ {
ShowLeaseSetDestination (s, dest); ShowLeaseSetDestination (s, dest);
// show streams // show streams
s << "<br>\r\n<table><caption>Streams</caption><tr>"; s << "<br>\r\n<table><caption>Streams</caption><tr>";
s << "<th>StreamID</th>"; s << "<th>StreamID</th>";
@ -377,35 +377,35 @@ namespace http {
s << "<td>" << it->GetRTT () << "</td>"; s << "<td>" << it->GetRTT () << "</td>";
s << "<td>" << it->GetWindowSize () << "</td>"; s << "<td>" << it->GetWindowSize () << "</td>";
s << "<td>" << (int)it->GetStatus () << "</td>"; s << "<td>" << (int)it->GetStatus () << "</td>";
s << "</tr><br>\r\n" << std::endl; s << "</tr><br>\r\n" << std::endl;
} }
s << "</table>"; 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 (); auto i2cpServer = i2p::client::context.GetI2CPServer ();
if (i2cpServer) if (i2cpServer)
{ {
s << "<b>I2CP Local Destination:</b><br>\r\n<br>\r\n"; 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 ()) if (it != i2cpServer->GetSessions ().end ())
ShowLeaseSetDestination (s, it->second->GetDestination ()); ShowLeaseSetDestination (s, it->second->GetDestination ());
else else
ShowError(s, "I2CP session not found"); ShowError(s, "I2CP session not found");
} }
else else
ShowError(s, "I2CP is not enabled"); ShowError(s, "I2CP is not enabled");
} }
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"; s << "<div id='leasesets'><b>LeaseSets (click on to show info):</b></div><br>\r\n";
int counter = 1; int counter = 1;
// for each lease set // for each lease set
i2p::data::netdb.VisitLeaseSets( 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 // create copy of lease set so we extract leases
i2p::data::LeaseSet ls(leaseSet->GetBuffer(), leaseSet->GetBufferLen()); i2p::data::LeaseSet ls(leaseSet->GetBuffer(), leaseSet->GetBufferLen());
@ -432,7 +432,7 @@ namespace http {
// end for each lease set // end for each lease set
} }
void ShowTunnels (std::stringstream& s) void ShowTunnels (std::stringstream& s)
{ {
s << "<b>Queue size:</b> " << i2p::tunnel::tunnels.GetQueueSize () << "<br>\r\n"; s << "<b>Queue size:</b> " << i2p::tunnel::tunnels.GetQueueSize () << "<br>\r\n";
@ -454,7 +454,7 @@ namespace http {
s << "<br>\r\n"; s << "<br>\r\n";
} }
static void ShowCommands (std::stringstream& s, uint32_t token) static void ShowCommands (std::stringstream& s, uint32_t token)
{ {
/* commands */ /* commands */
s << "<b>Router Commands</b><br>\r\n"; s << "<b>Router Commands</b><br>\r\n";
@ -465,18 +465,20 @@ namespace http {
else else
s << " <a href=\"/?cmd=" << HTTP_COMMAND_ENABLE_TRANSIT << "&token=" << token << "\">Accept transit tunnels</a><br>\r\n"; 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 (!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>"; 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"; s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Start graceful shutdown</a><br>\r\n";
#endif #elif defined(WIN32_APP)
#ifdef WIN32_APP if (i2p::util::DaemonWin32::Instance().isGraceful)
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Graceful shutdown</a><br>\r\n"; 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 #endif
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "&token=" << token << "\">Force shutdown</a><br>\r\n"; s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "&token=" << token << "\">Force shutdown</a><br>\r\n";
} }
void ShowTransitTunnels (std::stringstream& s) void ShowTransitTunnels (std::stringstream& s)
{ {
s << "<b>Transit tunnels:</b><br>\r\n<br>\r\n"; s << "<b>Transit tunnels:</b><br>\r\n<br>\r\n";
for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ()) 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 << "<b>Transports:</b><br>\r\n<br>\r\n"; s << "<b>Transports:</b><br>\r\n<br>\r\n";
auto ntcpServer = i2p::transport::transports.GetNTCPServer (); auto ntcpServer = i2p::transport::transports.GetNTCPServer ();
if (ntcpServer) if (ntcpServer)
{ {
auto sessions = ntcpServer->GetNTCPSessions (); 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 (); auto sam = i2p::client::context.GetSAMBridge ();
if (!sam) { if (!sam) {
@ -624,13 +626,13 @@ namespace http {
} }
} }
void ShowI2PTunnels (std::stringstream& s) void ShowI2PTunnels (std::stringstream& s)
{ {
s << "<b>Client Tunnels:</b><br>\r\n<br>\r\n"; s << "<b>Client Tunnels:</b><br>\r\n<br>\r\n";
for (auto& it: i2p::client::context.GetClientTunnels ()) for (auto& it: i2p::client::context.GetClientTunnels ())
{ {
auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); 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 << it.second->GetName () << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "<br>\r\n"<< std::endl; s << "<br>\r\n"<< std::endl;
@ -639,16 +641,16 @@ namespace http {
if (httpProxy) if (httpProxy)
{ {
auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash(); 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 << "HTTP Proxy" << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "<br>\r\n"<< std::endl; s << "<br>\r\n"<< std::endl;
} }
auto socksProxy = i2p::client::context.GetSocksProxy (); auto socksProxy = i2p::client::context.GetSocksProxy ();
if (socksProxy) if (socksProxy)
{ {
auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash(); 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 << "SOCKS Proxy" << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "<br>\r\n"<< std::endl; s << "<br>\r\n"<< std::endl;
@ -659,7 +661,7 @@ namespace http {
for (auto& it: serverTunnels) for (auto& it: serverTunnels)
{ {
auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); 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> &#8658; "; s << it.second->GetName () << "</a> &#8658; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << ":" << it.second->GetLocalPort (); s << ":" << it.second->GetLocalPort ();
@ -673,7 +675,7 @@ namespace http {
for (auto& it: clientForwards) for (auto& it: clientForwards)
{ {
auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); 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 << it.second->GetName () << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "<br>\r\n"<< std::endl; s << "<br>\r\n"<< std::endl;
@ -686,7 +688,7 @@ namespace http {
for (auto& it: serverForwards) for (auto& it: serverForwards)
{ {
auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); 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 << it.second->GetName () << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "<br>\r\n"<< std::endl; s << "<br>\r\n"<< std::endl;
@ -756,10 +758,10 @@ namespace http {
} }
/* method #2: 'Authorization' header sent */ /* method #2: 'Authorization' header sent */
auto provided = req.GetHeader ("Authorization"); auto provided = req.GetHeader ("Authorization");
if (provided.length () > 0) if (provided.length () > 0)
{ {
bool result = false; bool result = false;
std::string expected = user + ":" + pass; std::string expected = user + ":" + pass;
size_t b64_sz = i2p::data::Base64EncodingBufferSize(expected.length()) + 1; size_t b64_sz = i2p::data::Base64EncodingBufferSize(expected.length()) + 1;
char * b64_creds = new char[b64_sz]; char * b64_creds = new char[b64_sz];
@ -802,7 +804,7 @@ namespace http {
} else if (req.uri.find("cmd=") != std::string::npos) { } else if (req.uri.find("cmd=") != std::string::npos) {
HandleCommand (req, res, s); HandleCommand (req, res, s);
} else { } else {
ShowStatus (s, true); ShowStatus (s, true);
res.add_header("Refresh", "10"); res.add_header("Refresh", "10");
} }
ShowPageTail (s); ShowPageTail (s);
@ -814,7 +816,7 @@ namespace http {
std::map<uint32_t, uint32_t> HTTPConnection::m_Tokens; std::map<uint32_t, uint32_t> HTTPConnection::m_Tokens;
void HTTPConnection::HandlePage (const HTTPReq& req, HTTPRes& res, std::stringstream& s) void HTTPConnection::HandlePage (const HTTPReq& req, HTTPRes& res, std::stringstream& s)
{ {
std::map<std::string, std::string> params; std::map<std::string, std::string> params;
std::string page(""); std::string page("");
URL url; URL url;
@ -840,13 +842,13 @@ namespace http {
else else
++it; ++it;
} }
m_Tokens[token] = ts; m_Tokens[token] = ts;
ShowCommands (s, token); ShowCommands (s, token);
} }
else if (page == HTTP_PAGE_TRANSIT_TUNNELS) else if (page == HTTP_PAGE_TRANSIT_TUNNELS)
ShowTransitTunnels (s); ShowTransitTunnels (s);
else if (page == HTTP_PAGE_LOCAL_DESTINATIONS) else if (page == HTTP_PAGE_LOCAL_DESTINATIONS)
ShowLocalDestinations (s); ShowLocalDestinations (s);
else if (page == HTTP_PAGE_LOCAL_DESTINATION) else if (page == HTTP_PAGE_LOCAL_DESTINATION)
ShowLocalDestination (s, params["b32"]); ShowLocalDestination (s, params["b32"]);
else if (page == HTTP_PAGE_I2CP_LOCAL_DESTINATION) else if (page == HTTP_PAGE_I2CP_LOCAL_DESTINATION)
@ -864,7 +866,7 @@ namespace http {
ShowError(s, "Unknown page: " + page); ShowError(s, "Unknown page: " + page);
return; return;
} }
} }
void HTTPConnection::HandleCommand (const HTTPReq& req, HTTPRes& res, std::stringstream& s) void HTTPConnection::HandleCommand (const HTTPReq& req, HTTPRes& res, std::stringstream& s)
{ {
@ -881,7 +883,7 @@ namespace http {
return; return;
} }
std::string cmd = params["cmd"]; std::string cmd = params["cmd"];
if (cmd == HTTP_COMMAND_RUN_PEER_TEST) if (cmd == HTTP_COMMAND_RUN_PEER_TEST)
i2p::transport::transports.PeerTest (); i2p::transport::transports.PeerTest ();
else if (cmd == HTTP_COMMAND_RELOAD_CONFIG) else if (cmd == HTTP_COMMAND_RELOAD_CONFIG)
@ -894,14 +896,15 @@ namespace http {
i2p::context.SetAcceptsTunnels (false); i2p::context.SetAcceptsTunnels (false);
#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) #if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID))
Daemon.gracefulShutdownInterval = 10*60; Daemon.gracefulShutdownInterval = 10*60;
#endif #elif defined(WIN32_APP)
#ifdef WIN32_APP
i2p::win32::GracefulShutdown (); i2p::win32::GracefulShutdown ();
#endif #endif
} else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) { } else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) {
i2p::context.SetAcceptsTunnels (true); i2p::context.SetAcceptsTunnels (true);
#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) #if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID))
Daemon.gracefulShutdownInterval = 0; Daemon.gracefulShutdownInterval = 0;
#elif defined(WIN32_APP)
i2p::win32::StopGracefulShutdown ();
#endif #endif
} else if (cmd == HTTP_COMMAND_SHUTDOWN_NOW) { } else if (cmd == HTTP_COMMAND_SHUTDOWN_NOW) {
Daemon.running = false; Daemon.running = false;
@ -940,7 +943,7 @@ namespace http {
void HTTPServer::Start () 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 user; i2p::config::GetOption("http.user", user);
std::string pass; i2p::config::GetOption("http.pass", pass); std::string pass; i2p::config::GetOption("http.pass", pass);
/* generate pass if needed */ /* generate pass if needed */
@ -968,7 +971,7 @@ namespace http {
m_IsRunning = false; m_IsRunning = false;
m_Acceptor.close(); m_Acceptor.close();
m_Service.stop (); m_Service.stop ();
if (m_Thread) if (m_Thread)
{ {
m_Thread->join (); m_Thread->join ();
m_Thread = nullptr; m_Thread = nullptr;
@ -986,7 +989,7 @@ namespace http {
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "HTTPServer: runtime exception: ", ex.what ()); LogPrint (eLogError, "HTTPServer: runtime exception: ", ex.what ());
} }
} }
} }
@ -997,7 +1000,7 @@ namespace http {
boost::asio::placeholders::error, newSocket)); 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) std::shared_ptr<boost::asio::ip::tcp::socket> newSocket)
{ {
if (ecode) if (ecode)
@ -1005,7 +1008,7 @@ namespace http {
if(newSocket) newSocket->close(); if(newSocket) newSocket->close();
LogPrint(eLogError, "HTTP Server: error handling accept ", ecode.message()); LogPrint(eLogError, "HTTP Server: error handling accept ", ecode.message());
if(ecode != boost::asio::error::operation_aborted) if(ecode != boost::asio::error::operation_aborted)
Accept(); Accept();
return; return;
} }
CreateConnection(newSocket); CreateConnection(newSocket);

Loading…
Cancel
Save