From 114022d18a1947217b02351a3be1686bb89d79c6 Mon Sep 17 00:00:00 2001 From: "Francisco Blas (klondike) Izquierdo Riera" Date: Thu, 8 Jan 2015 01:31:31 +0100 Subject: [PATCH 1/5] Add the TCPIPAcceptor class for handling TCP/IP services on clearnet --- I2PService.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ I2PService.h | 36 +++++++++++++++++++++++++++++++++--- 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/I2PService.cpp b/I2PService.cpp index 568d03eb..69cee2bc 100644 --- a/I2PService.cpp +++ b/I2PService.cpp @@ -32,5 +32,49 @@ namespace client streamRequestComplete (nullptr); } } + + void TCPIPAcceptor::Start () + { + m_Acceptor.listen (); + Accept (); + } + + void TCPIPAcceptor::Stop () + { + m_Acceptor.close(); + m_Timer.cancel (); + ClearHandlers(); + } + + void TCPIPAcceptor::Accept () + { + auto newSocket = new boost::asio::ip::tcp::socket (GetService ()); + m_Acceptor.async_accept (*newSocket, std::bind (&TCPIPAcceptor::HandleAccept, this, + std::placeholders::_1, newSocket)); + } + + void TCPIPAcceptor::HandleAccept (const boost::system::error_code& ecode, boost::asio::ip::tcp::socket * socket) + { + if (!ecode) + { + LogPrint(eLogDebug,"--- ",GetName()," accepted"); + auto handler = CreateHandler(socket); + if (handler) { + AddHandler(handler); + handler->Handle(); + } else { + socket->close(); + delete socket; + } + Accept(); + } + else + { + if (ecode != boost::asio::error::operation_aborted) + LogPrint (eLogError,"--- ",GetName()," Closing socket on accept because: ", ecode.message ()); + delete socket; + } + } + } } diff --git a/I2PService.h b/I2PService.h index 6d9e878f..636a9780 100644 --- a/I2PService.h +++ b/I2PService.h @@ -46,6 +46,7 @@ namespace client virtual void Start () = 0; virtual void Stop () = 0; + virtual const char* GetName() { return "Generic I2P Service"; } private: ClientDestination * m_LocalDestination; @@ -59,19 +60,48 @@ namespace client public: I2PServiceHandler(I2PService * parent) : m_Service(parent), m_Dead(false) { } virtual ~I2PServiceHandler() { } + //If you override this make sure you call it from the children + virtual void Handle() {}; //Start handling the socket protected: // Call when terminating or handing over to avoid race conditions - inline bool Kill() { return m_Dead.exchange(true); } + inline bool Kill () { return m_Dead.exchange(true); } // Call to know if the handler is dead - inline bool Dead() { return m_Dead; } + inline bool Dead () { return m_Dead; } // Call when done to clean up (make sure Kill is called first) - inline void Done(std::shared_ptr me) { if(m_Service) m_Service->RemoveHandler(me); } + inline void Done (std::shared_ptr me) { if(m_Service) m_Service->RemoveHandler(me); } // Call to talk with the owner inline I2PService * GetOwner() { return m_Service; } private: I2PService *m_Service; std::atomic m_Dead; //To avoid cleaning up multiple times }; + + //This is a service that listens for connections on the IP network and interacts with I2P + class TCPIPAcceptor: public I2PService + { + public: + TCPIPAcceptor (int port, ClientDestination * localDestination = nullptr) : + I2PService(localDestination), + m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), port)), + m_Timer (GetService ()) {} + TCPIPAcceptor (int port, i2p::data::SigningKeyType kt) : + I2PService(kt), + m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), port)), + m_Timer (GetService ()) {} + virtual ~TCPIPAcceptor () { TCPIPAcceptor::Stop(); } + //If you override this make sure you call it from the children + void Start (); + //If you override this make sure you call it from the children + void Stop (); + protected: + virtual std::shared_ptr CreateHandler(boost::asio::ip::tcp::socket * socket) = 0; + virtual const char* GetName() { return "Generic TCP/IP accepting daemon"; } + private: + void Accept(); + void HandleAccept(const boost::system::error_code& ecode, boost::asio::ip::tcp::socket * socket); + boost::asio::ip::tcp::acceptor m_Acceptor; + boost::asio::deadline_timer m_Timer; + }; } } From 8a6bea64bce85795998b2ea4ee18960feb53440b Mon Sep 17 00:00:00 2001 From: "Francisco Blas (klondike) Izquierdo Riera" Date: Thu, 8 Jan 2015 01:35:42 +0100 Subject: [PATCH 2/5] Make the HTTP Proxy use TCPIPAcceptor --- HTTPProxy.cpp | 36 ++---------------------------------- HTTPProxy.h | 25 +++++++------------------ 2 files changed, 9 insertions(+), 52 deletions(-) diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index 77c2be40..5659a80b 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -231,41 +231,9 @@ namespace proxy } } - void HTTPProxyServer::Start () + std::shared_ptr HTTPProxyServer::CreateHandler(boost::asio::ip::tcp::socket * socket) { - m_Acceptor.listen (); - Accept (); - } - - void HTTPProxyServer::Stop () - { - m_Acceptor.close(); - m_Timer.cancel (); - ClearHandlers(); - } - - void HTTPProxyServer::Accept () - { - auto newSocket = new boost::asio::ip::tcp::socket (GetService ()); - m_Acceptor.async_accept (*newSocket, std::bind (&HTTPProxyServer::HandleAccept, this, - std::placeholders::_1, newSocket)); - } - - void HTTPProxyServer::HandleAccept (const boost::system::error_code& ecode, boost::asio::ip::tcp::socket * socket) - { - if (!ecode) - { - LogPrint(eLogDebug,"--- HTTP Proxy accepted"); - auto handler = std::make_shared (this, socket); - AddHandler(handler); - handler->Handle(); - Accept(); - } - else - { - LogPrint (eLogError,"--- HTTP Proxy Closing socket on accept because: ", ecode.message ()); - delete socket; - } + return std::make_shared (this, socket); } } diff --git a/HTTPProxy.h b/HTTPProxy.h index 8e348478..4558c88f 100644 --- a/HTTPProxy.h +++ b/HTTPProxy.h @@ -12,27 +12,16 @@ namespace i2p namespace proxy { class HTTPProxyHandler; - class HTTPProxyServer: public i2p::client::I2PService + class HTTPProxyServer: public i2p::client::TCPIPAcceptor { - private: - std::set > m_Handlers; - boost::asio::ip::tcp::acceptor m_Acceptor; - boost::asio::deadline_timer m_Timer; - std::mutex m_HandlersMutex; - - private: - - void Accept(); - void HandleAccept(const boost::system::error_code& ecode, boost::asio::ip::tcp::socket * socket); + protected: + // Implements TCPIPAcceptor + std::shared_ptr CreateHandler(boost::asio::ip::tcp::socket * socket); + const char* GetName() { return "HTTP Proxy"; } public: - HTTPProxyServer(int port) : I2PService(i2p::data::SIGNING_KEY_TYPE_DSA_SHA1), - m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), port)), - m_Timer (GetService ()) {}; - ~HTTPProxyServer() { Stop(); } - - void Start (); - void Stop (); + HTTPProxyServer(int port) : TCPIPAcceptor(port, i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) {} + ~HTTPProxyServer() {} }; typedef HTTPProxyServer HTTPProxy; From 7d9c0b76fcbadf2f86f5e30f58aa044902a1867c Mon Sep 17 00:00:00 2001 From: "Francisco Blas (klondike) Izquierdo Riera" Date: Thu, 8 Jan 2015 01:45:49 +0100 Subject: [PATCH 3/5] Make SOCKS use TCPIPAcceptor --- SOCKS.cpp | 36 ++---------------------------------- SOCKS.h | 26 +++++++------------------- 2 files changed, 9 insertions(+), 53 deletions(-) diff --git a/SOCKS.cpp b/SOCKS.cpp index 1cae4c83..ac30b6bd 100644 --- a/SOCKS.cpp +++ b/SOCKS.cpp @@ -514,41 +514,9 @@ namespace proxy } } - void SOCKSServer::Start () + std::shared_ptr SOCKSServer::CreateHandler(boost::asio::ip::tcp::socket * socket) { - m_Acceptor.listen (); - Accept (); - } - - void SOCKSServer::Stop () - { - m_Acceptor.close(); - m_Timer.cancel (); - ClearHandlers(); - } - - void SOCKSServer::Accept () - { - auto newSocket = new boost::asio::ip::tcp::socket (GetService ()); - m_Acceptor.async_accept (*newSocket, std::bind (&SOCKSServer::HandleAccept, this, - std::placeholders::_1, newSocket)); - } - - void SOCKSServer::HandleAccept (const boost::system::error_code& ecode, boost::asio::ip::tcp::socket * socket) - { - if (!ecode) - { - LogPrint(eLogDebug,"--- SOCKS accepted"); - auto handle = std::make_shared (this, socket); - AddHandler(handle); - handle->Handle(); - Accept(); - } - else - { - LogPrint (eLogError,"--- SOCKS Closing socket on accept because: ", ecode.message ()); - delete socket; - } + return std::make_shared (this, socket); } } diff --git a/SOCKS.h b/SOCKS.h index dc97bc0e..3d107f1c 100644 --- a/SOCKS.h +++ b/SOCKS.h @@ -11,28 +11,16 @@ namespace i2p { namespace proxy { - class SOCKSHandler; - class SOCKSServer: public i2p::client::I2PService + class SOCKSServer: public i2p::client::TCPIPAcceptor { - private: - std::set > m_Handlers; - boost::asio::ip::tcp::acceptor m_Acceptor; - boost::asio::deadline_timer m_Timer; - std::mutex m_HandlersMutex; - - private: - - void Accept(); - void HandleAccept(const boost::system::error_code& ecode, boost::asio::ip::tcp::socket * socket); + protected: + // Implements TCPIPAcceptor + std::shared_ptr CreateHandler(boost::asio::ip::tcp::socket * socket); + const char* GetName() { return "SOCKS"; } public: - SOCKSServer(int port) : I2PService(nullptr), - m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), port)), - m_Timer (GetService ()) {}; - ~SOCKSServer() { Stop(); } - - void Start (); - void Stop (); + SOCKSServer(int port) : TCPIPAcceptor(port) {} + ~SOCKSServer() {} }; typedef SOCKSServer SOCKSProxy; From df3e8ce93708a26a5772014cf50450b899e3a76c Mon Sep 17 00:00:00 2001 From: "Francisco Blas (klondike) Izquierdo Riera" Date: Thu, 8 Jan 2015 03:28:54 +0100 Subject: [PATCH 4/5] Move Stream creation to its own handler for cleanliness, it will hand over to a tunnel connection when done --- I2PTunnel.cpp | 76 ++++++++++++++++++++++++++++++++++++++------------- I2PTunnel.h | 1 - 2 files changed, 57 insertions(+), 20 deletions(-) diff --git a/I2PTunnel.cpp b/I2PTunnel.cpp index 2f96b859..6771abd5 100644 --- a/I2PTunnel.cpp +++ b/I2PTunnel.cpp @@ -151,6 +151,57 @@ namespace client } } + /* This handler tries to stablish a connection with the desired server and dies if it fails to do so */ + class I2PClientTunnelHandler: public I2PServiceHandler, public std::enable_shared_from_this + { + public: + I2PClientTunnelHandler (I2PClientTunnel * parent, i2p::data::IdentHash destination, + boost::asio::ip::tcp::socket * socket): + I2PServiceHandler(parent), m_DestinationIdentHash(destination), m_Socket(socket) {} + void Handle(); + void Terminate(); + private: + void HandleStreamRequestComplete (std::shared_ptr stream); + i2p::data::IdentHash m_DestinationIdentHash; + boost::asio::ip::tcp::socket * m_Socket; + }; + + void I2PClientTunnelHandler::Handle() + { + GetOwner()->GetLocalDestination ()->CreateStream (std::bind (&I2PClientTunnelHandler::HandleStreamRequestComplete, + shared_from_this(), std::placeholders::_1), m_DestinationIdentHash); + } + + void I2PClientTunnelHandler::HandleStreamRequestComplete (std::shared_ptr stream) + { + if (stream) + { + if (Kill()) return; + LogPrint (eLogInfo,"New I2PTunnel connection"); + auto connection = std::make_shared(GetOwner(), m_Socket, stream); + GetOwner()->AddHandler (connection); + connection->I2PConnect (); + Done(shared_from_this()); + } + else + { + LogPrint (eLogError,"I2P Client Tunnel Issue when creating the stream, check the previous warnings for more info."); + Terminate(); + } + } + + void I2PClientTunnelHandler::Terminate() + { + if (Kill()) return; + if (m_Socket) + { + m_Socket->close(); + delete m_Socket; + m_Socket = nullptr; + } + Done(shared_from_this()); + } + I2PClientTunnel::I2PClientTunnel (const std::string& destination, int port, ClientDestination * localDestination): I2PService (localDestination), m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), port)), @@ -208,12 +259,15 @@ namespace client { const i2p::data::IdentHash *identHash = GetIdentHash(); if (identHash) - GetLocalDestination ()->CreateStream ( - std::bind (&I2PClientTunnel::HandleStreamRequestComplete, - this, std::placeholders::_1, socket), *identHash); + { + auto connection = std::make_shared(this, *identHash, socket); + AddHandler (connection); + connection->Handle (); + } else { LogPrint (eLogError,"Closing socket"); + socket->close(); delete socket; } Accept (); @@ -225,22 +279,6 @@ namespace client } } - void I2PClientTunnel::HandleStreamRequestComplete (std::shared_ptr stream, boost::asio::ip::tcp::socket * socket) - { - if (stream) - { - LogPrint (eLogInfo,"New I2PTunnel connection"); - auto connection = std::make_shared(this, socket, stream); - AddHandler (connection); - connection->I2PConnect (); - } - else - { - LogPrint (eLogError,"Issue when creating the stream, check the previous warnings for more info."); - delete socket; - } - } - I2PServerTunnel::I2PServerTunnel (const std::string& address, int port, ClientDestination * localDestination): I2PService (localDestination), m_Endpoint (boost::asio::ip::address::from_string (address), port) { diff --git a/I2PTunnel.h b/I2PTunnel.h index f19f128c..374fa107 100644 --- a/I2PTunnel.h +++ b/I2PTunnel.h @@ -70,7 +70,6 @@ namespace client const i2p::data::IdentHash * GetIdentHash (); void Accept (); void HandleAccept (const boost::system::error_code& ecode, boost::asio::ip::tcp::socket * socket); - void HandleStreamRequestComplete (std::shared_ptr stream, boost::asio::ip::tcp::socket * socket); private: From 56014962d4cba1b585b2bd18b1890284f3908c79 Mon Sep 17 00:00:00 2001 From: "Francisco Blas (klondike) Izquierdo Riera" Date: Thu, 8 Jan 2015 03:49:35 +0100 Subject: [PATCH 5/5] Make I2PClientTunnel use TCPIPAcceptor --- HTTPProxy.h | 1 - I2PService.h | 1 + I2PTunnel.cpp | 53 ++++++++------------------------------------------- I2PTunnel.h | 16 ++++++++-------- 4 files changed, 17 insertions(+), 54 deletions(-) diff --git a/HTTPProxy.h b/HTTPProxy.h index 4558c88f..a7b81553 100644 --- a/HTTPProxy.h +++ b/HTTPProxy.h @@ -11,7 +11,6 @@ namespace i2p { namespace proxy { - class HTTPProxyHandler; class HTTPProxyServer: public i2p::client::TCPIPAcceptor { protected: diff --git a/I2PService.h b/I2PService.h index 636a9780..a03f16ed 100644 --- a/I2PService.h +++ b/I2PService.h @@ -76,6 +76,7 @@ namespace client std::atomic m_Dead; //To avoid cleaning up multiple times }; + /* TODO: support IPv6 too */ //This is a service that listens for connections on the IP network and interacts with I2P class TCPIPAcceptor: public I2PService { diff --git a/I2PTunnel.cpp b/I2PTunnel.cpp index 6771abd5..fe59b7d7 100644 --- a/I2PTunnel.cpp +++ b/I2PTunnel.cpp @@ -203,29 +203,17 @@ namespace client } I2PClientTunnel::I2PClientTunnel (const std::string& destination, int port, ClientDestination * localDestination): - I2PService (localDestination), - m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), port)), - m_Timer (GetService ()), m_Destination (destination), m_DestinationIdentHash (nullptr) - { - } + TCPIPAcceptor (port,localDestination), m_Destination (destination), m_DestinationIdentHash (nullptr) + {} - I2PClientTunnel::~I2PClientTunnel () - { - Stop (); - } - void I2PClientTunnel::Start () { GetIdentHash(); - m_Acceptor.listen (); - Accept (); } void I2PClientTunnel::Stop () { - m_Acceptor.close(); - m_Timer.cancel (); - ClearHandlers (); + TCPIPAcceptor::Stop(); auto *originalIdentHash = m_DestinationIdentHash; m_DestinationIdentHash = nullptr; delete originalIdentHash; @@ -245,38 +233,13 @@ namespace client return m_DestinationIdentHash; } - - void I2PClientTunnel::Accept () + std::shared_ptr I2PClientTunnel::CreateHandler(boost::asio::ip::tcp::socket * socket) { - auto newSocket = new boost::asio::ip::tcp::socket (GetService ()); - m_Acceptor.async_accept (*newSocket, std::bind (&I2PClientTunnel::HandleAccept, this, - std::placeholders::_1, newSocket)); - } - - void I2PClientTunnel::HandleAccept (const boost::system::error_code& ecode, boost::asio::ip::tcp::socket * socket) - { - if (!ecode) - { - const i2p::data::IdentHash *identHash = GetIdentHash(); - if (identHash) - { - auto connection = std::make_shared(this, *identHash, socket); - AddHandler (connection); - connection->Handle (); - } - else - { - LogPrint (eLogError,"Closing socket"); - socket->close(); - delete socket; - } - Accept (); - } + const i2p::data::IdentHash *identHash = GetIdentHash(); + if (identHash) + return std::make_shared(this, *identHash, socket); else - { - LogPrint (eLogError,"Closing socket on accept because: ", ecode.message ()); - delete socket; - } + return nullptr; } I2PServerTunnel::I2PServerTunnel (const std::string& address, int port, ClientDestination * localDestination): diff --git a/I2PTunnel.h b/I2PTunnel.h index 374fa107..010f4843 100644 --- a/I2PTunnel.h +++ b/I2PTunnel.h @@ -55,12 +55,18 @@ namespace client bool m_IsQuiet; // don't send destination }; - class I2PClientTunnel: public I2PService + class I2PClientTunnel: public TCPIPAcceptor { + protected: + + // Implements TCPIPAcceptor + std::shared_ptr CreateHandler(boost::asio::ip::tcp::socket * socket); + const char* GetName() { return "I2P Client Tunnel"; } + public: I2PClientTunnel (const std::string& destination, int port, ClientDestination * localDestination = nullptr); - ~I2PClientTunnel (); + ~I2PClientTunnel () {} void Start (); void Stop (); @@ -68,13 +74,7 @@ namespace client private: const i2p::data::IdentHash * GetIdentHash (); - void Accept (); - void HandleAccept (const boost::system::error_code& ecode, boost::asio::ip::tcp::socket * socket); - private: - - boost::asio::ip::tcp::acceptor m_Acceptor; - boost::asio::deadline_timer m_Timer; std::string m_Destination; const i2p::data::IdentHash * m_DestinationIdentHash; };