From b359f968868807173d2b0607f22a5e4a4ba2a175 Mon Sep 17 00:00:00 2001 From: psychon Date: Sat, 6 Nov 2010 15:21:59 +0000 Subject: [PATCH] Avoid a possibly expensive FindSockByName() for finding IRC socks While a user is connecting to an IRC server, the CUser instance didn't know about the CIRCSock instance (due to historic reasons). This meant that we needed to use FindSockByName() when we had to check if there is any CIRCSock associated with this user. However, this is a bad idea since FindSockByName() is O(n) on the number of sockets that the socket manager is managing. Instead, we now already set CUser::m_pIRCSock when the CIRCSock is created so that checking for an irc socket becomes O(1). This was inspired by the results of profiling a znc instance with 900 users. git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@2171 726aef4b-f618-498e-8847-2d620e286838 --- ClientCommand.cpp | 19 +++++-------------- IRCSock.cpp | 7 ++++++- Nick.cpp | 10 +++++++--- User.cpp | 15 ++++++++++++++- User.h | 4 ++-- znc.cpp | 12 ++---------- znc.h | 1 - 7 files changed, 36 insertions(+), 32 deletions(-) diff --git a/ClientCommand.cpp b/ClientCommand.cpp index 7f35d951..67de9a0a 100644 --- a/ClientCommand.cpp +++ b/ClientCommand.cpp @@ -245,13 +245,11 @@ void CClient::UserCommand(CString& sLine) { } m_pUser->SetNextServer(pServer); - if (!GetIRCSock()) { - // If we are already connecting to some server, - // we have to abort that attempt - Csock *pIRCSock = CZNC::Get().GetManager() - .FindSockByName("IRC::" + m_pUser->GetUserName()); - if (pIRCSock) - pIRCSock->Close(); + // If we are already connecting to some server, + // we have to abort that attempt + Csock *pIRCSock = GetIRCSock(); + if (pIRCSock && !pIRCSock->IsConnected()) { + pIRCSock->Close(); } } @@ -278,13 +276,6 @@ void CClient::UserCommand(CString& sLine) { if (GetIRCSock()) { CString sQuitMsg = sLine.Token(1, true); GetIRCSock()->Quit(sQuitMsg); - } else { - Csock* pIRCSock; - CString sSockName = "IRC::" + m_pUser->GetUserName(); - // This is *slow*, we try to avoid doing this - pIRCSock = CZNC::Get().GetManager().FindSockByName(sSockName); - if (pIRCSock) - pIRCSock->Close(); } m_pUser->SetIRCConnectEnabled(false); diff --git a/IRCSock.cpp b/IRCSock.cpp index c71fcc37..2380c7d3 100644 --- a/IRCSock.cpp +++ b/IRCSock.cpp @@ -38,6 +38,8 @@ CIRCSock::CIRCSock(CUser* pUser) : CZNCSock() { m_mueChanModes['i'] = NoArg; m_mueChanModes['n'] = NoArg; + pUser->SetIRCSocket(this); + // RFC says a line can have 512 chars max, but we don't care ;) SetMaxBufferThreshold(1024); } @@ -65,6 +67,10 @@ CIRCSock::~CIRCSock() { } void CIRCSock::Quit(const CString& sQuitMsg) { + if (!m_bAuthed) { + Close(CLT_NOW); + return; + } CString sMsg = (!sQuitMsg.empty()) ? sQuitMsg : m_pUser->GetQuitMsg(); PutIRC("QUIT :" + sMsg); Close(CLT_AFTERWRITE); @@ -920,7 +926,6 @@ void CIRCSock::SetNick(const CString& sNick) { void CIRCSock::Connected() { DEBUG(GetSockName() << " == Connected()"); - m_pUser->IRCConnected(this); CString sPass = m_sPass; CString sNick = m_pUser->GetNick(); diff --git a/Nick.cpp b/Nick.cpp index c4aefdd7..16823d21 100644 --- a/Nick.cpp +++ b/Nick.cpp @@ -131,11 +131,15 @@ const CString& CNick::GetNick() const { return m_sNick; } const CString& CNick::GetIdent() const { return m_sIdent; } const CString& CNick::GetHost() const { return m_sHost; } CString CNick::GetNickMask() const { - if (m_sNick.find('.') != CString::npos) { - return m_sNick; + CString sRet = m_sNick; + + if (!m_sHost.empty()) { + if (!m_sIdent.empty()) + sRet += "!" + m_sIdent; + sRet += "@" + m_sHost; } - return (m_sNick + "!" + m_sIdent + "@" + m_sHost); + return sRet; } CString CNick::GetHostMask() const { diff --git a/User.cpp b/User.cpp index 3384816b..87261405 100644 --- a/User.cpp +++ b/User.cpp @@ -157,10 +157,23 @@ void CUser::DelServers() m_vServers.clear(); } -void CUser::IRCConnected(CIRCSock* pIRCSock) { +void CUser::SetIRCSocket(CIRCSock* pIRCSock) { m_pIRCSock = pIRCSock; } +bool CUser::IsIRCConnected() const +{ + const CIRCSock* pSock = GetIRCSock(); + + if (!pSock) + return false; + + if (!pSock->IsConnected()) + return false; + + return true; +} + void CUser::IRCDisconnected() { m_pIRCSock = NULL; diff --git a/User.h b/User.h index 558fbad2..286451ea 100644 --- a/User.h +++ b/User.h @@ -109,8 +109,8 @@ public: CString GetLocalIP(); CString GetLocalDCCIP(); - bool IsIRCConnected() const { return GetIRCSock() != NULL; } - void IRCConnected(CIRCSock* pIRCSock); + bool IsIRCConnected() const; + void SetIRCSocket(CIRCSock* pIRCSock); void IRCDisconnected(); void CheckIRCConnect(); diff --git a/znc.cpp b/znc.cpp index 44e86419..d03f9cf9 100644 --- a/znc.cpp +++ b/znc.cpp @@ -111,9 +111,7 @@ bool CZNC::OnBoot() { bool CZNC::ConnectUser(CUser *pUser) { CString sSockName = "IRC::" + pUser->GetUserName(); - // Don't use pUser->GetIRCSock(), as that only returns something if the - // CIRCSock is already connected, not when it's still connecting! - CIRCSock* pIRCSock = (CIRCSock*) m_Manager.FindSockByName(sSockName); + CIRCSock* pIRCSock = pUser->GetIRCSock(); if (m_pISpoofLockFile != NULL) { return false; @@ -192,9 +190,7 @@ bool CZNC::HandleUserDeletion() } m_msUsers.erase(pUser->GetUserName()); - // Don't use pUser->GetIRCSock(), as that only returns something if the - // CIRCSock is already connected, not when it's still connecting! - CIRCSock* pIRCSock = (CIRCSock*) m_Manager.FindSockByName("IRC::" + pUser->GetUserName()); + CIRCSock* pIRCSock = pUser->GetIRCSock(); if (pIRCSock) { m_Manager.DelSockByAddr(pIRCSock); @@ -401,10 +397,6 @@ void CZNC::DeleteUsers() { DisableConnectUser(); } -Csock* CZNC::FindSockByName(const CString& sSockName) { - return m_Manager.FindSockByName(sSockName); -} - bool CZNC::IsHostAllowed(const CString& sHostMask) const { for (map::const_iterator a = m_msUsers.begin(); a != m_msUsers.end(); ++a) { if (a->second->IsHostAllowed(sHostMask)) { diff --git a/znc.h b/znc.h index 240eb3f5..b59e9a46 100644 --- a/znc.h +++ b/znc.h @@ -39,7 +39,6 @@ public: bool WritePidFile(int iPid); bool DeletePidFile(); bool WaitForChildLock(); - Csock* FindSockByName(const CString& sSockName); bool IsHostAllowed(const CString& sHostMask) const; // This returns false if there are too many anonymous connections from this ip bool AllowConnectionFrom(const CString& sIP) const;