mirror of
https://github.com/znc/znc.git
synced 2026-05-09 23:04:47 +02:00
WebModules: Fix a crash during shutdown
During shutdown, the global list of sessions is destroyed. The new multimap which counts sessions per address is also destroyed. However, they are destroyed in unspecified order. This is not what we want because destructing the session map also destroyed all the sessions which then has to access the sessions-per-ip multimap. This obviously crashes if the multimap was already destroyed. The fix here is to introduce a new class that contains both of those maps and makes sure all the sessions are destroyed before the maps are destroyed themselves. I hope this description makes some sense... git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@2264 726aef4b-f618-498e-8847-2d620e286838
This commit is contained in:
+31
-14
@@ -14,23 +14,40 @@
|
|||||||
/// @todo Do we want to make this a configure option?
|
/// @todo Do we want to make this a configure option?
|
||||||
#define _SKINDIR_ _DATADIR_ "/webskins"
|
#define _SKINDIR_ _DATADIR_ "/webskins"
|
||||||
|
|
||||||
// Sessions are valid for a day, (24h, ...)
|
const unsigned int CWebSock::m_uiMaxSessions = 5;
|
||||||
CWebSessionMap CWebSock::m_mspSessions(24 * 60 * 60 * 1000);
|
|
||||||
static std::multimap<CString, CWebSession*> mIPSessions;
|
// We need this class to make sure the contained maps and their content is
|
||||||
|
// destroyed in the order that we want.
|
||||||
|
struct CSessionManager {
|
||||||
|
// Sessions are valid for a day, (24h, ...)
|
||||||
|
CSessionManager() : m_mspSessions(24 * 60 * 60 * 1000) {}
|
||||||
|
~CSessionManager() {
|
||||||
|
// Make sure all sessions are destroyed before any of our maps
|
||||||
|
// are destroyed
|
||||||
|
m_mspSessions.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
CWebSessionMap m_mspSessions;
|
||||||
|
std::multimap<CString, CWebSession*> m_mIPSessions;
|
||||||
|
};
|
||||||
typedef std::multimap<CString, CWebSession*>::iterator mIPSessionsIterator;
|
typedef std::multimap<CString, CWebSession*>::iterator mIPSessionsIterator;
|
||||||
|
|
||||||
const unsigned int CWebSock::m_uiMaxSessions = 5;
|
static CSessionManager Sessions;
|
||||||
|
|
||||||
|
void CWebSock::FinishUserSessions(const CUser& User) {
|
||||||
|
Sessions.m_mspSessions.FinishUserSessions(User);
|
||||||
|
}
|
||||||
|
|
||||||
CWebSession::~CWebSession() {
|
CWebSession::~CWebSession() {
|
||||||
// Find our entry in mIPSessions
|
// Find our entry in mIPSessions
|
||||||
pair<mIPSessionsIterator, mIPSessionsIterator> p =
|
pair<mIPSessionsIterator, mIPSessionsIterator> p =
|
||||||
mIPSessions.equal_range(m_sIP);
|
Sessions.m_mIPSessions.equal_range(m_sIP);
|
||||||
mIPSessionsIterator it = p.first;
|
mIPSessionsIterator it = p.first;
|
||||||
mIPSessionsIterator end = p.second;
|
mIPSessionsIterator end = p.second;
|
||||||
|
|
||||||
while (it != end) {
|
while (it != end) {
|
||||||
if (it->second == this) {
|
if (it->second == this) {
|
||||||
mIPSessions.erase(it++);
|
Sessions.m_mIPSessions.erase(it++);
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
@@ -52,7 +69,7 @@ bool CZNCTagHandler::HandleTag(CTemplate& Tmpl, const CString& sName, const CStr
|
|||||||
|
|
||||||
CWebSession::CWebSession(const CString& sId, const CString& sIP) : m_sId(sId), m_sIP(sIP) {
|
CWebSession::CWebSession(const CString& sId, const CString& sIP) : m_sId(sId), m_sIP(sIP) {
|
||||||
m_pUser = NULL;
|
m_pUser = NULL;
|
||||||
mIPSessions.insert(make_pair(sIP, this));
|
Sessions.m_mIPSessions.insert(make_pair(sIP, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWebSession::IsAdmin() const { return IsLoggedIn() && m_pUser->IsAdmin(); }
|
bool CWebSession::IsAdmin() const { return IsLoggedIn() && m_pUser->IsAdmin(); }
|
||||||
@@ -681,19 +698,19 @@ CSmartPtr<CWebSession> CWebSock::GetSession() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const CString sCookieSessionId = GetRequestCookie("SessionId");
|
const CString sCookieSessionId = GetRequestCookie("SessionId");
|
||||||
CSmartPtr<CWebSession> *pSession = m_mspSessions.GetItem(sCookieSessionId);
|
CSmartPtr<CWebSession> *pSession = Sessions.m_mspSessions.GetItem(sCookieSessionId);
|
||||||
|
|
||||||
if (pSession != NULL) {
|
if (pSession != NULL) {
|
||||||
// Refresh the timeout
|
// Refresh the timeout
|
||||||
m_mspSessions.AddItem((*pSession)->GetId(), *pSession);
|
Sessions.m_mspSessions.AddItem((*pSession)->GetId(), *pSession);
|
||||||
m_spSession = *pSession;
|
m_spSession = *pSession;
|
||||||
DEBUG("Found existing session from cookie: [" + sCookieSessionId + "] IsLoggedIn(" + CString((*pSession)->IsLoggedIn() ? "true" : "false") + ")");
|
DEBUG("Found existing session from cookie: [" + sCookieSessionId + "] IsLoggedIn(" + CString((*pSession)->IsLoggedIn() ? "true" : "false") + ")");
|
||||||
return *pSession;
|
return *pSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mIPSessions.count(GetRemoteIP()) > m_uiMaxSessions) {
|
if (Sessions.m_mIPSessions.count(GetRemoteIP()) > m_uiMaxSessions) {
|
||||||
mIPSessionsIterator it = mIPSessions.find(GetRemoteIP());
|
mIPSessionsIterator it = Sessions.m_mIPSessions.find(GetRemoteIP());
|
||||||
mIPSessions.erase(it);
|
Sessions.m_mIPSessions.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
CString sSessionID;
|
CString sSessionID;
|
||||||
@@ -705,10 +722,10 @@ CSmartPtr<CWebSession> CWebSock::GetSession() {
|
|||||||
sSessionID = sSessionID.SHA256();
|
sSessionID = sSessionID.SHA256();
|
||||||
|
|
||||||
DEBUG("Auto generated session: [" + sSessionID + "]");
|
DEBUG("Auto generated session: [" + sSessionID + "]");
|
||||||
} while (m_mspSessions.HasItem(sSessionID));
|
} while (Sessions.m_mspSessions.HasItem(sSessionID));
|
||||||
|
|
||||||
CSmartPtr<CWebSession> spSession(new CWebSession(sSessionID, GetRemoteIP()));
|
CSmartPtr<CWebSession> spSession(new CWebSession(sSessionID, GetRemoteIP()));
|
||||||
m_mspSessions.AddItem(spSession->GetId(), spSession);
|
Sessions.m_mspSessions.AddItem(spSession->GetId(), spSession);
|
||||||
|
|
||||||
m_spSession = spSession;
|
m_spSession = spSession;
|
||||||
|
|
||||||
|
|||||||
+1
-4
@@ -147,9 +147,7 @@ public:
|
|||||||
CString GetRequestCookie(const CString& sKey);
|
CString GetRequestCookie(const CString& sKey);
|
||||||
bool SendCookie(const CString& sKey, const CString& sValue);
|
bool SendCookie(const CString& sKey, const CString& sValue);
|
||||||
|
|
||||||
static void FinishUserSessions(const CUser& User) {
|
static void FinishUserSessions(const CUser& User);
|
||||||
m_mspSessions.FinishUserSessions(User);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using CHTTPSock::PrintErrorPage;
|
using CHTTPSock::PrintErrorPage;
|
||||||
@@ -171,7 +169,6 @@ private:
|
|||||||
CString m_sPage; // Gets filled by ParsePath()
|
CString m_sPage; // Gets filled by ParsePath()
|
||||||
CSmartPtr<CWebSession> m_spSession;
|
CSmartPtr<CWebSession> m_spSession;
|
||||||
|
|
||||||
static CWebSessionMap m_mspSessions;
|
|
||||||
static const unsigned int m_uiMaxSessions;
|
static const unsigned int m_uiMaxSessions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user