diff --git a/I2PControl.cpp b/I2PControl.cpp index af4c8796..49085f5e 100644 --- a/I2PControl.cpp +++ b/I2PControl.cpp @@ -4,6 +4,9 @@ #include #include "Log.h" #include "NetDb.h" +#include "RouterContext.h" +#include "Daemon.h" +#include "Tunnel.h" #include "Timestamp.h" #include "I2PControl.h" @@ -13,11 +16,13 @@ namespace client { I2PControlService::I2PControlService (int port): m_IsRunning (false), m_Thread (nullptr), - m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)) + m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)), + m_ShutdownTimer (m_Service) { m_MethodHanders[I2P_CONTROL_METHOD_AUTHENTICATE] = &I2PControlService::AuthenticateHandler; m_MethodHanders[I2P_CONTROL_METHOD_ECHO] = &I2PControlService::EchoHandler; m_MethodHanders[I2P_CONTROL_METHOD_ROUTER_INFO] = &I2PControlService::RouterInfoHandler; + m_MethodHanders[I2P_CONTROL_METHOD_ROUTER_MANAGER] = &I2PControlService::RouterManagerHandler; } I2PControlService::~I2PControlService () @@ -192,12 +197,45 @@ namespace client void I2PControlService::RouterInfoHandler (const std::map& params, std::map& results) { LogPrint (eLogDebug, "I2PControl RouterInfo"); - for (auto& it :params) + for (auto& it: params) { LogPrint (eLogDebug, it.first); if (it.first == I2P_CONTROL_PARAM_RI_NETDB_KNOWNPEERS) results[I2P_CONTROL_PARAM_RI_NETDB_KNOWNPEERS] = boost::lexical_cast(i2p::data::netdb.GetNumRouters ()); } } + + void I2PControlService::RouterManagerHandler (const std::map& params, std::map& results) + { + LogPrint (eLogDebug, "I2PControl RouterManager"); + for (auto& it: params) + { + LogPrint (eLogDebug, it.first); + if (it.first == I2P_CONTROL_PARAM_ROUTER_MANAGER_SHUTDOWN) + { + LogPrint (eLogInfo, "Shutdown requested"); + results[I2P_CONTROL_PARAM_ROUTER_MANAGER_SHUTDOWN] = ""; + m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(1)); // 1 second to make sure response has been sent + m_ShutdownTimer.async_wait ( + [](const boost::system::error_code& ecode) + { + Daemon.running = 0; + }); + } + else if (it.first == I2P_CONTROL_PARAM_ROUTER_MANAGER_SHUTDOWN_GRACEFUL) + { + i2p::context.SetAcceptsTunnels (false); + int timeout = i2p::tunnel::tunnels.GetTransitTunnelsExpirationTimeout (); + LogPrint (eLogInfo, "Graceful shutdown requested. Will shutdown after ", timeout, " seconds"); + results[I2P_CONTROL_PARAM_ROUTER_MANAGER_SHUTDOWN_GRACEFUL] = ""; + m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(timeout + 1)); // + 1 second + m_ShutdownTimer.async_wait ( + [](const boost::system::error_code& ecode) + { + Daemon.running = 0; + }); + } + } + } } } diff --git a/I2PControl.h b/I2PControl.h index b5aed649..7874a3a2 100644 --- a/I2PControl.h +++ b/I2PControl.h @@ -25,7 +25,8 @@ namespace client const char I2P_CONTROL_METHOD_AUTHENTICATE[] = "Authenticate"; const char I2P_CONTROL_METHOD_ECHO[] = "Echo"; const char I2P_CONTROL_METHOD_ROUTER_INFO[] = "RouterInfo"; - + const char I2P_CONTROL_METHOD_ROUTER_MANAGER[] = "RouterManager"; + // params const char I2P_CONTROL_PARAM_API[] = "API"; const char I2P_CONTROL_PARAM_PASSWORD[] = "Password"; @@ -36,7 +37,10 @@ namespace client // RouterInfo params const char I2P_CONTROL_PARAM_RI_NETDB_KNOWNPEERS[] = "i2p.router.netdb.knownpeers"; - + // RouterManager params + const char I2P_CONTROL_PARAM_ROUTER_MANAGER_SHUTDOWN[] = "Shutdown"; + const char I2P_CONTROL_PARAM_ROUTER_MANAGER_SHUTDOWN_GRACEFUL[] = "ShutdownGraceful"; + class I2PControlService { public: @@ -66,14 +70,16 @@ namespace client void AuthenticateHandler (const std::map& params, std::map& results); void EchoHandler (const std::map& params, std::map& results); void RouterInfoHandler (const std::map& params, std::map& results); - + void RouterManagerHandler (const std::map& params, std::map& results); + private: bool m_IsRunning; std::thread * m_Thread; boost::asio::io_service m_Service; - boost::asio::ip::tcp::acceptor m_Acceptor; + boost::asio::ip::tcp::acceptor m_Acceptor; + boost::asio::deadline_timer m_ShutdownTimer; typedef void (I2PControlService::*MethodHandler)(const std::map& params, std::map& results); std::map m_MethodHanders; diff --git a/Tunnel.cpp b/Tunnel.cpp index 1e6aacd2..a569a329 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -610,5 +610,18 @@ namespace tunnel i2p::context.GetSharedRouterInfo () })); } + + int Tunnels::GetTransitTunnelsExpirationTimeout () + { + int timeout = 0; + uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + std::unique_lock l(m_TransitTunnelsMutex); + for (auto it: m_TransitTunnels) + { + int t = it.second->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT - ts; + if (t > timeout) timeout = t; + } + return timeout; + } } } diff --git a/Tunnel.h b/Tunnel.h index d5c48ee7..99f44976 100644 --- a/Tunnel.h +++ b/Tunnel.h @@ -123,6 +123,7 @@ namespace tunnel OutboundTunnel * GetNextOutboundTunnel (); TunnelPool * GetExploratoryPool () const { return m_ExploratoryPool; }; TransitTunnel * GetTransitTunnel (uint32_t tunnelID); + int GetTransitTunnelsExpirationTimeout (); void AddTransitTunnel (TransitTunnel * tunnel); void AddOutboundTunnel (OutboundTunnel * newTunnel); void AddInboundTunnel (InboundTunnel * newTunnel);