Mercurial > irccd
view lib/irccd/server-state.cpp @ 79:d0deb5835aed
Irccd: use bridge for libircclient to hide dependency, #449
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 30 Mar 2016 21:30:53 +0200 |
parents | 98ac3c79009f |
children | c67e734c9241 |
line wrap: on
line source
/* * server-state.cpp -- 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. */ #include <cassert> #include <irccd-config.h> #if !defined(_WIN32) # include <sys/types.h> # include <netinet/in.h> # include <arpa/nameser.h> # include <resolv.h> #endif #include "server-state.h" #include "server-private.h" namespace irccd { bool ServerState::connect(Server &server) { const ServerInfo &info = server.info(); const ServerIdentity &identity = server.identity(); const char *password = info.password.empty() ? nullptr : info.password.c_str(); std::string host = info.host; int code; /* libircclient requires # for SSL connection */ #if defined(WITH_SSL) if (info.flags & ServerInfo::Ssl) host.insert(0, 1, '#'); if (!(info.flags & ServerInfo::SslVerify)) irc_option_set(server.session(), LIBIRC_OPTION_SSL_NO_VERIFY); #endif if (info.flags & ServerInfo::Ipv6) { code = irc_connect6(server.session(), host.c_str(), info.port, password, identity.nickname.c_str(), identity.username.c_str(), identity.realname.c_str()); } else { code = irc_connect(server.session(), host.c_str(), info.port, password, identity.nickname.c_str(), identity.username.c_str(), identity.realname.c_str()); } return code == 0; } void ServerState::prepareConnected(Server &server, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd) { if (!irc_is_connected(server.session())) { const ServerSettings &settings = server.settings(); log::warning() << "server " << server.info().name << ": disconnected" << std::endl; if (settings.recotimeout > 0) { log::warning() << "server " << server.info().name << ": retrying in " << settings.recotimeout << " seconds" << std::endl; } server.next(ServerState::Disconnected); } else { irc_add_select_descriptors(server.session(), &setinput, &setoutput, reinterpret_cast<int *>(&maxfd)); } } void ServerState::prepareConnecting(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. */ const ServerInfo &info = server.info(); if (m_started) { const ServerSettings &settings = server.settings(); if (m_timer.elapsed() > static_cast<unsigned>(settings.recotimeout * 1000)) { log::warning() << "server " << info.name << ": timeout while connecting" << std::endl; server.next(ServerState::Disconnected); } else if (!irc_is_connected(server.session())) { log::warning() << "server " << info.name << ": error while connecting: "; log::warning() << irc_strerror(irc_errno(server.session())) << std::endl; if (settings.recotries != 0) log::warning() << "server " << info.name << ": retrying in " << settings.recotimeout << " seconds" << std::endl; server.next(ServerState::Disconnected); } else { irc_add_select_descriptors(server.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(_WIN32) (void)res_init(); #endif log::info() << "server " << info.name << ": trying to connect to " << info.host << ", port " << info.port << std::endl; if (!connect(server)) { log::warning() << "server " << info.name << ": disconnected while connecting: "; log::warning() << irc_strerror(irc_errno(server.session())) << std::endl; server.next(ServerState::Disconnected); } else { m_started = true; } } } void ServerState::prepareDisconnected(Server &server, fd_set &, fd_set &, net::Handle &) { const ServerInfo &info = server.info(); ServerSettings &settings = server.settings(); if (settings.recotries == 0) { log::warning() << "server " << info.name << ": reconnection disabled, skipping" << std::endl; server.onDie(); } else if (settings.recotries > 0 && settings.recocurrent > settings.recotries) { log::warning() << "server " << info.name << ": giving up" << std::endl; server.onDie(); } else { if (m_timer.elapsed() > static_cast<unsigned>(settings.recotimeout * 1000)) { irc_disconnect(server.session()); settings.recocurrent ++; server.next(ServerState::Connecting); } } } ServerState::ServerState(Type type) : m_type(type) { assert(static_cast<int>(m_type) >= static_cast<int>(ServerState::Undefined)); assert(static_cast<int>(m_type) <= static_cast<int>(ServerState::Disconnected)); } void ServerState::prepare(Server &server, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd) { switch (m_type) { case Connecting: prepareConnecting(server, setinput, setoutput, maxfd); break; case Connected: prepareConnected(server, setinput, setoutput, maxfd); break; case Disconnected: prepareDisconnected(server, setinput, setoutput, maxfd); break; default: break; } } } // !irccd