Mercurial > irccd
changeset 103:04d672ab41a4
Irccd: cleanup a lot server, #482
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 26 Apr 2016 19:31:42 +0200 |
parents | 4777f7e18bf2 |
children | be4b9ed19a17 |
files | lib/irccd/cmd-server-connect.cpp lib/irccd/config.cpp lib/irccd/js-server.cpp lib/irccd/server-state-connected.cpp lib/irccd/server-state-connecting.cpp lib/irccd/server-state-disconnected.cpp lib/irccd/server.cpp lib/irccd/server.hpp |
diffstat | 8 files changed, 145 insertions(+), 109 deletions(-) [+] |
line wrap: on
line diff
--- a/lib/irccd/cmd-server-connect.cpp Tue Apr 26 13:19:35 2016 +0200 +++ b/lib/irccd/cmd-server-connect.cpp Tue Apr 26 19:31:42 2016 +0200 @@ -106,8 +106,8 @@ ServerSettings settings; settings.command = object.valueOr("commandChar", json::Type::String, settings.command).toString(); - settings.recotries = object.valueOr("reconnectTries", json::Type::Int, settings.recotries).toInt(); - settings.recotimeout = object.valueOr("reconnectTimeout", json::Type::Int, settings.recotimeout).toInt(); + settings.reconnect_tries = object.valueOr("reconnectTries", json::Type::Int, settings.reconnect_tries).toInt(); + settings.reconnect_timeout = object.valueOr("reconnectTimeout", json::Type::Int, settings.reconnect_timeout).toInt(); return settings; }
--- a/lib/irccd/config.cpp Tue Apr 26 13:19:35 2016 +0200 +++ b/lib/irccd/config.cpp Tue Apr 26 19:31:42 2016 +0200 @@ -300,9 +300,9 @@ /* Reconnect */ try { if ((it = sc.find("reconnect-tries")) != sc.end()) - settings.recotries = std::stoi(it->value()); + settings.reconnect_tries = std::stoi(it->value()); if ((it = sc.find("reconnect-timeout")) != sc.end()) - settings.recotimeout = std::stoi(it->value()); + settings.reconnect_timeout = std::stoi(it->value()); if ((it = sc.find("ping-timeout")) != sc.end()) settings.ping_timeout = std::stoi(it->value()); } catch (const std::exception &) {
--- a/lib/irccd/js-server.cpp Tue Apr 26 13:19:35 2016 +0200 +++ b/lib/irccd/js-server.cpp Tue Apr 26 19:31:42 2016 +0200 @@ -388,8 +388,8 @@ for (const auto &chan: duk::getProperty<std::vector<std::string>>(ctx, 0, "channels")) settings.channels.push_back(Server::splitChannel(chan)); - settings.recotries = duk::optionalProperty<int>(ctx, 0, "recoTries", (int)settings.recotries); - settings.recotimeout = duk::optionalProperty<int>(ctx, 0, "recoTimeout", (int)settings.recotimeout); + settings.reconnect_tries = duk::optionalProperty<int>(ctx, 0, "recoTries", (int)settings.reconnect_tries); + settings.reconnect_timeout = duk::optionalProperty<int>(ctx, 0, "recoTimeout", (int)settings.reconnect_timeout); if (duk::optionalProperty<bool>(ctx, 0, "joinInvite", false)) settings.flags |= ServerSettings::JoinInvite;
--- a/lib/irccd/server-state-connected.cpp Tue Apr 26 13:19:35 2016 +0200 +++ b/lib/irccd/server-state-connected.cpp Tue Apr 26 19:31:42 2016 +0200 @@ -33,15 +33,15 @@ if (!irc_is_connected(server.session())) { log::warning() << "server " << info.name << ": disconnected" << std::endl; - if (settings.recotimeout > 0) { + if (settings.reconnect_timeout > 0) { log::warning() << "server " << info.name << ": retrying in " - << settings.recotimeout << " seconds" << std::endl; + << settings.reconnect_timeout << " seconds" << std::endl; } server.next(std::make_unique<state::Disconnected>()); - } else if (server.pingTimer().elapsed() >= settings.ping_timeout * 1000) { + } else if (server.cache().ping_timer.elapsed() >= settings.ping_timeout * 1000) { log::warning() << "server " << info.name << ": ping timeout after " - << (server.pingTimer().elapsed() / 1000) << " seconds" << std::endl; + << (server.cache().ping_timer.elapsed() / 1000) << " seconds" << std::endl; server.next(std::make_unique<state::Disconnected>()); } else { irc_add_select_descriptors(server.session(), &setinput, &setoutput, reinterpret_cast<int *>(&maxfd));
--- a/lib/irccd/server-state-connecting.cpp Tue Apr 26 13:19:35 2016 +0200 +++ b/lib/irccd/server-state-connecting.cpp Tue Apr 26 19:31:42 2016 +0200 @@ -87,15 +87,16 @@ if (m_started) { const ServerSettings &settings = server.settings(); - if (m_timer.elapsed() > static_cast<unsigned>(settings.recotimeout * 1000)) { + if (m_timer.elapsed() > static_cast<unsigned>(settings.reconnect_timeout * 1000)) { log::warning() << "server " << info.name << ": timeout while connecting" << std::endl; server.next(std::make_unique<state::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; + if (settings.reconnect_tries != 0) + log::warning() << "server " << info.name << ": retrying in " + << settings.reconnect_timeout << " seconds" << std::endl; server.next(std::make_unique<state::Disconnected>()); } else {
--- a/lib/irccd/server-state-disconnected.cpp Tue Apr 26 13:19:35 2016 +0200 +++ b/lib/irccd/server-state-disconnected.cpp Tue Apr 26 19:31:42 2016 +0200 @@ -29,18 +29,19 @@ { const ServerInfo &info = server.info(); ServerSettings &settings = server.settings(); + ServerCache &cache = server.cache(); - if (settings.recotries == 0) { + if (settings.reconnect_tries == 0) { log::warning() << "server " << info.name << ": reconnection disabled, skipping" << std::endl; server.onDie(); - } else if (settings.recotries > 0 && settings.recocurrent > settings.recotries) { + } else if (settings.reconnect_tries > 0 && cache.reconnect_current > settings.reconnect_tries) { log::warning() << "server " << info.name << ": giving up" << std::endl; server.onDie(); } else { - if (m_timer.elapsed() > static_cast<unsigned>(settings.recotimeout * 1000)) { + if (m_timer.elapsed() > static_cast<unsigned>(settings.reconnect_timeout * 1000)) { irc_disconnect(server.session()); - settings.recocurrent ++; + server.cache().reconnect_current ++; server.next(std::make_unique<state::Connecting>()); } }
--- a/lib/irccd/server.cpp Tue Apr 26 13:19:35 2016 +0200 +++ b/lib/irccd/server.cpp Tue Apr 26 19:31:42 2016 +0200 @@ -31,66 +31,91 @@ namespace irccd { -bool Server::isSelf(const std::string &nick) const noexcept -{ - char target[32]{0}; +namespace { - irc_target_get_nick(nick.c_str(), target, sizeof (target)); - - return m_identity.nickname == target; +/* + * strify + * ------------------------------------------------------------------ + * + * Make sure to build a C++ string with a not-null C string. + */ +inline std::string strify(const char *s) +{ + return (s == nullptr) ? "" : std::string(s); } -void Server::extractPrefixes(const std::string &line) +/* + * cleanPrefix + * ------------------------------------------------------------------ + * + * Remove the user prefix only if it is present in the mode table, for example removes @ from @irccd if and only if + * @ is a character mode (e.g. operator). + */ +std::string cleanPrefix(const ServerInfo &info, std::string nickname) +{ + if (nickname.length() > 0) { + for (const auto &pair : info.modes) { + if (nickname[0] == pair.second) { + nickname.erase(0, 1); + } + } + } + + return nickname; +} + +/* + * extractPrefixes + * ------------------------------------------------------------------ + * + * Read modes from the IRC event numeric. + */ +std::map<ServerChanMode, char> extractPrefixes(const std::string &line) { std::pair<char, char> table[16]; std::string buf = line.substr(7); + std::map<ServerChanMode, char> modes; for (int i = 0; i < 16; ++i) table[i] = std::make_pair(-1, -1); int j = 0; - bool readModes = true; + bool read_modes = true; for (size_t i = 0; i < buf.size(); ++i) { if (buf[i] == '(') continue; if (buf[i] == ')') { j = 0; - readModes = false; + read_modes = false; continue; } - if (readModes) + if (read_modes) table[j++].first = buf[i]; else table[j++].second = buf[i]; } - // Put these as a map of mode to prefix + /* Put these as a map of mode to prefix */ for (int i = 0; i < 16; ++i) { auto key = static_cast<ServerChanMode>(table[i].first); auto value = table[i].second; - m_info.modes.emplace(key, value); + modes.emplace(key, value); } + + return modes; } -std::string Server::cleanPrefix(std::string nickname) const noexcept -{ - if (nickname.length() > 0) - for (const auto &pair : m_info.modes) - if (nickname[0] == pair.second) - nickname.erase(0, 1); - - return nickname; -} +} // !namespace void Server::handleConnect(const char *, const char **) noexcept { /* Reset the number of tried reconnection. */ - m_settings.recocurrent = 0; + m_cache.reconnect_current = 0; /* Reset the timer. */ - m_ping_timer.reset(); + m_cache.ping_timer.reset(); /* Don't forget to change state and notify. */ next(std::make_unique<state::Connected>()); @@ -193,7 +218,7 @@ /* The listing may add some prefixes, remove them if needed */ for (std::string u : users) - m_namesMap[params[2]].insert(cleanPrefix(u)); + m_cache.names_map[params[2]].insert(cleanPrefix(m_info, u)); } else if (event == LIBIRC_RFC_RPL_ENDOFNAMES) { /* * Called when end of name listing has finished on a channel. @@ -206,12 +231,12 @@ if (c < 3 || params[1] == nullptr) return; - auto it = m_namesMap.find(params[1]); - if (it != m_namesMap.end()) { + auto it = m_cache.names_map.find(params[1]); + if (it != m_cache.names_map.end()) { onNames(params[1], it->second); /* Don't forget to remove the list */ - m_namesMap.erase(it); + m_cache.names_map.erase(it); } } else if (event == LIBIRC_RFC_RPL_WHOISUSER) { /* @@ -234,7 +259,7 @@ info.host = strify(params[3]); info.realname = strify(params[5]); - m_whoisMap.emplace(info.nick, info); + m_cache.whois_map.emplace(info.nick, info); } else if (event == LIBIRC_RFC_RPL_WHOISCHANNELS) { /* * Called when we have received channels for one user. @@ -246,13 +271,13 @@ if (c < 3 || !params[1] || !params[2]) return; - auto it = m_whoisMap.find(params[1]); - if (it != m_whoisMap.end()) { + auto it = m_cache.whois_map.find(params[1]); + if (it != m_cache.whois_map.end()) { std::vector<std::string> channels = util::split(params[2], " \t"); /* Clean their prefixes */ for (auto &s : channels) - s = cleanPrefix(s); + s = cleanPrefix(m_info, s); /* Insert */ it->second.channels = std::move(channels); @@ -266,12 +291,12 @@ * params[2] == End of WHOIS list */ - auto it = m_whoisMap.find(params[1]); - if (it != m_whoisMap.end()) { + auto it = m_cache.whois_map.find(params[1]); + if (it != m_cache.whois_map.end()) { onWhois(it->second); /* Don't forget to remove */ - m_whoisMap.erase(it); + m_cache.whois_map.erase(it); } } else if (event == /* RPL_BOUNCE */ 5) { /* @@ -279,7 +304,7 @@ */ for (unsigned int i = 0; i < c; ++i) { if (strncmp(params[i], "PREFIX", 6) == 0) { - extractPrefixes(params[i]); + m_info.modes = extractPrefixes(params[i]); break; } } @@ -294,7 +319,7 @@ void Server::handlePing(const char *, const char **params) noexcept { /* Reset the timer to detect disconnection. */ - m_ping_timer.reset(); + m_cache.ping_timer.reset(); /* Don't forget to respond */ send(params[0]); @@ -448,6 +473,15 @@ irc_process_select_descriptors(*m_session, &setinput, &setoutput); } +bool Server::isSelf(const std::string &nick) const noexcept +{ + char target[32]{0}; + + irc_target_get_nick(nick.c_str(), target, sizeof (target)); + + return m_identity.nickname == target; +} + void Server::cmode(std::string channel, std::string mode) { m_queue.push([=] () { @@ -455,21 +489,21 @@ }); } -void Server::cnotice(std::string channel, std::string message) noexcept +void Server::cnotice(std::string channel, std::string message) { m_queue.push([=] () { return irc_cmd_notice(*m_session, channel.c_str(), message.c_str()) == 0; }); } -void Server::invite(std::string target, std::string channel) noexcept +void Server::invite(std::string target, std::string channel) { m_queue.push([=] () { return irc_cmd_invite(*m_session, target.c_str(), channel.c_str()) == 0; }); } -void Server::join(std::string channel, std::string password) noexcept +void Server::join(std::string channel, std::string password) { m_queue.push([=] () { const char *ptr = password.empty() ? nullptr : password.c_str(); @@ -478,7 +512,7 @@ }); } -void Server::kick(std::string target, std::string channel, std::string reason) noexcept +void Server::kick(std::string target, std::string channel, std::string reason) { m_queue.push([=] () { return irc_cmd_kick(*m_session, target.c_str(), channel.c_str(), reason.c_str()) == 0;
--- a/lib/irccd/server.hpp Tue Apr 26 13:19:35 2016 +0200 +++ b/lib/irccd/server.hpp Tue Apr 26 19:31:42 2016 +0200 @@ -136,14 +136,36 @@ ServerChannels channels; //!< List of channel to join std::string command{"!"}; //!< The command character to trigger plugin command - std::int8_t recotries{-1}; //!< Number of tries to reconnect before giving up - std::uint16_t recotimeout{30}; //!< Number of seconds to wait before trying to connect + std::int8_t reconnect_tries{-1}; //!< Number of tries to reconnect before giving up + std::uint16_t reconnect_timeout{30}; //!< Number of seconds to wait before trying to connect std::uint8_t flags{0}; //!< Optional flags + std::uint16_t ping_timeout{300}; //!< Time in seconds before ping timeout is announced +}; - std::uint16_t ping_timeout{300}; //!< Ping timeout in milliseconds +/** + * \brief Some variables that are needed in many places internally. + */ +class ServerCache { +public: + /** + * Track elapsed time for ping timeout. + */ + ElapsedTimer ping_timer; - /* Private */ - std::int8_t recocurrent{1}; //!< number of tries tested + /** + * Number of reconnection already tested. + */ + std::int8_t reconnect_current{1}; + + /** + * Map of names being build by channels. + */ + std::map<std::string, std::set<std::string>> names_map; + + /** + * Map of whois being build by nicknames. + */ + std::map<std::string, ServerWhois> whois_map; }; /** @@ -387,20 +409,11 @@ using SessionPtr = std::unique_ptr<Session>; using Queue = std::queue<ServerCommand>; - /** - * List of NAMES being built. - */ - using NamesMap = std::unordered_map<std::string, std::set<std::string>>; - - /** - * List of WHOIS being built. - */ - using WhoisMap = std::unordered_map<std::string, ServerWhois>; - private: ServerInfo m_info; ServerSettings m_settings; ServerIdentity m_identity; + ServerCache m_cache; SessionPtr m_session; Queue m_queue; @@ -408,28 +421,6 @@ std::unique_ptr<ServerState> m_state; std::unique_ptr<ServerState> m_state_next; - /* - * Detect timeout from server. - */ - ElapsedTimer m_ping_timer; - - /* - * The names map is being built by a successive call to handleNumeric so we need to store a temporary - * map by channels to list of names. Then, when we receive the end of names listing, we remove the - * temporary set of names and calls the appropriate signal. - */ - NamesMap m_namesMap; - WhoisMap m_whoisMap; - - bool isSelf(const std::string &nick) const noexcept; - void extractPrefixes(const std::string &line); - std::string cleanPrefix(std::string nickname) const noexcept; - - inline std::string strify(const char *s) - { - return (s == nullptr) ? "" : std::string(s); - } - void handleChannel(const char *, const char **) noexcept; void handleChannelMode(const char *, const char **) noexcept; void handleChannelNotice(const char *, const char **) noexcept; @@ -475,22 +466,12 @@ * * \param state the new state */ - inline void next(std::unique_ptr<ServerState> state) + inline void next(std::unique_ptr<ServerState> state) noexcept { m_state_next = std::move(state); } /** - * Get the ping timer. - * - * \return the ping timer - */ - inline ElapsedTimer &pingTimer() noexcept - { - return m_ping_timer; - } - - /** * Switch to next state if it has. * * If the server is installed into irccd, it is called automatically. @@ -573,6 +554,17 @@ } /** + * Access the cache. + * + * \return the cache + * \warning use with care + */ + inline ServerCache &cache() noexcept + { + return m_cache; + } + + /** * Get the server settings. * * \warning This overload should not be used by the user, it is required to @@ -625,6 +617,14 @@ } /** + * Determine if the nickname is the bot itself. + * + * \param nick the nickname to check + * \return true if it is the bot + */ + bool isSelf(const std::string &nick) const noexcept; + + /** * Change the channel mode. * * \param channel the channel @@ -640,7 +640,7 @@ * \param message message notice * \note Thread-safe */ - void cnotice(std::string channel, std::string message) noexcept; + void cnotice(std::string channel, std::string message); /** * Invite a user to a channel. @@ -649,7 +649,7 @@ * \param channel the channel * \note Thread-safe */ - void invite(std::string target, std::string channel) noexcept; + void invite(std::string target, std::string channel); /** * Join a channel, the password is optional and can be kept empty. @@ -658,7 +658,7 @@ * \param password the optional password * \note Thread-safe */ - void join(std::string channel, std::string password = "") noexcept; + void join(std::string channel, std::string password = ""); /** * Kick someone from the channel. Please be sure to have the rights @@ -669,7 +669,7 @@ * \param reason the optional reason * \note Thread-safe */ - void kick(std::string target, std::string channel, std::string reason = "") noexcept; + void kick(std::string target, std::string channel, std::string reason = ""); /** * Send a CTCP Action as known as /me. The target may be either a