Mercurial > irccd
changeset 124:0895acad4072
Irccd: implement Service and InterruptService, #494, #495
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 10 May 2016 22:11:36 +0200 |
parents | c7fee63ccf92 |
children | ef4bef0bf0f8 |
files | lib/irccd/CMakeSources.cmake lib/irccd/irccd.cpp lib/irccd/irccd.hpp lib/irccd/service-interrupt.cpp lib/irccd/service-interrupt.hpp lib/irccd/service.hpp |
diffstat | 6 files changed, 249 insertions(+), 38 deletions(-) [+] |
line wrap: on
line diff
--- a/lib/irccd/CMakeSources.cmake Tue May 10 21:27:40 2016 +0200 +++ b/lib/irccd/CMakeSources.cmake Tue May 10 22:11:36 2016 +0200 @@ -62,6 +62,8 @@ ${CMAKE_CURRENT_LIST_DIR}/server-state-connected.hpp ${CMAKE_CURRENT_LIST_DIR}/server-state-connecting.hpp ${CMAKE_CURRENT_LIST_DIR}/server-state-disconnected.hpp + ${CMAKE_CURRENT_LIST_DIR}/service.hpp + ${CMAKE_CURRENT_LIST_DIR}/service-interrupt.hpp ${CMAKE_CURRENT_LIST_DIR}/sockets.hpp ${CMAKE_CURRENT_LIST_DIR}/system.hpp ${CMAKE_CURRENT_LIST_DIR}/timer.hpp @@ -129,6 +131,7 @@ ${CMAKE_CURRENT_LIST_DIR}/server-state-connected.cpp ${CMAKE_CURRENT_LIST_DIR}/server-state-connecting.cpp ${CMAKE_CURRENT_LIST_DIR}/server-state-disconnected.cpp + ${CMAKE_CURRENT_LIST_DIR}/service-interrupt.cpp ${CMAKE_CURRENT_LIST_DIR}/sockets.cpp ${CMAKE_CURRENT_LIST_DIR}/system.cpp ${CMAKE_CURRENT_LIST_DIR}/timer.cpp
--- a/lib/irccd/irccd.cpp Tue May 10 21:27:40 2016 +0200 +++ b/lib/irccd/irccd.cpp Tue May 10 22:11:36 2016 +0200 @@ -26,6 +26,7 @@ #include "logger.hpp" #include "path.hpp" #include "server-event.hpp" +#include "service-interrupt.hpp" #include "util.hpp" using namespace std; @@ -630,17 +631,6 @@ }); } -void Irccd::processIpc(fd_set &input) -{ - if (FD_ISSET(m_socketServer.handle(), &input)) { - try { - (void)m_socketServer.recv(8); - } catch (const exception &) { - // TODO: think what we can do here - } - } -} - void Irccd::processTransportClients(fd_set &input, fd_set &output) { for (auto &client : m_transportClients) { @@ -695,8 +685,10 @@ void Irccd::process(fd_set &setinput, fd_set &setoutput) { - /* 1. May be IPC */ - processIpc(setinput); + // TODO: create services for servers and transports + for (const auto &service : m_services) { + service->sync(setinput, setoutput); + } /* 2. Check for transport clients */ processTransportClients(setinput, setoutput); @@ -709,16 +701,9 @@ } Irccd::Irccd() + : m_interruptService(std::make_shared<InterruptService>()) { - /* Bind a socket to any port */ - m_socketServer.set(net::option::SockReuseAddress{true}); - m_socketServer.bind(net::address::Ip{"*", 0}); - m_socketServer.listen(1); - - /* Do the socket pair */ - m_socketClient.connect(net::address::Ip{"127.0.0.1", m_socketServer.address().port()}); - m_socketServer = m_socketServer.accept(nullptr); - m_socketClient.set(net::option::SockBlockMode{false}); + m_services.push_back(m_interruptService); } void Irccd::post(std::function<void (Irccd &)> ev) noexcept @@ -726,12 +711,7 @@ std::lock_guard<mutex> lock(m_mutex); m_events.push_back(move(ev)); - - /* Silently discard */ - try { - m_socketClient.send(" "); - } catch (...) { - } + m_interruptService->interrupt(); } void Irccd::addServer(shared_ptr<Server> server) noexcept @@ -999,7 +979,8 @@ { fd_set setinput; fd_set setoutput; - auto max = m_socketServer.handle(); + net::Handle max = 0; + auto set = [&] (fd_set &set, net::Handle handle) { FD_SET(handle, &set); @@ -1010,8 +991,10 @@ FD_ZERO(&setinput); FD_ZERO(&setoutput); - /* 1. Add master socket */ - FD_SET(m_socketServer.handle(), &setinput); + // TODO: create services for servers and transports + for (const auto &service : m_services) { + service->prepare(setinput, setoutput, max); + } /* 2. Add servers */ for (auto &server : m_servers) { @@ -1036,7 +1019,7 @@ /* 5. Do the selection */ struct timeval tv; - tv.tv_sec = 0; + tv.tv_sec = 5; tv.tv_usec = 250000; int error = select(max + 1, &setinput, &setoutput, nullptr, &tv);
--- a/lib/irccd/irccd.hpp Tue May 10 21:27:40 2016 +0200 +++ b/lib/irccd/irccd.hpp Tue May 10 22:11:36 2016 +0200 @@ -48,8 +48,10 @@ namespace irccd { +class InterruptService; class Irccd; class Plugin; +class Service; class TransportCommand; /** @@ -73,10 +75,6 @@ std::mutex m_mutex; std::vector<std::function<void (Irccd &)>> m_events; - // IPC. - net::SocketTcp<net::address::Ip> m_socketServer; - net::SocketTcp<net::address::Ip> m_socketClient; - // Servers. std::vector<std::shared_ptr<Server>> m_servers; @@ -92,6 +90,10 @@ std::vector<std::shared_ptr<TransportClient>> m_transportClients; std::vector<std::shared_ptr<TransportServer>> m_transportServers; + // Services + std::shared_ptr<InterruptService> m_interruptService; + std::vector<std::shared_ptr<Service>> m_services; + /* * Server slots * ---------------------------------------------------------- @@ -140,7 +142,6 @@ * These functions are called after polling which sockets are ready for reading/writing. */ - void processIpc(fd_set &input); void processTransportClients(fd_set &input, fd_set &output); void processTransportServers(fd_set &input); void processServers(fd_set &input, fd_set &output); @@ -148,11 +149,19 @@ public: /** - * Constructor that instanciate IPC. + * Prepare standard services. */ Irccd(); /** + * Add a generic service. + */ + inline void addService(std::shared_ptr<Service> service) + { + m_services.push_back(std::move(service)); + } + + /** * Add an event to the queue. This will immediately signals the event loop to interrupt itself to dispatch * the pending events. *
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/service-interrupt.cpp Tue May 10 22:11:36 2016 +0200 @@ -0,0 +1,68 @@ +/* + * service-interrupt.cpp -- interrupt irccd event loop + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "logger.hpp" +#include "service-interrupt.hpp" + +namespace irccd { + +InterruptService::InterruptService() +{ + // Bind a socket to any port. + m_in.set(net::option::SockReuseAddress{true}); + m_in.bind(net::address::Ip{"*", 0}); + m_in.listen(1); + + // Do the socket pair. + m_out.connect(net::address::Ip{"127.0.0.1", m_in.address().port()}); + m_in = m_in.accept(nullptr); + m_out.set(net::option::SockBlockMode{false}); +} + +void InterruptService::prepare(fd_set &in, fd_set &, net::Handle &max) +{ + FD_SET(m_in.handle(), &in); + + if (m_in.handle() > max) { + max = m_in.handle(); + } +} + +void InterruptService::sync(fd_set &in, fd_set &) +{ + if (FD_ISSET(m_in.handle(), &in)) { + try { + log::debug("irccd: interrupt service recv"); + m_in.recv(32); + } catch (const std::exception &ex) { + log::warning() << "irccd: interrupt service error: " << ex.what() << std::endl; + } + } +} + +void InterruptService::interrupt() noexcept +{ + try { + log::debug("irccd: interrupt service send"); + m_out.send(" "); + } catch (const std::exception &ex) { + log::warning() << "irccd: interrupt service error: " << ex.what() << std::endl; + } +} + +} // !irccd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/service-interrupt.hpp Tue May 10 22:11:36 2016 +0200 @@ -0,0 +1,65 @@ +/* + * service-interrupt.hpp -- interrupt irccd event loop + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_SERVICE_INTERRUPT_HPP +#define IRCCD_SERVICE_INTERRUPT_HPP + +/** + * \file service-interrupt.hpp + * \brief Interrupt irccd event loop. + */ + +#include "service.hpp" + +namespace irccd { + +/** + * \brief Interrupt irccd event loop. + */ +class InterruptService : public Service { +private: + net::SocketTcpIp m_in; + net::SocketTcpIp m_out; + +public: + /** + * Prepare the socket pair. + * + * \throw std::runtime_error on errors + */ + InterruptService(); + + /** + * \copydoc Service::prepare + */ + void prepare(fd_set &in, fd_set &out, net::Handle &max) override; + + /** + * \copydoc Service::sync + */ + void sync(fd_set &in, fd_set &out) override; + + /** + * Request interruption. + */ + void interrupt() noexcept; +}; + +} // !irccd + +#endif // !IRCCD_SERVICE_INTERRUPT_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/service.hpp Tue May 10 22:11:36 2016 +0200 @@ -0,0 +1,83 @@ +/* + * service.hpp -- selectable service + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_SERVICE_HPP +#define IRCCD_SERVICE_HPP + +/** + * \file service.hpp + * \brief Selectable service. + */ + +#include "sockets.hpp" + +namespace irccd { + +/** + * \brief Selectable service. + * + * This class can be used to prepare a set of sockets that will be selected by Irccd class. + * + * First, the function prepare is called, the user is responsible to fill the input and output set and adjust max + * accordingly. + * + * Second, after select has been called, sync is called. The user is responsible of checking which sockets are ready + * for input or output. + */ +class Service { +public: + /** + * Default constructor. + */ + Service() noexcept = default; + + /** + * Virtual destructor defaulted. + */ + virtual ~Service() noexcept = default; + + /** + * Prepare the input and output set. + * + * \param in the input set + * \param out the output set + * \param max the handle to update + */ + virtual void prepare(fd_set &in, fd_set &out, net::Handle &max) + { + (void)in; + (void)out; + (void)max; + } + + /** + * Synchronize with result sets. + * + * \param in the input set + * \param out the output set + */ + virtual void sync(fd_set &in, fd_set &out) + { + (void)in; + (void)out; + } +}; + +} // !irccd + +#endif // !IRCCD_SERVICE_HPP