From 4196f1be3a13ae7e507497da449a995bc5a48d5c Mon Sep 17 00:00:00 2001 From: lotodore Date: Sat, 8 Dec 2007 00:40:46 +0000 Subject: [PATCH] Very graceful auto-reconnect for the server irc bot. Will give up after two attempts within 60 seconds. --- src/net/common/ircthread.cpp | 166 ++++++++++++++++++++--------------- src/net/ircthread.h | 3 + 2 files changed, 99 insertions(+), 70 deletions(-) diff --git a/src/net/common/ircthread.cpp b/src/net/common/ircthread.cpp index 8ae76310..d18a08ff 100644 --- a/src/net/common/ircthread.cpp +++ b/src/net/common/ircthread.cpp @@ -29,11 +29,12 @@ using namespace std; -#define IRC_WAIT_TERMINATION_MSEC 500 -#define IRC_MAX_RENAME_TRIES 5 +#define IRC_WAIT_TERMINATION_MSEC 500 +#define IRC_MAX_RENAME_TRIES 5 +#define IRC_MIN_RECONNECT_INTERVAL_SEC 60 -#define IRC_RENAME_ATTACH "|Lobby" -#define IRC_MAX_NICK_LEN 16 +#define IRC_RENAME_ATTACH "|Lobby" +#define IRC_MAX_NICK_LEN 16 struct IrcContext @@ -252,7 +253,9 @@ irc_event_numeric(irc_session_t * session, unsigned irc_event, const char * /*or } IrcThread::IrcThread(IrcCallback &callback) -: m_callback(callback), m_terminationTimer(boost::posix_time::time_duration(0, 0, 0), boost::timers::portable::microsec_timer::manual_start) +: m_callback(callback), + m_terminationTimer(boost::posix_time::time_duration(0, 0, 0), boost::timers::portable::microsec_timer::manual_start), + m_lastConnectTimer(boost::posix_time::time_duration(0, 0, 0), boost::timers::portable::microsec_timer::manual_start) { m_context.reset(new IrcContext(*this)); } @@ -278,7 +281,43 @@ IrcThread::Init(const std::string &serverAddress, unsigned serverPort, bool ipv6 context.nick = nick; context.channel = channel; context.channelPassword = channelPassword; +} +void +IrcThread::SendChatMessage(const std::string &msg) +{ + IrcContext &context = GetContext(); + irc_cmd_msg(context.session, context.channel.c_str(), msg.c_str()); +} + +void +IrcThread::SignalTermination() +{ + Thread::SignalTermination(); + irc_cmd_quit(GetContext().session, NULL); +} + +void +IrcThread::Main() +{ + do + { + if (IrcInit()) + IrcMain(); // Will loop until terminated. + } while (!ShouldTerminate() && GetContext().session && !irc_is_connected(GetContext().session) && m_lastConnectTimer.elapsed().total_seconds() > IRC_MIN_RECONNECT_INTERVAL_SEC); +} + +bool +IrcThread::IrcInit() +{ + bool retVal = false; + + IrcContext &context = GetContext(); + if (context.session) + { + irc_destroy_session(context.session); + context.session = NULL; + } // Initialize libirc stuff. irc_callbacks_t callbacks; memset (&callbacks, 0, sizeof(callbacks)); @@ -311,86 +350,73 @@ IrcThread::Init(const std::string &serverAddress, unsigned serverPort, bool ipv6 irc_set_ctx(context.session, &context); // We want nicknames only, strip them from nick!host. irc_option_set(context.session, LIBIRC_OPTION_STRIPNICKS); + retVal = true; } + return retVal; } void -IrcThread::SendChatMessage(const std::string &msg) -{ - IrcContext &context = GetContext(); - irc_cmd_msg(context.session, context.channel.c_str(), msg.c_str()); -} - -void -IrcThread::SignalTermination() -{ - Thread::SignalTermination(); - irc_cmd_quit(GetContext().session, NULL); -} - -void -IrcThread::Main() +IrcThread::IrcMain() { + m_lastConnectTimer.restart(); IrcContext &context = GetContext(); irc_session_t *s = context.session; - if (s) + + bool connected = false; + if (context.useIPv6) + connected = irc_connect6(s, context.serverAddress.c_str(), context.serverPort, 0, context.nick.c_str(), 0, 0) == 0; + else + connected = irc_connect(s, context.serverAddress.c_str(), context.serverPort, 0, context.nick.c_str(), 0, 0) == 0; + + if (!connected) + HandleIrcError(irc_errno(s)); + else { - bool connected = false; - if (context.useIPv6) - connected = irc_connect6(s, context.serverAddress.c_str(), context.serverPort, 0, context.nick.c_str(), 0, 0) == 0; - else - connected = irc_connect(s, context.serverAddress.c_str(), context.serverPort, 0, context.nick.c_str(), 0, 0) == 0; - - if (!connected) - HandleIrcError(irc_errno(s)); - else + // Main loop. + while (irc_is_connected(s)) { - // Main loop. - while (irc_is_connected(s)) + // Handle thread termination - gracefully. + if (!m_terminationTimer.is_running()) { - // Handle thread termination - gracefully. - if (!m_terminationTimer.is_running()) + if (ShouldTerminate()) + m_terminationTimer.start(); + } + else + { + if (m_terminationTimer.elapsed().total_milliseconds() > IRC_WAIT_TERMINATION_MSEC) + break; + } + + struct timeval timeout; + fd_set readSet, writeSet; + int maxfd = 0; + + + FD_ZERO(&readSet); + FD_ZERO(&writeSet); + timeout.tv_sec = 0; + timeout.tv_usec = RECV_TIMEOUT_MSEC * 1000; + + irc_add_select_descriptors(s, &readSet, &writeSet, &maxfd); + + int selectResult = select(maxfd + 1, &readSet, &writeSet, 0, &timeout); + if (!IS_VALID_SELECT(selectResult)) + { + GetCallback().SignalIrcError(ERR_IRC_SELECT_FAILED); + break; + } + + if (irc_process_select_descriptors(s, &readSet, &writeSet) != 0) + { + int errorCode = irc_errno(s); + if (errorCode) { - if (ShouldTerminate()) - m_terminationTimer.start(); - } - else - { - if (m_terminationTimer.elapsed().total_milliseconds() > IRC_WAIT_TERMINATION_MSEC) - break; - } - - struct timeval timeout; - fd_set readSet, writeSet; - int maxfd = 0; - - - FD_ZERO(&readSet); - FD_ZERO(&writeSet); - timeout.tv_sec = 0; - timeout.tv_usec = RECV_TIMEOUT_MSEC * 1000; - - irc_add_select_descriptors(s, &readSet, &writeSet, &maxfd); - - int selectResult = select(maxfd + 1, &readSet, &writeSet, 0, &timeout); - if (!IS_VALID_SELECT(selectResult)) - { - GetCallback().SignalIrcError(ERR_IRC_SELECT_FAILED); + HandleIrcError(errorCode); break; } - - if (irc_process_select_descriptors(s, &readSet, &writeSet) != 0) - { - int errorCode = irc_errno(s); - if (errorCode) - { - HandleIrcError(errorCode); - break; - } - } - Msleep(10); // paranoia } + Msleep(10); // paranoia } } } diff --git a/src/net/ircthread.h b/src/net/ircthread.h index d9290876..6cb2845c 100644 --- a/src/net/ircthread.h +++ b/src/net/ircthread.h @@ -48,6 +48,8 @@ protected: // Main function of the thread. virtual void Main(); + bool IrcInit(); + void IrcMain(); void HandleIrcError(int errorCode); @@ -59,6 +61,7 @@ private: IrcCallback &m_callback; boost::timers::portable::microsec_timer m_terminationTimer; + boost::timers::portable::microsec_timer m_lastConnectTimer; }; #endif