From 1f90b08445953fc0feaca6eaf3812ba7b2f2814d Mon Sep 17 00:00:00 2001 From: EinMByte Date: Sat, 1 Aug 2015 16:48:35 +0200 Subject: [PATCH] Began separation of i2pcontrol (untested). --- ClientContext.h | 2 +- I2PControl.cpp | 418 -------------------------------- I2PControl.h | 149 ------------ Makefile | 3 + filelist.mk | 6 +- i2pcontrol/I2PControl.cpp | 254 +++++++++++++++++++ i2pcontrol/I2PControl.h | 136 +++++++++++ i2pcontrol/I2PControlServer.cpp | 178 ++++++++++++++ i2pcontrol/I2PControlServer.h | 58 +++++ 9 files changed, 634 insertions(+), 570 deletions(-) delete mode 100644 I2PControl.cpp delete mode 100644 I2PControl.h create mode 100644 i2pcontrol/I2PControl.cpp create mode 100644 i2pcontrol/I2PControl.h create mode 100644 i2pcontrol/I2PControlServer.cpp create mode 100644 i2pcontrol/I2PControlServer.h diff --git a/ClientContext.h b/ClientContext.h index 52a7a0e7..b4d8b35a 100644 --- a/ClientContext.h +++ b/ClientContext.h @@ -11,7 +11,7 @@ #include "SAM.h" #include "BOB.h" #include "AddressBook.h" -#include "I2PControl.h" +#include "i2pcontrol/I2PControlServer.h" namespace i2p { diff --git a/I2PControl.cpp b/I2PControl.cpp deleted file mode 100644 index 4e993aa9..00000000 --- a/I2PControl.cpp +++ /dev/null @@ -1,418 +0,0 @@ -// There is bug in boost 1.49 with gcc 4.7 coming with Debian Wheezy -#define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 7)) - -#include "I2PControl.h" -#include -#include -#include -#include -#if !GCC47_BOOST149 -#include -#endif -#include "util/Log.h" -#include "NetDb.h" -#include "RouterContext.h" -#include "Daemon.h" -#include "tunnel/Tunnel.h" -#include "util/Timestamp.h" -#include "transport/Transports.h" -#include "version.h" - -namespace i2p -{ -namespace client -{ - I2PControlService::I2PControlService(const std::string& address, int port) - : m_Password(I2P_CONTROL_DEFAULT_PASSWORD), m_IsRunning(false), - m_Thread(nullptr), m_Acceptor(m_Service, boost::asio::ip::tcp::endpoint( - boost::asio::ip::address::from_string(address), port) - ), - m_ShutdownTimer (m_Service) - { - m_MethodHandlers[I2P_CONTROL_METHOD_AUTHENTICATE] = &I2PControlService::AuthenticateHandler; - m_MethodHandlers[I2P_CONTROL_METHOD_ECHO] = &I2PControlService::EchoHandler; - m_MethodHandlers[I2P_CONTROL_METHOD_I2PCONTROL] = &I2PControlService::I2PControlHandler; - m_MethodHandlers[I2P_CONTROL_METHOD_ROUTER_INFO] = &I2PControlService::RouterInfoHandler; - m_MethodHandlers[I2P_CONTROL_METHOD_ROUTER_MANAGER] = &I2PControlService::RouterManagerHandler; - m_MethodHandlers[I2P_CONTROL_METHOD_NETWORK_SETTING] = &I2PControlService::NetworkSettingHandler; - - // RouterInfo - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_UPTIME] = &I2PControlService::UptimeHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_VERSION] = &I2PControlService::VersionHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_STATUS] = &I2PControlService::StatusHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS] = &I2PControlService::NetDbKnownPeersHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS] = &I2PControlService::NetDbActivePeersHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NET_STATUS] = &I2PControlService::NetStatusHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING] = &I2PControlService::TunnelsParticipatingHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_IB_1S] = &I2PControlService::InboundBandwidth1S ; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_OB_1S] = &I2PControlService::OutboundBandwidth1S ; - - // RouterManager - m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN] = &I2PControlService::ShutdownHandler; - m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL] = &I2PControlService::ShutdownGracefulHandler; - m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_RESEED] = &I2PControlService::ReseedHandler; - } - - I2PControlService::~I2PControlService () - { - Stop (); - } - - void I2PControlService::Start () - { - if (!m_IsRunning) - { - Accept (); - m_IsRunning = true; - m_Thread = new std::thread (std::bind (&I2PControlService::Run, this)); - } - } - - void I2PControlService::Stop () - { - if (m_IsRunning) - { - m_IsRunning = false; - m_Acceptor.cancel (); - m_Service.stop (); - if (m_Thread) - { - m_Thread->join (); - delete m_Thread; - m_Thread = nullptr; - } - } - } - - void I2PControlService::Run () - { - while (m_IsRunning) - { - try - { - m_Service.run (); - } - catch (std::exception& ex) - { - LogPrint (eLogError, "I2PControl: ", ex.what ()); - } - } - } - - void I2PControlService::Accept () - { - auto newSocket = std::make_shared (m_Service); - m_Acceptor.async_accept (*newSocket, std::bind (&I2PControlService::HandleAccept, this, - std::placeholders::_1, newSocket)); - } - - void I2PControlService::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket) - { - if (ecode != boost::asio::error::operation_aborted) - Accept (); - - if (!ecode) - { - LogPrint (eLogInfo, "New I2PControl request from ", socket->remote_endpoint ()); - std::this_thread::sleep_for (std::chrono::milliseconds(5)); - ReadRequest (socket); - } - else - LogPrint (eLogError, "I2PControl accept error: ", ecode.message ()); - } - - void I2PControlService::ReadRequest (std::shared_ptr socket) - { - auto request = std::make_shared(); - socket->async_read_some ( -#if BOOST_VERSION >= 104900 - boost::asio::buffer (*request), -#else - boost::asio::buffer (request->data (), request->size ()), -#endif - std::bind(&I2PControlService::HandleRequestReceived, this, - std::placeholders::_1, std::placeholders::_2, socket, request)); - } - - void I2PControlService::HandleRequestReceived (const boost::system::error_code& ecode, - size_t bytes_transferred, std::shared_ptr socket, - std::shared_ptr buf) - { - if (ecode) - { - LogPrint (eLogError, "I2PControl read error: ", ecode.message ()); - } - else - { - try - { - bool isHtml = !memcmp (buf->data (), "POST", 4); - std::stringstream ss; - ss.write (buf->data (), bytes_transferred); - if (isHtml) - { - std::string header; - while (!ss.eof () && header != "\r") - std::getline(ss, header); - if (ss.eof ()) - { - LogPrint (eLogError, "Malformed I2PControl request. HTTP header expected"); - return; // TODO: - } - } -#if GCC47_BOOST149 - LogPrint (eLogError, "json_read is not supported due bug in boost 1.49 with gcc 4.7"); -#else - boost::property_tree::ptree pt; - boost::property_tree::read_json (ss, pt); - - std::string method = pt.get(I2P_CONTROL_PROPERTY_METHOD); - auto it = m_MethodHandlers.find (method); - if (it != m_MethodHandlers.end ()) - { - std::ostringstream response; - response << "{\"id\":" << pt.get(I2P_CONTROL_PROPERTY_ID) << ",\"result\":{"; - - (this->*(it->second))(pt.get_child (I2P_CONTROL_PROPERTY_PARAMS), response); - response << "},\"jsonrpc\":\"2.0\"}"; - SendResponse (socket, buf, response, isHtml); - } - else - LogPrint (eLogWarning, "Unknown I2PControl method ", method); -#endif - } - catch (std::exception& ex) - { - LogPrint (eLogError, "I2PControl handle request: ", ex.what ()); - } - catch (...) - { - LogPrint (eLogError, "I2PControl handle request unknown exception"); - } - } - } - - void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, int value) const - { - ss << "\"" << name << "\":" << value; - } - - void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value) const - { - ss << "\"" << name << "\":"; - if (value.length () > 0) - ss << "\"" << value << "\""; - else - ss << "null"; - } - - void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, double value) const - { - ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value; - } - - void I2PControlService::SendResponse (std::shared_ptr socket, - std::shared_ptr buf, std::ostringstream& response, bool isHtml) - { - size_t len = response.str ().length (), offset = 0; - if (isHtml) - { - std::ostringstream header; - header << "HTTP/1.1 200 OK\r\n"; - header << "Connection: close\r\n"; - header << "Content-Length: " << boost::lexical_cast(len) << "\r\n"; - header << "Content-Type: application/json\r\n"; - header << "Date: "; - auto facet = new boost::local_time::local_time_facet ("%a, %d %b %Y %H:%M:%S GMT"); - header.imbue(std::locale (header.getloc(), facet)); - header << boost::posix_time::second_clock::local_time() << "\r\n"; - header << "\r\n"; - offset = header.str ().size (); - memcpy (buf->data (), header.str ().c_str (), offset); - } - memcpy (buf->data () + offset, response.str ().c_str (), len); - boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), offset + len), - boost::asio::transfer_all (), - std::bind(&I2PControlService::HandleResponseSent, this, - std::placeholders::_1, std::placeholders::_2, socket, buf)); - } - - void I2PControlService::HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, - std::shared_ptr socket, std::shared_ptr buf) - { - if (ecode) - LogPrint (eLogError, "I2PControl write error: ", ecode.message ()); - socket->close (); - } - -// handlers - - void I2PControlService::AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results) - { - int api = params.get (I2P_CONTROL_PARAM_API); - auto password = params.get (I2P_CONTROL_PARAM_PASSWORD); - LogPrint (eLogDebug, "I2PControl Authenticate API=", api, " Password=", password); - if (password != m_Password) - LogPrint (eLogError, "I2PControl Authenticate Invalid password ", password, " expected ", m_Password); - InsertParam (results, I2P_CONTROL_PARAM_API, api); - results << ","; - std::string token = boost::lexical_cast(i2p::util::GetSecondsSinceEpoch ()); - m_Tokens.insert (token); - InsertParam (results, I2P_CONTROL_PARAM_TOKEN, token); - } - - void I2PControlService::EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) - { - auto echo = params.get (I2P_CONTROL_PARAM_ECHO); - LogPrint (eLogDebug, "I2PControl Echo Echo=", echo); - InsertParam (results, I2P_CONTROL_PARAM_RESULT, echo); - } - - -// I2PControl - - void I2PControlService::I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results) - { - LogPrint (eLogDebug, "I2PControl I2PControl"); - for (auto& it: params) - { - LogPrint (eLogDebug, it.first); - auto it1 = m_I2PControlHandlers.find (it.first); - if (it1 != m_I2PControlHandlers.end ()) - (this->*(it1->second))(it.second.data ()); - else - LogPrint (eLogError, "I2PControl NetworkSetting unknown request ", it.first); - } - } - -// RouterInfo - - void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) - { - LogPrint (eLogDebug, "I2PControl RouterInfo"); - for (auto it = params.begin (); it != params.end (); it++) - { - if (it != params.begin ()) results << ","; - LogPrint (eLogDebug, it->first); - auto it1 = m_RouterInfoHandlers.find (it->first); - if (it1 != m_RouterInfoHandlers.end ()) - (this->*(it1->second))(results); - else - LogPrint (eLogError, "I2PControl RouterInfo unknown request ", it->first); - } - } - - void I2PControlService::UptimeHandler (std::ostringstream& results) - { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_UPTIME, (int)i2p::context.GetUptime ()*1000); - } - - void I2PControlService::VersionHandler (std::ostringstream& results) - { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_VERSION, VERSION); - } - - void I2PControlService::StatusHandler (std::ostringstream& results) - { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_STATUS, "???"); // TODO: - } - - void I2PControlService::NetDbKnownPeersHandler (std::ostringstream& results) - { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS, i2p::data::netdb.GetNumRouters ()); - } - - void I2PControlService::NetDbActivePeersHandler (std::ostringstream& results) - { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS, (int)i2p::transport::transports.GetPeers ().size ()); - } - - void I2PControlService::NetStatusHandler (std::ostringstream& results) - { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_NET_STATUS, (int)i2p::context.GetStatus ()); - } - - void I2PControlService::TunnelsParticipatingHandler (std::ostringstream& results) - { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING, (int)i2p::tunnel::tunnels.GetTransitTunnels ().size ()); - } - - void I2PControlService::InboundBandwidth1S (std::ostringstream& results) - { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_BW_IB_1S, (double)i2p::transport::transports.GetInBandwidth ()); - } - - void I2PControlService::OutboundBandwidth1S (std::ostringstream& results) - { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_BW_OB_1S, (double)i2p::transport::transports.GetOutBandwidth ()); - } - -// RouterManager - - void I2PControlService::RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results) - { - LogPrint (eLogDebug, "I2PControl RouterManager"); - for (auto it = params.begin (); it != params.end (); it++) - { - if (it != params.begin ()) results << ","; - LogPrint (eLogDebug, it->first); - auto it1 = m_RouterManagerHandlers.find (it->first); - if (it1 != m_RouterManagerHandlers.end ()) - (this->*(it1->second))(results); - else - LogPrint (eLogError, "I2PControl RouterManager unknown request ", it->first); - } - } - - - void I2PControlService::ShutdownHandler (std::ostringstream& results) - { - LogPrint (eLogInfo, "Shutdown requested"); - InsertParam (results, I2P_CONTROL_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; - }); - } - - void I2PControlService::ShutdownGracefulHandler (std::ostringstream& results) - { - i2p::context.SetAcceptsTunnels (false); - int timeout = i2p::tunnel::tunnels.GetTransitTunnelsExpirationTimeout (); - LogPrint (eLogInfo, "Graceful shutdown requested. Will shutdown after ", timeout, " seconds"); - InsertParam (results, I2P_CONTROL_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; - }); - } - - void I2PControlService::ReseedHandler (std::ostringstream& results) - { - LogPrint (eLogInfo, "Reseed requested"); - InsertParam (results, I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN, ""); - i2p::data::netdb.Reseed (); - } - -// network setting - void I2PControlService::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results) - { - LogPrint (eLogDebug, "I2PControl NetworkSetting"); - for (auto it = params.begin (); it != params.end (); it++) - { - if (it != params.begin ()) results << ","; - LogPrint (eLogDebug, it->first); - auto it1 = m_NetworkSettingHandlers.find (it->first); - if (it1 != m_NetworkSettingHandlers.end ()) - (this->*(it1->second))(it->second.data (), results); - else - LogPrint (eLogError, "I2PControl NetworkSetting unknown request ", it->first); - } - } - -} -} diff --git a/I2PControl.h b/I2PControl.h deleted file mode 100644 index 9dae9344..00000000 --- a/I2PControl.h +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef I2P_CONTROL_H__ -#define I2P_CONTROL_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace i2p -{ -namespace client -{ - const size_t I2P_CONTROL_MAX_REQUEST_SIZE = 1024; - typedef std::array I2PControlBuffer; - - const char I2P_CONTROL_DEFAULT_PASSWORD[] = "itoopie"; - - const char I2P_CONTROL_PROPERTY_ID[] = "id"; - const char I2P_CONTROL_PROPERTY_METHOD[] = "method"; - const char I2P_CONTROL_PROPERTY_PARAMS[] = "params"; - const char I2P_CONTROL_PROPERTY_RESULT[] = "result"; - - // methods - const char I2P_CONTROL_METHOD_AUTHENTICATE[] = "Authenticate"; - const char I2P_CONTROL_METHOD_ECHO[] = "Echo"; - const char I2P_CONTROL_METHOD_I2PCONTROL[] = "I2PControl"; - const char I2P_CONTROL_METHOD_ROUTER_INFO[] = "RouterInfo"; - const char I2P_CONTROL_METHOD_ROUTER_MANAGER[] = "RouterManager"; - const char I2P_CONTROL_METHOD_NETWORK_SETTING[] = "NetworkSetting"; - - // params - const char I2P_CONTROL_PARAM_API[] = "API"; - const char I2P_CONTROL_PARAM_PASSWORD[] = "Password"; - const char I2P_CONTROL_PARAM_TOKEN[] = "Token"; - const char I2P_CONTROL_PARAM_ECHO[] = "Echo"; - const char I2P_CONTROL_PARAM_RESULT[] = "Result"; - - // I2PControl - const char I2P_CONTROL_I2PCONTROL_ADDRESS[] = "i2pcontrol.address"; - const char I2P_CONTROL_I2PCONTROL_PASSWORD[] = "i2pcontrol.password"; - const char I2P_CONTROL_I2PCONTROL_PORT[] = "i2pcontrol.port"; - - // RouterInfo requests - const char I2P_CONTROL_ROUTER_INFO_UPTIME[] = "i2p.router.uptime"; - const char I2P_CONTROL_ROUTER_INFO_VERSION[] = "i2p.router.version"; - const char I2P_CONTROL_ROUTER_INFO_STATUS[] = "i2p.router.status"; - const char I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS[] = "i2p.router.netdb.knownpeers"; - const char I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS[] = "i2p.router.netdb.activepeers"; - const char I2P_CONTROL_ROUTER_INFO_NET_STATUS[] = "i2p.router.net.status"; - const char I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING[] = "i2p.router.net.tunnels.participating"; - const char I2P_CONTROL_ROUTER_INFO_BW_IB_1S[] = "i2p.router.net.bw.inbound.1s"; - const char I2P_CONTROL_ROUTER_INFO_BW_OB_1S[] = "i2p.router.net.bw.outbound.1s"; - - // RouterManager requests - const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN[] = "Shutdown"; - const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL[] = "ShutdownGraceful"; - const char I2P_CONTROL_ROUTER_MANAGER_RESEED[] = "Reseed"; - - class I2PControlService - { - public: - - I2PControlService(const std::string& address, int port); - ~I2PControlService (); - - void Start (); - void Stop (); - - private: - - void Run (); - void Accept (); - void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); - void ReadRequest (std::shared_ptr socket); - void HandleRequestReceived (const boost::system::error_code& ecode, size_t bytes_transferred, - std::shared_ptr socket, std::shared_ptr buf); - void SendResponse (std::shared_ptr socket, - std::shared_ptr buf, std::ostringstream& response, bool isHtml); - void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, - std::shared_ptr socket, std::shared_ptr buf); - - private: - - void InsertParam (std::ostringstream& ss, const std::string& name, int value) const; - void InsertParam (std::ostringstream& ss, const std::string& name, double value) const; - void InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value) const; - - // methods - typedef void (I2PControlService::*MethodHandler)(const boost::property_tree::ptree& params, std::ostringstream& results); - - void AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results); - void EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results); - void I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results); - void RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results); - void RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results); - void NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results); - - // I2PControl - typedef void (I2PControlService::*I2PControlRequestHandler)(const std::string& value); - - // RouterInfo - typedef void (I2PControlService::*RouterInfoRequestHandler)(std::ostringstream& results); - void UptimeHandler (std::ostringstream& results); - void VersionHandler (std::ostringstream& results); - void StatusHandler (std::ostringstream& results); - void NetDbKnownPeersHandler (std::ostringstream& results); - void NetDbActivePeersHandler (std::ostringstream& results); - void NetStatusHandler (std::ostringstream& results); - void TunnelsParticipatingHandler (std::ostringstream& results); - void InboundBandwidth1S (std::ostringstream& results); - void OutboundBandwidth1S (std::ostringstream& results); - - // RouterManager - typedef void (I2PControlService::*RouterManagerRequestHandler)(std::ostringstream& results); - void ShutdownHandler (std::ostringstream& results); - void ShutdownGracefulHandler (std::ostringstream& results); - void ReseedHandler (std::ostringstream& results); - - // NetworkSetting - typedef void (I2PControlService::*NetworkSettingRequestHandler)(const std::string& value, std::ostringstream& results); - - private: - - std::string m_Password; - bool m_IsRunning; - std::thread * m_Thread; - - boost::asio::io_service m_Service; - boost::asio::ip::tcp::acceptor m_Acceptor; - boost::asio::deadline_timer m_ShutdownTimer; - std::set m_Tokens; - - std::map m_MethodHandlers; - std::map m_I2PControlHandlers; - std::map m_RouterInfoHandlers; - std::map m_RouterManagerHandlers; - std::map m_NetworkSettingHandlers; - }; -} -} - -#endif - diff --git a/Makefile b/Makefile index cd4961f4..06926c82 100644 --- a/Makefile +++ b/Makefile @@ -32,6 +32,7 @@ mk_build_dir: mkdir -p obj/util mkdir -p obj/crypto mkdir -p obj/tunnel + mkdir -p obj/i2pcontrol mk_build_test_dir: mkdir -p obj/tests @@ -51,6 +52,7 @@ deps: @mkdir -p obj/util @mkdir -p obj/crypto @mkdir -p obj/tunnel + @mkdir -p obj/i2pcontrol $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) -MM *.cpp > $(DEPS) @sed -i -e '/\.o:/ s/^/obj\//' $(DEPS) @@ -61,6 +63,7 @@ obj/%.o : %.cpp @mkdir -p obj/util @mkdir -p obj/crypto @mkdir -p obj/tunnel + @mkdir -p obj/i2pcontrol $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(CPU_FLAGS) -c -o $@ $< # '-' is 'ignore if missing' on first run diff --git a/filelist.mk b/filelist.mk index e7f29f23..b44a02eb 100644 --- a/filelist.mk +++ b/filelist.mk @@ -16,7 +16,8 @@ ifeq ($(UNAME),Darwin) # Else will get linker error about unknown symbols. - torkel COMMON_SRC += \ AddressBook.cpp BOB.cpp ClientContext.cpp Daemon.cpp I2PTunnel.cpp I2PService.cpp \ - SAM.cpp SOCKS.cpp UPnP.cpp HTTPProxy.cpp i2p.cpp DaemonLinux.cpp I2PControl.cpp \ + SAM.cpp SOCKS.cpp UPnP.cpp HTTPProxy.cpp i2p.cpp DaemonLinux.cpp \ + i2pcontrol/I2PControlServer.cpp i2pcontrol/I2PControl.cpp \ HTTPServer.cpp endif @@ -24,7 +25,8 @@ endif # also: Daemon{Linux,Win32}.cpp will be added later DAEMON_SRC = $(COMMON_SRC) \ AddressBook.cpp BOB.cpp ClientContext.cpp Daemon.cpp I2PTunnel.cpp I2PService.cpp \ - SAM.cpp SOCKS.cpp HTTPServer.cpp HTTPProxy.cpp I2PControl.cpp i2p.cpp + SAM.cpp SOCKS.cpp HTTPServer.cpp HTTPProxy.cpp i2pcontrol/I2PControl.cpp \ + i2pcontrol/I2PControlServer.cpp i2p.cpp LIB_SRC := $(COMMON_SRC) \ api.cpp diff --git a/i2pcontrol/I2PControl.cpp b/i2pcontrol/I2PControl.cpp new file mode 100644 index 00000000..3e693efc --- /dev/null +++ b/i2pcontrol/I2PControl.cpp @@ -0,0 +1,254 @@ +// There is bug in boost 1.49 with gcc 4.7 coming with Debian Wheezy +// #define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 7)) +// TODO: handle this somewhere, but definitely not here + +#include "I2PControl.h" +#include "util/Log.h" +#include +#include +#include "util/Timestamp.h" +#include +#include "transport/Transports.h" +#include "tunnel/Tunnel.h" +#include "NetDb.h" +#include "version.h" +#include "Daemon.h" + +namespace i2p { +namespace client { + +I2PControlSession::Response::Response(const std::string& id, const std::string& version) + : id(id), version(version), parameters() +{ + +} + +std::string I2PControlSession::Response::toJsonString() const +{ + std::ostringstream oss; + oss << "{\"id\":" << id << ",\"result\":{"; + oss << "},\"jsonrpc\":\"" << version << "\"}"; + for(auto& pair : parameters) + oss << '"' << pair.first << "\":" << pair.second << ", "; + return oss.str(); +} + +void I2PControlSession::Response::setParam(const std::string& param, const std::string& value) +{ + parameters[param] = value.empty() ? "\"" + value + "\"" : "null"; +} + +void I2PControlSession::Response::setParam(const std::string& param, int value) +{ + parameters[param] = std::to_string(value); +} + +void I2PControlSession::Response::setParam(const std::string& param, double value) +{ + std::ostringstream oss; + oss << std::fixed << std::setprecision(2) << value; + parameters[param] = oss.str(); +} + +I2PControlSession::I2PControlSession(boost::asio::io_service& ios) + : password(I2P_CONTROL_DEFAULT_PASSWORD), service(ios), shutdownTimer(ios) +{ + // Method handlers + methodHandlers[I2P_CONTROL_METHOD_AUTHENTICATE] = &I2PControlSession::handleAuthenticate; + methodHandlers[I2P_CONTROL_METHOD_ECHO] = &I2PControlSession::handleEcho; + methodHandlers[I2P_CONTROL_METHOD_I2PCONTROL] = &I2PControlSession::handleI2PControl; + methodHandlers[I2P_CONTROL_METHOD_ROUTER_INFO] = &I2PControlSession::handleRouterInfo; + methodHandlers[I2P_CONTROL_METHOD_ROUTER_MANAGER] = &I2PControlSession::handleRouterManager; + methodHandlers[I2P_CONTROL_METHOD_NETWORK_SETTING] = &I2PControlSession::handleNetworkSetting; + // RouterInfo handlers + routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_UPTIME] = &I2PControlSession::handleUptime; + routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_VERSION] = &I2PControlSession::handleVersion; + routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_STATUS] = &I2PControlSession::handleStatus; + routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS]= &I2PControlSession::handleNetDbKnownPeers; + routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS] = &I2PControlSession::handleNetDbActivePeers; + routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_NET_STATUS] = &I2PControlSession::handleNetStatus; + routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING] = &I2PControlSession::handleTunnelsParticipating; + routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_IB_1S] = &I2PControlSession::handleInBandwidth1S; + routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_OB_1S] = &I2PControlSession::handleOutBandwidth1S; + + // RouterManager handlers + routerManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN] = &I2PControlSession::handleShutdown; + routerManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL] = &I2PControlSession::handleShutdownGraceful; + routerManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_RESEED] = &I2PControlSession::handleReseed; +} + +I2PControlSession::Response I2PControlSession::handleRequest(std::stringstream& request) +{ + boost::property_tree::ptree pt; + boost::property_tree::read_json(request, pt); + + std::string method = pt.get(I2P_CONTROL_PROPERTY_METHOD); + auto it = methodHandlers.find(method); + if(it == methodHandlers.end()) { // Not found + LogPrint(eLogWarning, "Unknown I2PControl method ", method); + return Response("error"); // TODO: indicate the error through i2pcontrol + } + + Response response(pt.get(I2P_CONTROL_PROPERTY_ID)); + // Call the appropriate handler + (this->*(it->second))(pt.get_child(I2P_CONTROL_PROPERTY_PARAMS), response); + return response; +} + +void I2PControlSession::handleAuthenticate(const PropertyTree& pt, Response& response) +{ + int api = pt.get(I2P_CONTROL_PARAM_API); + const std::string given_pass = pt.get(I2P_CONTROL_PARAM_PASSWORD); + LogPrint(eLogDebug, "I2PControl Authenticate API = ", api, " Password = ", password); + if(given_pass != password) { + LogPrint( + eLogError, "I2PControl Authenticate Invalid password ", password, + " expected ", password + ); + return; + } + const std::string token = std::to_string(i2p::util::GetSecondsSinceEpoch()); + response.setParam(I2P_CONTROL_PARAM_API, api); + response.setParam(I2P_CONTROL_PARAM_TOKEN, token); + // TODO: store tokens to do something useful with them +} + +void I2PControlSession::handleEcho(const PropertyTree& pt, Response& response) +{ + const std::string echo = pt.get(I2P_CONTROL_PARAM_ECHO); + LogPrint(eLogDebug, "I2PControl Echo Echo = ", echo); + response.setParam(I2P_CONTROL_PARAM_RESULT, echo); +} + +void I2PControlSession::handleI2PControl(const PropertyTree& pt, Response& response) +{ + LogPrint(eLogDebug, "I2PControl I2PControl"); + // TODO: implement + +} + +void I2PControlSession::handleRouterInfo(const PropertyTree& pt, Response& response) +{ + LogPrint(eLogDebug, "I2PControl RouterInfo"); + for(auto pair : pt) { + LogPrint(eLogDebug, pair.first); + auto it = routerInfoHandlers.find(pair.first); + if(it != routerInfoHandlers.end()) + (this->*(it->second))(response); + else + LogPrint(eLogError, "I2PControl RouterInfo unknown request ", it->first); + } +} + +void I2PControlSession::handleRouterManager(const PropertyTree& pt, Response& response) +{ + LogPrint(eLogDebug, "I2PControl RouterManager"); + for(auto pair : pt) { + LogPrint(eLogDebug, pair.first); + auto it = routerManagerHandlers.find(pair.first); + if(it != routerManagerHandlers.end()) + (this->*(it->second))(response); + else + LogPrint(eLogError, "I2PControl RouterManager unknown request ", it->first); + } +} + +void I2PControlSession::handleNetworkSetting(const PropertyTree& pt, Response& response) +{ + +} + +void I2PControlSession::handleUptime(Response& response) +{ + response.setParam(I2P_CONTROL_ROUTER_INFO_UPTIME, (int)i2p::context.GetUptime()*1000); +} + +void I2PControlSession::handleVersion(Response& response) +{ + response.setParam(I2P_CONTROL_ROUTER_INFO_VERSION, VERSION); +} + +void I2PControlSession::handleStatus(Response& response) +{ + response.setParam(I2P_CONTROL_ROUTER_INFO_STATUS, "???"); // TODO: +} + +void I2PControlSession::handleNetDbKnownPeers(Response& response) +{ + response.setParam( + I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS, i2p::data::netdb.GetNumRouters() + ); +} + +void I2PControlSession::handleNetDbActivePeers(Response& response) +{ + response.setParam( + I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS, + i2p::data::netdb.GetNumRouters() + ); +} + +void I2PControlSession::handleNetStatus(Response& response) +{ + response.setParam( + I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS, + (int)i2p::transport::transports.GetPeers().size() + ); +} + +void I2PControlSession::handleTunnelsParticipating(Response& response) +{ + response.setParam( + I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING, + (int)i2p::tunnel::tunnels.GetTransitTunnels().size() + ); +} + +void I2PControlSession::handleInBandwidth1S(Response& response) +{ + response.setParam( + I2P_CONTROL_ROUTER_INFO_BW_IB_1S, + (double)i2p::transport::transports.GetInBandwidth() + ); +} + +void I2PControlSession::handleOutBandwidth1S(Response& response) +{ + response.setParam( + I2P_CONTROL_ROUTER_INFO_BW_OB_1S, + (double)i2p::transport::transports.GetOutBandwidth() + ); +} + +void I2PControlSession::handleShutdown(Response& response) +{ + LogPrint(eLogInfo, "Shutdown requested"); + response.setParam(I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN, ""); + // 1 second to make sure response has been sent + shutdownTimer.expires_from_now(boost::posix_time::seconds(1)); + shutdownTimer.async_wait([](const boost::system::error_code& ecode) { + Daemon.running = 0; + }); +} + +void I2PControlSession::handleShutdownGraceful(Response& response) +{ + i2p::context.SetAcceptsTunnels(false); + int timeout = i2p::tunnel::tunnels.GetTransitTunnelsExpirationTimeout(); + LogPrint(eLogInfo, "Graceful shutdown requested. Will shutdown after ", timeout, " seconds"); + response.setParam(I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL, ""); + shutdownTimer.expires_from_now(boost::posix_time::seconds(timeout + 1)); + shutdownTimer.async_wait([](const boost::system::error_code& ecode) { + Daemon.running = 0; + }); +} + +void I2PControlSession::handleReseed(Response& response) +{ + LogPrint(eLogInfo, "Reseed requested"); + response.setParam(I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN, ""); + i2p::data::netdb.Reseed(); +} + +} +} diff --git a/i2pcontrol/I2PControl.h b/i2pcontrol/I2PControl.h new file mode 100644 index 00000000..1011d4d5 --- /dev/null +++ b/i2pcontrol/I2PControl.h @@ -0,0 +1,136 @@ +#ifndef I2PCONTROL_H__ +#define I2PCONTROL_H__ + +#include +#include +#include +#include +#include + +namespace i2p { +namespace client { + +const char I2P_CONTROL_DEFAULT_PASSWORD[] = "itoopie"; + +const char I2P_CONTROL_PROPERTY_ID[] = "id"; +const char I2P_CONTROL_PROPERTY_METHOD[] = "method"; +const char I2P_CONTROL_PROPERTY_PARAMS[] = "params"; +const char I2P_CONTROL_PROPERTY_RESULT[] = "result"; + +// methods +const char I2P_CONTROL_METHOD_AUTHENTICATE[] = "Authenticate"; +const char I2P_CONTROL_METHOD_ECHO[] = "Echo"; +const char I2P_CONTROL_METHOD_I2PCONTROL[] = "I2PControl"; +const char I2P_CONTROL_METHOD_ROUTER_INFO[] = "RouterInfo"; +const char I2P_CONTROL_METHOD_ROUTER_MANAGER[] = "RouterManager"; +const char I2P_CONTROL_METHOD_NETWORK_SETTING[] = "NetworkSetting"; + +// params +const char I2P_CONTROL_PARAM_API[] = "API"; +const char I2P_CONTROL_PARAM_PASSWORD[] = "Password"; +const char I2P_CONTROL_PARAM_TOKEN[] = "Token"; +const char I2P_CONTROL_PARAM_ECHO[] = "Echo"; +const char I2P_CONTROL_PARAM_RESULT[] = "Result"; + +// I2PControl +const char I2P_CONTROL_I2PCONTROL_ADDRESS[] = "i2pcontrol.address"; +const char I2P_CONTROL_I2PCONTROL_PASSWORD[] = "i2pcontrol.password"; +const char I2P_CONTROL_I2PCONTROL_PORT[] = "i2pcontrol.port"; + +// RouterInfo requests +const char I2P_CONTROL_ROUTER_INFO_UPTIME[] = "i2p.router.uptime"; +const char I2P_CONTROL_ROUTER_INFO_VERSION[] = "i2p.router.version"; +const char I2P_CONTROL_ROUTER_INFO_STATUS[] = "i2p.router.status"; +const char I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS[] = "i2p.router.netdb.knownpeers"; +const char I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS[] = "i2p.router.netdb.activepeers"; +const char I2P_CONTROL_ROUTER_INFO_NET_STATUS[] = "i2p.router.net.status"; +const char I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING[] = "i2p.router.net.tunnels.participating"; +const char I2P_CONTROL_ROUTER_INFO_BW_IB_1S[] = "i2p.router.net.bw.inbound.1s"; +const char I2P_CONTROL_ROUTER_INFO_BW_OB_1S[] = "i2p.router.net.bw.outbound.1s"; + +// RouterManager requests +const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN[] = "Shutdown"; +const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL[] = "ShutdownGraceful"; +const char I2P_CONTROL_ROUTER_MANAGER_RESEED[] = "Reseed"; + +/** + * "Null" I2P control implementation, does not do actual networking. + */ +class I2PControlSession { + +public: + class Response { + std::string id; + std::string version; + std::map parameters; + public: + Response(const std::string& id, const std::string& version = "2.0"); + std::string toJsonString() const; + + /** + * Set an ouptut parameter to a specified string. + * @todo escape quotes + */ + void setParam(const std::string& param, const std::string& value); + void setParam(const std::string& param, int value); + void setParam(const std::string& param, double value); + }; + + /** + * Sets up the appropriate handlers. + * @param ios the parent io_service object + */ + I2PControlSession(boost::asio::io_service& ios); + + /** + * Handle a json string with I2PControl instructions. + */ + Response handleRequest(std::stringstream& request); +private: + // For convenience + typedef boost::property_tree::ptree PropertyTree; + // Handler types + typedef void (I2PControlSession::*MethodHandler)( + const PropertyTree& pt, Response& results + ); + typedef void (I2PControlSession::*RequestHandler)(Response& results); + + // Method handlers + void handleAuthenticate(const PropertyTree& pt, Response& response); + void handleEcho(const PropertyTree& pt, Response& response); + void handleI2PControl(const PropertyTree& pt, Response& response); + void handleRouterInfo(const PropertyTree& pt, Response& response); + void handleRouterManager(const PropertyTree& pt, Response& response); + void handleNetworkSetting(const PropertyTree& pt, Response& response); + + // RouterInfo handlers + void handleUptime(Response& response); + void handleVersion(Response& response); + void handleStatus(Response& response); + void handleNetDbKnownPeers(Response& response); + void handleNetDbActivePeers(Response& response); + void handleNetStatus(Response& response); + void handleTunnelsParticipating(Response& response); + void handleInBandwidth1S(Response& response); + void handleOutBandwidth1S(Response& response); + + // RouterManager handlers + void handleShutdown(Response& response); + void handleShutdownGraceful(Response& response); + void handleReseed(Response& response); + + std::string password; + + std::map methodHandlers; + std::map routerInfoHandlers; + std::map routerManagerHandlers; + std::map networkSettingHandlers; + + boost::asio::io_service& service; + boost::asio::deadline_timer shutdownTimer; +}; + +} +} + +#endif // I2PCONTROL_H__ diff --git a/i2pcontrol/I2PControlServer.cpp b/i2pcontrol/I2PControlServer.cpp new file mode 100644 index 00000000..ceb947fa --- /dev/null +++ b/i2pcontrol/I2PControlServer.cpp @@ -0,0 +1,178 @@ +#include "I2PControlServer.h" +#include +#include +#include +#include "util/Log.h" +#include "util/Timestamp.h" +#include "version.h" + +namespace i2p +{ +namespace client +{ + I2PControlService::I2PControlService(const std::string& address, int port) + : m_Session(m_Service), m_IsRunning(false), m_Thread(nullptr), + m_Acceptor(m_Service, boost::asio::ip::tcp::endpoint( + boost::asio::ip::address::from_string(address), port) + ) + { + } + + I2PControlService::~I2PControlService () + { + Stop (); + } + + void I2PControlService::Start () + { + if (!m_IsRunning) + { + Accept (); + m_IsRunning = true; + m_Thread = new std::thread (std::bind (&I2PControlService::Run, this)); + } + } + + void I2PControlService::Stop () + { + if (m_IsRunning) + { + m_IsRunning = false; + m_Acceptor.cancel (); + m_Service.stop (); + if (m_Thread) + { + m_Thread->join (); + delete m_Thread; + m_Thread = nullptr; + } + } + } + + void I2PControlService::Run () + { + while (m_IsRunning) + { + try + { + m_Service.run (); + } + catch (std::exception& ex) + { + LogPrint (eLogError, "I2PControl: ", ex.what ()); + } + } + } + + void I2PControlService::Accept () + { + auto newSocket = std::make_shared (m_Service); + m_Acceptor.async_accept (*newSocket, std::bind (&I2PControlService::HandleAccept, this, + std::placeholders::_1, newSocket)); + } + + void I2PControlService::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket) + { + if (ecode != boost::asio::error::operation_aborted) + Accept (); + + if (!ecode) + { + LogPrint (eLogInfo, "New I2PControl request from ", socket->remote_endpoint ()); + std::this_thread::sleep_for (std::chrono::milliseconds(5)); + ReadRequest (socket); + } + else + LogPrint (eLogError, "I2PControl accept error: ", ecode.message ()); + } + + void I2PControlService::ReadRequest (std::shared_ptr socket) + { + auto request = std::make_shared(); + socket->async_read_some ( +#if BOOST_VERSION >= 104900 + boost::asio::buffer (*request), +#else + boost::asio::buffer (request->data (), request->size ()), +#endif + std::bind(&I2PControlService::HandleRequestReceived, this, + std::placeholders::_1, std::placeholders::_2, socket, request)); + } + + void I2PControlService::HandleRequestReceived (const boost::system::error_code& ecode, + size_t bytes_transferred, std::shared_ptr socket, + std::shared_ptr buf) + { + if (ecode) + { + LogPrint (eLogError, "I2PControl read error: ", ecode.message ()); + } + else + { + try + { + bool isHtml = !memcmp (buf->data (), "POST", 4); + std::stringstream ss; + ss.write (buf->data (), bytes_transferred); + if (isHtml) + { + std::string header; + while (!ss.eof () && header != "\r") + std::getline(ss, header); + if (ss.eof ()) + { + LogPrint (eLogError, "Malformed I2PControl request. HTTP header expected"); + return; // TODO: + } + } + + I2PControlSession::Response response = m_Session.handleRequest(ss); + SendResponse(socket, buf, response.toJsonString(), isHtml); + } + catch (const std::exception& ex) + { + LogPrint (eLogError, "I2PControl handle request: ", ex.what ()); + } + catch (...) + { + LogPrint (eLogError, "I2PControl handle request unknown exception"); + } + } + } + + void I2PControlService::SendResponse (std::shared_ptr socket, + std::shared_ptr buf, const std::string& response, bool isHtml) + { + size_t len = response.length (), offset = 0; + if (isHtml) + { + std::ostringstream header; + header << "HTTP/1.1 200 OK\r\n"; + header << "Connection: close\r\n"; + header << "Content-Length: " << boost::lexical_cast(len) << "\r\n"; + header << "Content-Type: application/json\r\n"; + header << "Date: "; + auto facet = new boost::local_time::local_time_facet ("%a, %d %b %Y %H:%M:%S GMT"); + header.imbue(std::locale (header.getloc(), facet)); + header << boost::posix_time::second_clock::local_time() << "\r\n"; + header << "\r\n"; + offset = header.str ().size (); + memcpy (buf->data (), header.str ().c_str (), offset); + } + memcpy (buf->data () + offset, response.c_str (), len); + boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), offset + len), + boost::asio::transfer_all (), + std::bind(&I2PControlService::HandleResponseSent, this, + std::placeholders::_1, std::placeholders::_2, socket, buf)); + } + + void I2PControlService::HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, + std::shared_ptr socket, std::shared_ptr buf) + { + if (ecode) + LogPrint (eLogError, "I2PControl write error: ", ecode.message ()); + socket->close (); + } + +} +} diff --git a/i2pcontrol/I2PControlServer.h b/i2pcontrol/I2PControlServer.h new file mode 100644 index 00000000..7113288b --- /dev/null +++ b/i2pcontrol/I2PControlServer.h @@ -0,0 +1,58 @@ +#ifndef I2P_CONTROL_SERVER_H__ +#define I2P_CONTROL_SERVER_H__ + +#include "I2PControl.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace i2p { +namespace client { + +const size_t I2P_CONTROL_MAX_REQUEST_SIZE = 1024; +typedef std::array I2PControlBuffer; + +class I2PControlService { +public: + + I2PControlService(const std::string& address, int port); + ~I2PControlService (); + + void Start (); + void Stop (); + +private: + + void Run (); + void Accept (); + void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); + void ReadRequest (std::shared_ptr socket); + void HandleRequestReceived (const boost::system::error_code& ecode, size_t bytes_transferred, + std::shared_ptr socket, std::shared_ptr buf); + void SendResponse (std::shared_ptr socket, + std::shared_ptr buf, const std::string& response, bool isHtml); + void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, + std::shared_ptr socket, std::shared_ptr buf); + +private: + + bool m_IsRunning; + std::thread * m_Thread; + + boost::asio::io_service m_Service; + boost::asio::ip::tcp::acceptor m_Acceptor; + + I2PControlSession m_Session; + +}; +} +} + +#endif +