From a50ca30e769a628f609f8cc0eedf5bc10b3f1b5a Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 21 Feb 2015 06:39:20 +0100 Subject: [PATCH] Use a timer to try reconnecting to the XMPP server only each 2 seconds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the connection is lost, immediately try to reconnect, then try to reconnect every 2 seconds. This is much better than the previous “Try to re-connect as fast as possible”. --- CHANGELOG | 2 ++ src/main.cpp | 23 +++++++++++++++++++++-- src/network/poller.cpp | 3 ++- src/network/tcp_socket_handler.cpp | 5 ++++- src/xmpp/xmpp_component.cpp | 3 +++ src/xmpp/xmpp_component.hpp | 6 ++++++ 6 files changed, 38 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9e907b0..872eb4d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,8 @@ Version 2.0 - Setting a participant's role/affiliation now results in a change of IRC mode, instead of being ignored. Setting Toto's affiliation to admin is now equivalent to “/mode +o Toto” + - Fix the reconnection to the XMPP server to try every 2 seconds + instead of immediately. This avoid hogging resources for nothing Version 1.1 2014-16-07 diff --git a/src/main.cpp b/src/main.cpp index 393bf05..a67baf9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -108,6 +108,8 @@ int main(int ac, char** av) exiting = true; stop.store(false); xmpp_component->shutdown(); + // Cancel the timer for an potential reconnection + TimedEventsManager::instance().cancel("XMPP reconnection"); } if (reload) { @@ -127,17 +129,34 @@ int main(int ac, char** av) if (!exiting && xmpp_component->ever_auth && !xmpp_component->is_connected() && !xmpp_component->is_connecting()) - { + { + if (xmpp_component->first_connection_try == true) + { // immediately re-try to connect xmpp_component->reset(); xmpp_component->start(); } + else + { // Re-connecting failed, we now try only each few seconds + auto reconnect_later = [xmpp_component]() + { + xmpp_component->reset(); + xmpp_component->start(); + }; + TimedEvent event(std::chrono::steady_clock::now() + 2s, + reconnect_later, "XMPP reconnection"); + TimedEventsManager::instance().add_event(std::move(event)); + } + } // If the only existing connection is the one to the XMPP component: // close the XMPP stream. if (exiting && xmpp_component->is_connecting()) xmpp_component->close(); if (exiting && p->size() == 1 && xmpp_component->is_document_open()) xmpp_component->close_document(); - timeout = TimedEventsManager::instance().get_timeout(); + if (exiting) // If we are exiting, do not wait for any timed event + timeout = utils::no_timeout; + else + timeout = TimedEventsManager::instance().get_timeout(); } log_info("All connections cleanly closed, have a nice day."); return 0; diff --git a/src/network/poller.cpp b/src/network/poller.cpp index 29c4bce..ffc4f2d 100644 --- a/src/network/poller.cpp +++ b/src/network/poller.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -133,7 +134,7 @@ void Poller::stop_watching_send_events(SocketHandler* socket_handler) int Poller::poll(const std::chrono::milliseconds& timeout) { - if (this->socket_handlers.empty()) + if (this->socket_handlers.empty() && timeout == utils::no_timeout) return -1; #if POLLER == POLL int nb_events = ::poll(this->fds, this->nfds, timeout.count()); diff --git a/src/network/tcp_socket_handler.cpp b/src/network/tcp_socket_handler.cpp index c5d254e..1d1eaa7 100644 --- a/src/network/tcp_socket_handler.cpp +++ b/src/network/tcp_socket_handler.cpp @@ -213,8 +213,11 @@ ssize_t TCPSocketHandler::do_recv(void* recv_buf, const size_t buf_size) else if (-1 == size) { log_warning("Error while reading from socket: " << strerror(errno)); + // Remember if we were connecting, or already connected when this + // happened, because close() sets this->connecting to false + const auto were_connecting = this->connecting; this->close(); - if (this->connecting) + if (were_connecting) this->on_connection_failed(strerror(errno)); else this->on_connection_close(strerror(errno)); diff --git a/src/xmpp/xmpp_component.cpp b/src/xmpp/xmpp_component.cpp index 1335326..841ead4 100644 --- a/src/xmpp/xmpp_component.cpp +++ b/src/xmpp/xmpp_component.cpp @@ -39,6 +39,7 @@ static std::set kickable_errors{ XmppComponent::XmppComponent(std::shared_ptr poller, const std::string& hostname, const std::string& secret): TCPSocketHandler(poller), ever_auth(false), + first_connection_try(true), served_hostname(hostname), secret(secret), authenticated(false), @@ -86,6 +87,7 @@ void XmppComponent::send_stanza(const Stanza& stanza) void XmppComponent::on_connection_failed(const std::string& reason) { + this->first_connection_try = false; log_error("Failed to connect to the XMPP server: " << reason); #ifdef SYSTEMDDAEMON_FOUND sd_notifyf(0, "STATUS=Failed to connect to the XMPP server: %s", reason.data()); @@ -95,6 +97,7 @@ void XmppComponent::on_connection_failed(const std::string& reason) void XmppComponent::on_connected() { log_info("connected to XMPP server"); + this->first_connection_try = true; XmlNode node("", nullptr); node.set_name("stream:stream"); node["xmlns"] = COMPONENT_NS; diff --git a/src/xmpp/xmpp_component.hpp b/src/xmpp/xmpp_component.hpp index 64b2ff7..951d5a3 100644 --- a/src/xmpp/xmpp_component.hpp +++ b/src/xmpp/xmpp_component.hpp @@ -241,6 +241,12 @@ public: * Whether or not we ever succeeded our authentication to the XMPP server */ bool ever_auth; + /** + * Whether or not this is the first consecutive try on connecting to the + * XMPP server. We use this to delay the connection attempt for a few + * seconds, if it is not the first try. + */ + bool first_connection_try; private: /** -- 2.45.2