Mercurial > irccd
changeset 246:62807bf9a68c
Irccd: reduce server stuff
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 17 Aug 2016 20:41:25 +0200 |
parents | 520bf779bf28 |
children | 4dec71ea1326 |
files | lib/irccd/CMakeSources.cmake lib/irccd/server-private.hpp lib/irccd/server-state-connected.cpp lib/irccd/server-state-connected.hpp lib/irccd/server-state-connecting.cpp lib/irccd/server-state-connecting.hpp lib/irccd/server-state-disconnected.cpp lib/irccd/server-state-disconnected.hpp lib/irccd/server-state.hpp lib/irccd/server.cpp |
diffstat | 10 files changed, 241 insertions(+), 563 deletions(-) [+] |
line wrap: on
line diff
--- a/lib/irccd/CMakeSources.cmake Wed Aug 17 18:35:31 2016 +0200 +++ b/lib/irccd/CMakeSources.cmake Wed Aug 17 20:41:25 2016 +0200 @@ -55,11 +55,6 @@ ${CMAKE_CURRENT_LIST_DIR}/plugin-js.hpp ${CMAKE_CURRENT_LIST_DIR}/rule.hpp ${CMAKE_CURRENT_LIST_DIR}/server.hpp - ${CMAKE_CURRENT_LIST_DIR}/server-private.hpp - ${CMAKE_CURRENT_LIST_DIR}/server-state.hpp - ${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-command.hpp ${CMAKE_CURRENT_LIST_DIR}/service-interrupt.hpp @@ -129,9 +124,6 @@ ${CMAKE_CURRENT_LIST_DIR}/plugin-js.cpp ${CMAKE_CURRENT_LIST_DIR}/rule.cpp ${CMAKE_CURRENT_LIST_DIR}/server.cpp - ${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-command.cpp ${CMAKE_CURRENT_LIST_DIR}/service-interrupt.cpp ${CMAKE_CURRENT_LIST_DIR}/service-module.cpp
--- a/lib/irccd/server-private.hpp Wed Aug 17 18:35:31 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * server-private.hpp -- libircclient bridge - * - * 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_SERVER_PRIVATE_HPP -#define IRCCD_SERVER_PRIVATE_HPP - -#include <memory> - -#include <libircclient.h> - -#include "server.hpp" - -namespace irccd { - -/** - * \brief Bridge for libircclient - */ -class Server::Session { -public: - /** - * libircclient handle. - */ - using Handle = std::unique_ptr<irc_session_t, void (*)(irc_session_t *)>; - -private: - Handle m_handle; - -public: - /** - * Create a null session. - */ - inline Session() - : m_handle(nullptr, nullptr) - { - } - - /** - * Convert the libircclient session. - */ - inline operator const irc_session_t *() const noexcept - { - return m_handle.get(); - } - - /** - * Overloaded function. - */ - inline operator irc_session_t *() noexcept - { - return m_handle.get(); - } - - /** - * Get the handle. - * - * \return the handle - */ - inline Handle &handle() noexcept - { - return m_handle; - } - - /** - * Tells if the connection is made. - * - * \return true if connected - */ - inline bool isConnected() const noexcept - { - return irc_is_connected(m_handle.get()); - } -}; - -} // !irccd - -#endif // !IRCCD_SERVER_PRIVATE_HPP
--- a/lib/irccd/server-state-connected.cpp Wed Aug 17 18:35:31 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * server-state-connected.cpp -- connected state - * - * 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 <format.h> - -#include "logger.hpp" -#include "server-state-connected.hpp" -#include "server-state-disconnected.hpp" -#include "server-private.hpp" - -using namespace fmt::literals; - -namespace irccd { - -void Server::ConnectedState::prepare(Server &server, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd) -{ - if (!irc_is_connected(*server.m_session)) { - log::warning() << "server " << server.m_name << ": disconnected" << std::endl; - - if (server.m_recodelay > 0) - log::warning("server {}: retrying in {} seconds"_format(server.m_name, server.m_recodelay)); - - server.next(std::make_unique<DisconnectedState>()); - } else if (server.m_timer.elapsed() >= server.m_timeout * 1000) { - log::warning() << "server " << server.m_name << ": ping timeout after " - << (server.m_timer.elapsed() / 1000) << " seconds" << std::endl; - server.next(std::make_unique<DisconnectedState>()); - } else - irc_add_select_descriptors(*server.m_session, &setinput, &setoutput, reinterpret_cast<int *>(&maxfd)); -} - -std::string Server::ConnectedState::ident() const -{ - return "Connected"; -} - -} // !irccd
--- a/lib/irccd/server-state-connected.hpp Wed Aug 17 18:35:31 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * server-state-connected.hpp -- connected state - * - * 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_SERVER_STATE_CONNECTED_HPP -#define IRCCD_SERVER_STATE_CONNECTED_HPP - -/** - * \file server-state-connected.hpp - * \brief Connected state. - */ - -#include "server-state.hpp" - -namespace irccd { - -/** - * \brief Connected state. - * \ingroup states - */ -class Server::ConnectedState : public State { -public: - /** - * \copydoc State::prepare - */ - IRCCD_EXPORT void prepare(Server &server, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd) override; - - /** - * \copydoc State::ident - */ - IRCCD_EXPORT std::string ident() const override; -}; - -} // !irccd - -#endif // !IRCCD_SERVER_STATE_CONNECTED_HPP
--- a/lib/irccd/server-state-connecting.cpp Wed Aug 17 18:35:31 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -/* - * server-state-connecting.cpp -- connecting state - * - * 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 <format.h> - -#include "logger.hpp" -#include "server-state-connecting.hpp" -#include "server-state-connected.hpp" -#include "server-state-disconnected.hpp" -#include "server-private.hpp" -#include "sysconfig.hpp" - -#if !defined(IRCCD_SYSTEM_WINDOWS) -# include <sys/types.h> -# include <netinet/in.h> -# include <arpa/nameser.h> -# include <resolv.h> -#endif - -using namespace fmt::literals; - -namespace irccd { - -bool Server::ConnectingState::connect(Server &server) -{ - const char *password = server.m_password.empty() ? nullptr : server.m_password.c_str(); - std::string host = server.m_host; - int code; - - // libircclient requires # for SSL connection. -#if defined(WITH_SSL) - if (server.m_flags & Server::Ssl) - host.insert(0, 1, '#'); - if (!(server.m_flags & Server::SslVerify)) - irc_option_set(*server.m_session, LIBIRC_OPTION_SSL_NO_VERIFY); -#endif - - if (server.flags() & Server::Ipv6) { - code = irc_connect6(*server.m_session, host.c_str(), server.m_port, password, - server.m_nickname.c_str(), - server.m_username.c_str(), - server.m_realname.c_str()); - } else { - code = irc_connect(*server.m_session, host.c_str(), server.m_port, password, - server.m_nickname.c_str(), - server.m_username.c_str(), - server.m_realname.c_str()); - } - - return code == 0; -} - -void Server::ConnectingState::prepare(Server &server, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd) -{ - /* - * The connect function will either fail if the hostname wasn't resolved or if any of the internal functions - * fail. - * - * It returns success if the connection was successful but it does not mean that connection is established. - * - * Because this function will be called repeatidly, the connection was started and we're still not - * connected in the specified timeout time, we mark the server as disconnected. - * - * Otherwise, the libircclient event_connect will change the state. - */ - if (m_started) { - if (m_timer.elapsed() > static_cast<unsigned>(server.m_recodelay * 1000)) { - log::warning() << "server " << server.name() << ": timeout while connecting" << std::endl; - server.next(std::make_unique<DisconnectedState>()); - } else if (!irc_is_connected(*server.m_session)) { - log::warning() << "server " << server.m_name << ": error while connecting: "; - log::warning() << irc_strerror(irc_errno(*server.m_session)) << std::endl; - - if (server.m_recotries != 0) - log::warning("server {}: retrying in {} seconds"_format(server.m_name, server.m_recodelay)); - - server.next(std::make_unique<DisconnectedState>()); - } else - irc_add_select_descriptors(*server.m_session, &setinput, &setoutput, reinterpret_cast<int *>(&maxfd)); - } else { - /* - * This is needed if irccd is started before DHCP or if DNS cache is outdated. - * - * For more information see bug #190. - */ -#if !defined(IRCCD_SYSTEM_WINDOWS) - (void)res_init(); -#endif - log::info("server {}: trying to connect to {}, port {}"_format(server.m_name, server.m_host, server.m_port)); - - if (!connect(server)) { - log::warning() << "server " << server.m_name << ": disconnected while connecting: "; - log::warning() << irc_strerror(irc_errno(*server.m_session)) << std::endl; - server.next(std::make_unique<DisconnectedState>()); - } else { - m_started = true; - - if (irc_is_connected(*server.m_session)) - irc_add_select_descriptors(*server.m_session, &setinput, &setoutput, reinterpret_cast<int *>(&maxfd)); - } - } -} - -std::string Server::ConnectingState::ident() const -{ - return "Connecting"; -} - -} // !irccd
--- a/lib/irccd/server-state-connecting.hpp Wed Aug 17 18:35:31 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * server-state-connecting.hpp -- connecting state - * - * 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_SERVER_STATE_CONNECTING_HPP -#define IRCCD_SERVER_STATE_CONNECTING_HPP - -/** - * \file server-state-connecting.hpp - * \brief Connecting state. - */ - -#include "elapsed-timer.hpp" -#include "server-state.hpp" - -namespace irccd { - -/** - * \brief Connecting state. - * \ingroup states - */ -class Server::ConnectingState : public State { -private: - bool m_started{false}; - ElapsedTimer m_timer; - - bool connect(Server &server); - -public: - /** - * \copydoc State::prepare - */ - IRCCD_EXPORT void prepare(Server &server, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd) override; - - /** - * \copydoc State::ident - */ - IRCCD_EXPORT std::string ident() const override; -}; - -} // !irccd - -#endif // !IRCCD_SERVER_STATE_CONNECTING_HPP
--- a/lib/irccd/server-state-disconnected.cpp Wed Aug 17 18:35:31 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * server-state-disconnected.cpp -- disconnected state - * - * 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 "server-state-connecting.hpp" -#include "server-state-disconnected.hpp" -#include "server-private.hpp" - -namespace irccd { - -void Server::DisconnectedState::prepare(Server &server, fd_set &, fd_set &, net::Handle &) -{ - if (server.m_recotries == 0) { - log::warning() << "server " << server.m_name << ": reconnection disabled, skipping" << std::endl; - server.onDie(); - } else if (server.m_recotries > 0 && server.m_recocur > server.m_recotries) { - log::warning() << "server " << server.m_name << ": giving up" << std::endl; - server.onDie(); - } else { - if (m_timer.elapsed() > static_cast<unsigned>(server.m_recodelay * 1000)) { - irc_disconnect(*server.m_session); - - server.m_recocur ++; - server.next(std::make_unique<ConnectingState>()); - } - } -} - -std::string Server::DisconnectedState::ident() const -{ - return "Disconnected"; -} - -} // !irccd
--- a/lib/irccd/server-state-disconnected.hpp Wed Aug 17 18:35:31 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * server-state-disconnected.hpp -- disconnected state - * - * 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_SERVER_STATE_DISCONNECTED_HPP -#define IRCCD_SERVER_STATE_DISCONNECTED_HPP - -/** - * \file server-state-disconnected.hpp - * \brief Connecting state. - */ - -#include "elapsed-timer.hpp" -#include "server-state.hpp" - -namespace irccd { - -/** - * \brief Disconnected state. - * \ingroup states - */ -class Server::DisconnectedState : public Server::State { -private: - ElapsedTimer m_timer; - -public: - /** - * \copydoc State::prepare - */ - IRCCD_EXPORT void prepare(Server &server, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd) override; - - /** - * \copydoc State::ident - */ - IRCCD_EXPORT std::string ident() const override; -}; - -} // !irccd - -#endif // !IRCCD_SERVER_STATE_DISCONNECTED_HPP
--- a/lib/irccd/server-state.hpp Wed Aug 17 18:35:31 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * server-state.hpp -- server current state - * - * 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_SERVER_STATE_HPP -#define IRCCD_SERVER_STATE_HPP - -/** - * \file server-state.hpp - * \brief Server state. - */ - -/** - * \defgroup states Server states - * \brief States for Server class. - */ - -#include "elapsed-timer.hpp" -#include "net.hpp" -#include "sysconfig.hpp" -#include "server.hpp" - -namespace irccd { - -/** - * \brief Server current state. - */ -class Server::State { -public: - /** - * Default constructor. - */ - State() = default; - - /** - * Virtual default destructor. - */ - virtual ~State() = default; - - /** - * Prepare the state. - * - * \param server the server - * \param setinput the read set - * \param setoutput the write set - * \param maxfd the maximum fd - */ - virtual void prepare(Server &server, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd) = 0; - - /** - * Return the state identifier, only for information purposes. - * - * \return the identifier - */ - virtual std::string ident() const = 0; -}; - -} // !irccd - -#endif // !IRCCD_SERVER_STATE_HPP
--- a/lib/irccd/server.cpp Wed Aug 17 18:35:31 2016 +0200 +++ b/lib/irccd/server.cpp Wed Aug 17 20:41:25 2016 +0200 @@ -23,18 +23,110 @@ #include <format.h> +#include <libircclient.h> #include <libirc_rfcnumeric.h> +#include "sysconfig.hpp" + +#if !defined(IRCCD_SYSTEM_WINDOWS) +# include <sys/types.h> +# include <netinet/in.h> +# include <arpa/nameser.h> +# include <resolv.h> +#endif + #include "logger.hpp" -#include "server-private.hpp" -#include "server-state-connected.hpp" -#include "server-state-connecting.hpp" #include "util.hpp" +#include "server.hpp" using namespace fmt::literals; namespace irccd { +/* + * Server::Session declaration. + * ------------------------------------------------------------------ + */ + +class Server::Session { +public: + std::unique_ptr<irc_session_t, void (*)(irc_session_t *)> m_handle{nullptr, nullptr}; + + inline operator const irc_session_t *() const noexcept + { + return m_handle.get(); + } + + inline operator irc_session_t *() noexcept + { + return m_handle.get(); + } + + inline bool isConnected() const noexcept + { + return irc_is_connected(m_handle.get()); + } +}; + +/* + * Server::State declaration. + * ------------------------------------------------------------------ + */ + +class Server::State { +public: + State() = default; + virtual ~State() = default; + virtual void prepare(Server &, fd_set &, fd_set &, net::Handle &) = 0; + virtual std::string ident() const = 0; +}; + +/* + * Server::DisconnectedState declaration. + * ------------------------------------------------------------------ + */ + +class Server::DisconnectedState : public Server::State { +private: + ElapsedTimer m_timer; + +public: + void prepare(Server &, fd_set &, fd_set &, net::Handle &) override; + std::string ident() const override; +}; + +/* + * Server::ConnectingState declaration. + * ------------------------------------------------------------------ + */ + +class Server::ConnectingState : public State { +private: + enum { + Disconnected, + Connecting + } m_state{Disconnected}; + + ElapsedTimer m_timer; + + bool connect(Server &server); + +public: + void prepare(Server &, fd_set &, fd_set &, net::Handle &) override; + std::string ident() const override; +}; + +/* + * Server::ConnectedState declaration. + * ------------------------------------------------------------------ + */ + +class Server::ConnectedState : public State { +public: + void prepare(Server &, fd_set &, fd_set &, net::Handle &) override; + std::string ident() const override; +}; + namespace { /* @@ -459,7 +551,7 @@ static_cast<Server *>(irc_get_ctx(session))->handleMode(orig, params); }; - m_session->handle() = Session::Handle{irc_create_session(&callbacks), irc_destroy_session}; + m_session->m_handle = {irc_create_session(&callbacks), irc_destroy_session}; // Save this to the session. irc_set_ctx(*m_session, this); @@ -665,4 +757,149 @@ }); } +/* + * Server::DisconnectedState implementation + * ------------------------------------------------------------------ + */ + +void Server::DisconnectedState::prepare(Server &server, fd_set &, fd_set &, net::Handle &) +{ + if (server.m_recotries == 0) { + log::warning() << "server " << server.m_name << ": reconnection disabled, skipping" << std::endl; + server.onDie(); + } else if (server.m_recotries > 0 && server.m_recocur > server.m_recotries) { + log::warning() << "server " << server.m_name << ": giving up" << std::endl; + server.onDie(); + } else { + if (m_timer.elapsed() > static_cast<unsigned>(server.m_recodelay * 1000)) { + irc_disconnect(*server.m_session); + + server.m_recocur ++; + server.next(std::make_unique<ConnectingState>()); + } + } +} + +std::string Server::DisconnectedState::ident() const +{ + return "Disconnected"; +} + +/* + * Server::ConnectingState implementation + * ------------------------------------------------------------------ + */ + +bool Server::ConnectingState::connect(Server &server) +{ + const char *password = server.m_password.empty() ? nullptr : server.m_password.c_str(); + std::string host = server.m_host; + int code; + + // libircclient requires # for SSL connection. +#if defined(WITH_SSL) + if (server.m_flags & Server::Ssl) + host.insert(0, 1, '#'); + if (!(server.m_flags & Server::SslVerify)) + irc_option_set(*server.m_session, LIBIRC_OPTION_SSL_NO_VERIFY); +#endif + + if (server.flags() & Server::Ipv6) { + code = irc_connect6(*server.m_session, host.c_str(), server.m_port, password, + server.m_nickname.c_str(), + server.m_username.c_str(), + server.m_realname.c_str()); + } else { + code = irc_connect(*server.m_session, host.c_str(), server.m_port, password, + server.m_nickname.c_str(), + server.m_username.c_str(), + server.m_realname.c_str()); + } + + return code == 0; +} + +void Server::ConnectingState::prepare(Server &server, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd) +{ + /* + * The connect function will either fail if the hostname wasn't resolved or if any of the internal functions + * fail. + * + * It returns success if the connection was successful but it does not mean that connection is established. + * + * Because this function will be called repeatidly, the connection was started and we're still not + * connected in the specified timeout time, we mark the server as disconnected. + * + * Otherwise, the libircclient event_connect will change the state. + */ + if (m_state == Disconnected) { + if (m_timer.elapsed() > static_cast<unsigned>(server.m_recodelay * 1000)) { + log::warning() << "server " << server.name() << ": timeout while connecting" << std::endl; + server.next(std::make_unique<DisconnectedState>()); + } else if (!irc_is_connected(*server.m_session)) { + log::warning() << "server " << server.m_name << ": error while connecting: "; + log::warning() << irc_strerror(irc_errno(*server.m_session)) << std::endl; + + if (server.m_recotries != 0) + log::warning("server {}: retrying in {} seconds"_format(server.m_name, server.m_recodelay)); + + server.next(std::make_unique<DisconnectedState>()); + } else + irc_add_select_descriptors(*server.m_session, &setinput, &setoutput, reinterpret_cast<int *>(&maxfd)); + } else { + /* + * This is needed if irccd is started before DHCP or if DNS cache is outdated. + * + * For more information see bug #190. + */ +#if !defined(IRCCD_SYSTEM_WINDOWS) + (void)res_init(); +#endif + log::info("server {}: trying to connect to {}, port {}"_format(server.m_name, server.m_host, server.m_port)); + + if (!connect(server)) { + log::warning() << "server " << server.m_name << ": disconnected while connecting: "; + log::warning() << irc_strerror(irc_errno(*server.m_session)) << std::endl; + server.next(std::make_unique<DisconnectedState>()); + } else { + m_state = Connecting; + + if (irc_is_connected(*server.m_session)) + irc_add_select_descriptors(*server.m_session, &setinput, &setoutput, reinterpret_cast<int *>(&maxfd)); + } + } +} + +std::string Server::ConnectingState::ident() const +{ + return "Connecting"; +} + +/* + * Server::ConnectedState implementation + * ------------------------------------------------------------------ + */ + +void Server::ConnectedState::prepare(Server &server, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd) +{ + if (!irc_is_connected(*server.m_session)) { + log::warning() << "server " << server.m_name << ": disconnected" << std::endl; + + if (server.m_recodelay > 0) + log::warning("server {}: retrying in {} seconds"_format(server.m_name, server.m_recodelay)); + + server.next(std::make_unique<DisconnectedState>()); + } else if (server.m_timer.elapsed() >= server.m_timeout * 1000) { + log::warning() << "server " << server.m_name << ": ping timeout after " + << (server.m_timer.elapsed() / 1000) << " seconds" << std::endl; + server.next(std::make_unique<DisconnectedState>()); + } else + irc_add_select_descriptors(*server.m_session, &setinput, &setoutput, reinterpret_cast<int *>(&maxfd)); +} + +std::string Server::ConnectedState::ident() const +{ + return "Connected"; +} + } // !irccd