diff --git a/i2pcontrol/I2PControl.cpp b/i2pcontrol/I2PControl.cpp index ae895606..0d642ce9 100644 --- a/i2pcontrol/I2PControl.cpp +++ b/i2pcontrol/I2PControl.cpp @@ -122,6 +122,17 @@ I2PControlSession::I2PControlSession(boost::asio::io_service& ios) routerManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_RESEED] = &I2PControlSession::handleReseed; } +I2PControlSession::~I2PControlSession() +{ + stop(); +} + +void I2PControlSession::stop() +{ + boost::system::error_code e; // Make sure this doesn't throw + shutdownTimer.cancel(e); +} + I2PControlSession::Response I2PControlSession::handleRequest(std::stringstream& request) { boost::property_tree::ptree pt; diff --git a/i2pcontrol/I2PControl.h b/i2pcontrol/I2PControl.h index eae0a6f3..5d021172 100644 --- a/i2pcontrol/I2PControl.h +++ b/i2pcontrol/I2PControl.h @@ -57,6 +57,7 @@ const char I2P_CONTROL_ROUTER_MANAGER_RESEED[] = "Reseed"; /** * "Null" I2P control implementation, does not do actual networking. * @note authentication tokens are per-session + * @warning an I2PControlSession must be destroyed before its io_service */ class I2PControlSession { @@ -104,10 +105,19 @@ public: /** * Sets up the appropriate handlers. - * @param ios the parent io_service object + * @param ios the parent io_service object, must remain valid throughout + * the lifetime of this I2PControlSession. */ I2PControlSession(boost::asio::io_service& ios); + ~I2PControlSession(); + + /** + * Cancels all operations that are waiting. + * @note must not be called before destruction, destructor handles this + */ + void stop(); + /** * Handle a json string with I2PControl instructions. */ @@ -120,7 +130,6 @@ private: const PropertyTree& pt, Response& results ); typedef void (I2PControlSession::*RequestHandler)(Response& results); - /** * Tries to authenticate by checking whether the given token is valid. diff --git a/i2pcontrol/I2PControlServer.cpp b/i2pcontrol/I2PControlServer.cpp index ceb947fa..119e3835 100644 --- a/i2pcontrol/I2PControlServer.cpp +++ b/i2pcontrol/I2PControlServer.cpp @@ -11,11 +11,12 @@ namespace i2p namespace client { I2PControlService::I2PControlService(const std::string& address, int port) - : m_Session(m_Service), m_IsRunning(false), m_Thread(nullptr), + : m_Session(new I2PControlSession(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 () @@ -39,6 +40,8 @@ namespace client { m_IsRunning = false; m_Acceptor.cancel (); + // Delete the session before the io_service is stopped and destroyed + delete m_Session; m_Service.stop (); if (m_Thread) { @@ -126,7 +129,7 @@ namespace client } } - I2PControlSession::Response response = m_Session.handleRequest(ss); + I2PControlSession::Response response = m_Session->handleRequest(ss); SendResponse(socket, buf, response.toJsonString(), isHtml); } catch (const std::exception& ex) diff --git a/i2pcontrol/I2PControlServer.h b/i2pcontrol/I2PControlServer.h index 7113288b..eaffb213 100644 --- a/i2pcontrol/I2PControlServer.h +++ b/i2pcontrol/I2PControlServer.h @@ -48,7 +48,7 @@ private: boost::asio::io_service m_Service; boost::asio::ip::tcp::acceptor m_Acceptor; - I2PControlSession m_Session; + I2PControlSession* m_Session; }; }