From fbb18d1aa4f86003c810d9a6cbdab3490be8d328 Mon Sep 17 00:00:00 2001 From: Alex Fabijanic Date: Wed, 19 Nov 2014 22:25:28 -0600 Subject: [PATCH] (Parallel)SocketAcceptor ctor/dtor call virtual functions #608 --- Net/include/Poco/Net/ParallelSocketAcceptor.h | 54 ++++++++++++++----- Net/include/Poco/Net/SocketAcceptor.h | 48 ++++++++++++----- Net/testsuite/src/SocketReactorTest.cpp | 20 +++++++ Net/testsuite/src/SocketReactorTest.h | 1 + 4 files changed, 97 insertions(+), 26 deletions(-) diff --git a/Net/include/Poco/Net/ParallelSocketAcceptor.h b/Net/include/Poco/Net/ParallelSocketAcceptor.h index 0532065de..f8b9e616f 100644 --- a/Net/include/Poco/Net/ParallelSocketAcceptor.h +++ b/Net/include/Poco/Net/ParallelSocketAcceptor.h @@ -73,7 +73,7 @@ public: SocketReactor& reactor, unsigned threads = Poco::Environment::processorCount()): _socket(socket), - _pReactor(0), + _pReactor(&reactor), _threads(threads), _next(0) /// Creates a ParallelSocketAcceptor using the given ServerSocket, sets the @@ -81,7 +81,9 @@ public: /// with the given SocketReactor. { init(); - registerAcceptor(reactor); + _pReactor->addEventHandler(_socket, + Poco::Observer(*this, &ParallelSocketAcceptor::onAccept)); } virtual ~ParallelSocketAcceptor() @@ -89,22 +91,42 @@ public: { try { - unregisterAcceptor(); + if (_pReactor) + { + _pReactor->removeEventHandler(_socket, + Poco::Observer(*this, &ParallelSocketAcceptor::onAccept)); + } } catch (...) { poco_unexpected(); } } + + void setReactor(SocketReactor& reactor) + /// Sets the reactor for this acceptor. + { + _pReactor = &reactor; + if (!_pReactor->hasEventHandler(_socket, Poco::Observer(*this, &SocketAcceptor::onAccept))) + { + registerAcceptor(reactor); + } + } virtual void registerAcceptor(SocketReactor& reactor) /// Registers the ParallelSocketAcceptor with a SocketReactor. /// - /// A subclass can override this and, for example, also register - /// an event handler for a timeout event. - /// - /// The overriding method must call the baseclass implementation first. + /// A subclass can override this function to e.g. + /// register an event handler for timeout event. + /// + /// The overriding method must either call the base class + /// implementation or register the accept handler on its own. { + if (_pReactor) + throw Poco::InvalidAccessException("Acceptor already registered."); + _pReactor = &reactor; _pReactor->addEventHandler(_socket, Poco::ObserverremoveEventHandler(_socket, - Poco::Observer(*this, &ParallelSocketAcceptor::onAccept)); + if (_pReactor) + { + _pReactor->removeEventHandler(_socket, + Poco::Observer(*this, &ParallelSocketAcceptor::onAccept)); + } } void onAccept(ReadableNotification* pNotification) diff --git a/Net/include/Poco/Net/SocketAcceptor.h b/Net/include/Poco/Net/SocketAcceptor.h index b6cbd3f89..ff2bfa79d 100644 --- a/Net/include/Poco/Net/SocketAcceptor.h +++ b/Net/include/Poco/Net/SocketAcceptor.h @@ -78,11 +78,12 @@ public: SocketAcceptor(ServerSocket& socket, SocketReactor& reactor): _socket(socket), - _pReactor(0) + _pReactor(&reactor) /// Creates a SocketAcceptor, using the given ServerSocket. /// The SocketAcceptor registers itself with the given SocketReactor. { - registerAcceptor(reactor); + _pReactor->addEventHandler(_socket, Poco::Observer(*this, &SocketAcceptor::onAccept)); } virtual ~SocketAcceptor() @@ -90,22 +91,43 @@ public: { try { - unregisterAcceptor(); + if (_pReactor) + { + _pReactor->removeEventHandler(_socket, Poco::Observer(*this, &SocketAcceptor::onAccept)); + } } catch (...) { poco_unexpected(); } } - + + void setReactor(SocketReactor& reactor) + /// Sets the reactor for this acceptor. + { + _pReactor = &reactor; + if (!_pReactor->hasEventHandler(_socket, Poco::Observer(*this, &SocketAcceptor::onAccept))) + { + registerAcceptor(reactor); + } + } + virtual void registerAcceptor(SocketReactor& reactor) /// Registers the SocketAcceptor with a SocketReactor. /// - /// A subclass can override this and, for example, also register - /// an event handler for a timeout event. - /// - /// The overriding method must call the baseclass implementation first. + /// A subclass can override this function to e.g. + /// register an event handler for timeout event. + /// + /// If acceptor was constructed without providing reactor to it, + /// the override of this method must either call the base class + /// implementation or directly register the accept handler with + /// the reactor. { + if (_pReactor) + throw Poco::InvalidAccessException("Acceptor already registered."); + _pReactor = &reactor; _pReactor->addEventHandler(_socket, Poco::Observer(*this, &SocketAcceptor::onAccept)); } @@ -113,10 +135,12 @@ public: virtual void unregisterAcceptor() /// Unregisters the SocketAcceptor. /// - /// A subclass can override this and, for example, also unregister - /// its event handler for a timeout event. - /// - /// The overriding method must call the baseclass implementation first. + /// A subclass can override this function to e.g. + /// unregister its event handler for a timeout event. + /// + /// If the accept handler was registered with the reactor, + /// the overriding method must either call the base class + /// implementation or directly unregister the accept handler. { if (_pReactor) { diff --git a/Net/testsuite/src/SocketReactorTest.cpp b/Net/testsuite/src/SocketReactorTest.cpp index f1f9a8598..fce4a70c7 100644 --- a/Net/testsuite/src/SocketReactorTest.cpp +++ b/Net/testsuite/src/SocketReactorTest.cpp @@ -327,6 +327,26 @@ void SocketReactorTest::testSocketReactor() } +void SocketReactorTest::testSetSocketReactor() +{ + SocketAddress ssa; + ServerSocket ss(ssa); + SocketReactor reactor; + SocketAcceptor acceptor(ss); + acceptor.setReactor(reactor); + SocketAddress sa("localhost", ss.address().port()); + SocketConnector connector(sa, reactor); + ClientServiceHandler::setOnce(true); + ClientServiceHandler::resetData(); + reactor.run(); + std::string data(ClientServiceHandler::data()); + assert(data.size() == 1024); + assert(!ClientServiceHandler::readableError()); + assert(!ClientServiceHandler::writableError()); + assert(!ClientServiceHandler::timeoutError()); +} + + void SocketReactorTest::testParallelSocketReactor() { SocketAddress ssa; diff --git a/Net/testsuite/src/SocketReactorTest.h b/Net/testsuite/src/SocketReactorTest.h index c47ffa4d9..6f3d13817 100644 --- a/Net/testsuite/src/SocketReactorTest.h +++ b/Net/testsuite/src/SocketReactorTest.h @@ -27,6 +27,7 @@ public: ~SocketReactorTest(); void testSocketReactor(); + void testSetSocketReactor(); void testParallelSocketReactor(); void testSocketConnectorFail(); void testSocketConnectorTimeout();