From a213258c99808b91b7a50476a94fda5a6bc99bdf Mon Sep 17 00:00:00 2001 From: psychon Date: Sat, 3 Nov 2007 20:04:24 +0000 Subject: [PATCH] Move code for creating CIRCSocks into a CCron and use DynamicSelectLoop DynamicSelectLoop checks when the next cron runs and sleeps until then (with an upper and lower border). To fix the connecting code it needed to be moved into a cron. git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@860 726aef4b-f618-498e-8847-2d620e286838 --- User.cpp | 3 + znc.cpp | 195 ++++++++++++++++++++++++++++++++++++------------------- znc.h | 12 +++- 3 files changed, 141 insertions(+), 69 deletions(-) diff --git a/User.cpp b/User.cpp index f043ac87..629096f0 100644 --- a/User.cpp +++ b/User.cpp @@ -118,6 +118,9 @@ void CUser::IRCDisconnected() { for (unsigned int a = 0; a < m_vClients.size(); a++) { m_vClients[a]->IRCDisconnected(); } + + // Get the reconnect going + CZNC::Get().EnableConnectUser(); } CString CUser::ExpandString(const CString& sStr) const { diff --git a/znc.cpp b/znc.cpp index 3ee61d53..ee55d512 100644 --- a/znc.cpp +++ b/znc.cpp @@ -30,6 +30,7 @@ CZNC::CZNC() { SetISpoofFormat(""); // Set ISpoofFormat to default m_uBytesRead = 0; m_uBytesWritten = 0; + m_pConnectUserTimer = NULL; } CZNC::~CZNC() { @@ -52,6 +53,7 @@ CZNC::~CZNC() { a->second->SetBeingDeleted(true); } + // This deletes m_pConnectUserTimer m_Manager.Cleanup(); DeleteUsers(); @@ -88,10 +90,55 @@ bool CZNC::OnBoot() { return true; } +bool CZNC::ConnectUser(CUser *pUser) { + CString sSockName = "IRC::" + pUser->GetUserName(); + CIRCSock* pIRCSock = (CIRCSock*) m_Manager.FindSockByName(sSockName); + + if (m_pISpoofLockFile != NULL) { + return false; + } + + + if (pIRCSock || !pUser->HasServers()) + return false; + + if (pUser->ConnectPaused()) + return false; + + CServer* pServer = pUser->GetNextServer(); + + if (!pServer) + return false; + + if (!WriteISpoof(pUser)) { + DEBUG_ONLY(cout << "ISpoof could not be written" << endl); + pUser->PutStatus("ISpoof could not be written, retrying..."); + return true; + } + + DEBUG_ONLY(cout << "User [" << pUser->GetUserName() << "] is connecting to [" << pServer->GetName() << ":" << pServer->GetPort() << "] ..." << endl); + pUser->PutStatus("Attempting to connect to [" + pServer->GetName() + ":" + CString(pServer->GetPort()) + "] ..."); + + pIRCSock = new CIRCSock(pUser); + pIRCSock->SetPass(pServer->GetPass()); + + bool bSSL = false; +#ifdef HAVE_LIBSSL + if (pServer->IsSSL()) { + bSSL = true; + } +#endif + + if (!m_Manager.Connect(pServer->GetName(), pServer->GetPort(), sSockName, 20, bSSL, pUser->GetVHost(), pIRCSock)) { + ReleaseISpoof(); + pUser->PutStatus("Unable to connect. (Bad host?)"); + } + + return true; +} + int CZNC::Loop() { - m_Manager.SetSelectTimeout(500000); - m_itUserIter = m_msUsers.begin(); - time_t tNextConnect = 0; + EnableConnectUser(); while (true) { // Check for users that need to be deleted @@ -124,73 +171,13 @@ int CZNC::Loop() { } m_ssDelUsers.clear(); - m_itUserIter = m_msUsers.begin(); + RestartConnectUser(); WriteConfig(); } - m_Manager.Loop(); - - if (m_pISpoofLockFile != NULL) { - continue; - } - - if (m_itUserIter == m_msUsers.end()) { - m_itUserIter = m_msUsers.begin(); - } - - if (m_msUsers.empty()) { - usleep(10000); - continue; - } - - if (tNextConnect > time(NULL)) { - continue; - } - - CString sSockName = "IRC::" + m_itUserIter->first; - CUser* pUser = m_itUserIter->second; - - m_itUserIter++; - - CIRCSock* pIRCSock = (CIRCSock*) m_Manager.FindSockByName(sSockName); - - if (!pIRCSock && pUser->HasServers()) { - if (pUser->ConnectPaused() && pUser->IsLastServer()) { - continue; - } - - CServer* pServer = pUser->GetNextServer(); - - if (!pServer) { - continue; - } - - tNextConnect = time(NULL) + m_uiConnectDelay; - - if(!WriteISpoof(pUser)) { - DEBUG_ONLY(cout << "ISpoof could not be written" << endl); - pUser->PutStatus("ISpoof could not be written, retrying..."); - continue; - } - - DEBUG_ONLY(cout << "User [" << pUser->GetUserName() << "] is connecting to [" << pServer->GetName() << ":" << pServer->GetPort() << "] ..." << endl); - pUser->PutStatus("Attempting to connect to [" + pServer->GetName() + ":" + CString(pServer->GetPort()) + "] ..."); - - pIRCSock = new CIRCSock(pUser); - pIRCSock->SetPass(pServer->GetPass()); - - bool bSSL = false; -#ifdef HAVE_LIBSSL - if (pServer->IsSSL()) { - bSSL = true; - } -#endif - - if (!m_Manager.Connect(pServer->GetName(), pServer->GetPort(), sSockName, 20, bSSL, pUser->GetVHost(), pIRCSock)) { - ReleaseISpoof(); - pUser->PutStatus("Unable to connect. (Bad host?)"); - } - } + // Csocket wants micro seconds + // between 5 to 600 secs + m_Manager.DynamicSelectLoop(5 * 1000 * 1000, 600 * 1000 * 1000); } return 0; @@ -314,7 +301,7 @@ void CZNC::DeleteUsers() { } m_msUsers.clear(); - m_itUserIter = m_msUsers.begin(); + RestartConnectUser(); } CUser* CZNC::GetUser(const CString& sUser) { @@ -1345,3 +1332,75 @@ void CZNC::UpdateTrafficStats() { } } +class CConnectUserTimer : public CCron { +public: + CConnectUserTimer(int iSecs) : CCron() { + SetName("Connect users"); + Start(iSecs); + m_itUserIter = CZNC::Get().GetUserMap().begin(); + } + virtual ~CConnectUserTimer() {} + +protected: + virtual void RunJob() { + CUser *pStartedUser; + map::const_iterator end; + bool bUserWithoutIRC = false; + + pStartedUser = m_itUserIter->second; + end = CZNC::Get().GetUserMap().end(); + + // Try to connect each user, if this doesnt work, abort + do { + if (m_itUserIter == end) { + m_itUserIter = CZNC::Get().GetUserMap().begin(); + } + + CUser* pUser = m_itUserIter->second; + + m_itUserIter++; + + if (pUser->GetIRCSock() == NULL) + bUserWithoutIRC = true; + + if (CZNC::Get().ConnectUser(pUser)) + return; + } while (pStartedUser != m_itUserIter->second); + + if (bUserWithoutIRC == false) + CZNC::Get().DisableConnectUser(); + } + +private: + map::const_iterator m_itUserIter; +}; + +void CZNC::EnableConnectUser() { + if (m_pConnectUserTimer != NULL) + return; + + m_pConnectUserTimer = new CConnectUserTimer(m_uiConnectDelay); + GetManager().AddCron(m_pConnectUserTimer); +} + +void CZNC::DisableConnectUser() { + if (m_pConnectUserTimer == NULL) + return; + + // This will kill the cron + m_pConnectUserTimer->Stop(); + m_pConnectUserTimer = NULL; +} + +void CZNC::RestartConnectUser() { + DisableConnectUser(); + + map::iterator end = m_msUsers.end(); + for (map::iterator it = m_msUsers.begin(); it != end; it++) { + // If there is a user without irc socket we need the timer + if (it->second->GetIRCSock() == NULL) { + EnableConnectUser(); + return; + } + } +} diff --git a/znc.h b/znc.h index 980d26e4..bac29593 100644 --- a/znc.h +++ b/znc.h @@ -87,6 +87,8 @@ private: protected: }; +class CConnectUserTimer; + class CZNC { public: CZNC(); @@ -160,6 +162,14 @@ public: const VCString& GetMotd() const { return m_vsMotd; } // !MOTD + // Create a CIRCSocket. Return false if user cant connect + bool ConnectUser(CUser *pUser); + // This creates a CConnectUserTimer if we haven't got one yet + void EnableConnectUser(); + void DisableConnectUser(); + // This needs to be called if anything was added / removed to m_msUsers + void RestartConnectUser(); + private: protected: vector m_vpListeners; @@ -185,13 +195,13 @@ protected: VCString m_vsMotd; CLockFile m_LockFile; CLockFile* m_pISpoofLockFile; - map::iterator m_itUserIter; // This needs to be reset to m_msUsers.begin() if anything is added or removed to the map uint m_uiConnectDelay; #ifdef _MODULES CGlobalModules* m_pModules; #endif unsigned long long m_uBytesRead; unsigned long long m_uBytesWritten; + CConnectUserTimer *m_pConnectUserTimer; }; class CListener {