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