diff --git a/ClientContext.cpp b/ClientContext.cpp index b6126fcb..4a34cbdc 100644 --- a/ClientContext.cpp +++ b/ClientContext.cpp @@ -12,7 +12,8 @@ namespace client ClientContext::ClientContext (): m_SharedLocalDestination (nullptr), m_HttpProxy (nullptr), m_SocksProxy (nullptr), m_IrcTunnel (nullptr), - m_ServerTunnel (nullptr), m_SamBridge (nullptr), m_BOBCommandChannel (nullptr) + m_ServerTunnel (nullptr), m_SamBridge (nullptr), m_BOBCommandChannel (nullptr), + m_I2PControlService (nullptr) { } @@ -24,6 +25,7 @@ namespace client delete m_ServerTunnel; delete m_SamBridge; delete m_BOBCommandChannel; + delete m_I2PControlService; } void ClientContext::Start () @@ -75,6 +77,13 @@ namespace client m_BOBCommandChannel->Start (); LogPrint("BOB command channel started"); } + int i2pcontrolPort = i2p::util::config::GetArg("-i2pcontrolport", 0); + if (i2pcontrolPort) + { + m_I2PControlService = new I2PControlService (i2pcontrolPort); + m_I2PControlService->Start (); + LogPrint("I2PControl started"); + } m_AddressBook.StartSubscriptions (); } @@ -117,6 +126,13 @@ namespace client m_BOBCommandChannel = nullptr; LogPrint("BOB command channel stoped"); } + if (m_I2PControlService) + { + m_I2PControlService->Stop (); + delete m_I2PControlService; + m_I2PControlService = nullptr; + LogPrint("I2PControl stoped"); + } for (auto it: m_Destinations) { diff --git a/ClientContext.h b/ClientContext.h index 4ee81549..f472dc32 100644 --- a/ClientContext.h +++ b/ClientContext.h @@ -9,6 +9,7 @@ #include "SAM.h" #include "BOB.h" #include "AddressBook.h" +#include "I2PControl.h" namespace i2p { @@ -49,6 +50,7 @@ namespace client I2PServerTunnel * m_ServerTunnel; SAMBridge * m_SamBridge; BOBCommandChannel * m_BOBCommandChannel; + I2PControlService * m_I2PControlService; public: // for HTTP diff --git a/I2PControl.cpp b/I2PControl.cpp index 203dce8e..e95a6bbd 100644 --- a/I2PControl.cpp +++ b/I2PControl.cpp @@ -12,6 +12,7 @@ namespace client m_IsRunning (false), m_Thread (nullptr), m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)) { + m_MethodHanders[I2P_CONTROL_METHOD_ROUTER_INFO] = &I2PControlService::RouterInfoHandler; } I2PControlService::~I2PControlService () @@ -113,11 +114,48 @@ namespace client if (!v.first.empty()) params[v.first] = v.second.data (); } - (this->*(it->second))(params); + std::map results; + (this->*(it->second))(params, results); + SendResponse (socket, buf, pt.get(I2P_CONTROL_PROPERTY_ID), results); } else LogPrint (eLogWarning, "Unknown I2PControl method ", method); } } + + void I2PControlService::SendResponse (std::shared_ptr socket, + std::shared_ptr buf, const std::string& id, + const std::map& results) + { + boost::property_tree::ptree ptr; + for (auto& result: results) + ptr.put (result.first, result.second); + + boost::property_tree::ptree pt; + pt.put (I2P_CONTROL_PROPERTY_ID, id); + pt.put_child (I2P_CONTROL_PROPERTY_RESULT, ptr); + pt.put ("jsonrpc", "2.0"); + + std::ostringstream ss; + boost::property_tree::write_json (ss, pt, false); + size_t len = ss.str ().length (); + memcpy (buf->data (), ss.str ().c_str (), len); + boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), 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 (); + } + + void I2PControlService::RouterInfoHandler (const std::map& params, std::map results) + { + } } } diff --git a/I2PControl.h b/I2PControl.h index f46afcb7..600e44d9 100644 --- a/I2PControl.h +++ b/I2PControl.h @@ -20,6 +20,10 @@ namespace client const char I2P_CONTROL_PROPERTY_METHOD[] = "method"; const char I2P_CONTROL_PROPERTY_TOKEN[] = "Token"; const char I2P_CONTROL_PROPERTY_PARAMS[] = "params"; + const char I2P_CONTROL_PROPERTY_RESULT[] = "result"; + + // methods + const char I2P_CONTROL_METHOD_ROUTER_INFO[] = "RouterInfo"; class I2PControlService { @@ -39,6 +43,15 @@ namespace client 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& id, + const std::map& results); + void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, + std::shared_ptr socket, std::shared_ptr buf); + + private: + + void RouterInfoHandler (const std::map& params, std::map results); private: @@ -48,7 +61,7 @@ namespace client boost::asio::io_service m_Service; boost::asio::ip::tcp::acceptor m_Acceptor; - typedef void (I2PControlService::*MethodHandler)(const std::map& params); + typedef void (I2PControlService::*MethodHandler)(const std::map& params, std::map results); std::map m_MethodHanders; }; } diff --git a/README.md b/README.md index 7e354a76..f5bcab00 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ Cmdline options * --eepport= - Port incoming trafic forward to. 80 by default * --samport= - Port of SAM bridge. Usually 7656. SAM is off if not specified * --bobport= - Port of BOB command channel. Usually 2827. BOB is off if not specified +* --i2pcontrolport= - Port of I2P control service. Usually 7650. I2PControl is off if not specified * --conf= - Config file (default: ~/.i2pd/i2p.conf or /var/lib/i2pd/i2p.conf) This parameter will be silently ignored if the specified config file does not exist. Options specified on the command line take precedence over those in the config file.