winix/core/sessionmanager.cpp

335 lines
5.5 KiB
C++
Executable File

/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include <sys/stat.h>
#include "sessionmanager.h"
#include "request.h"
#include "log.h"
#include "session.h"
#include "sessionparser.h"
#include "plugin.h"
SessionManager::SessionManager()
{
session_checker = 0;
}
void SessionManager::SetRequest(Request * prequest)
{
request = prequest;
session_tab.SetRequest(prequest);
}
void SessionManager::SetConfig(Config * pconfig)
{
config = pconfig;
}
void SessionManager::SetSystem(System * psystem)
{
system = psystem;
}
void SessionManager::SetLastContainer(LastContainer * plast_container)
{
session_tab.SetLastContainer(plast_container);
}
size_t SessionManager::Size()
{
return session_tab.Size();
}
bool SessionManager::IsSession(long id)
{
if( session_tab.FindById(id) == session_tab.End() )
return false;
return true;
}
long SessionManager::CreateSessionId()
{
long id;
// make sure to call std::srand() somewhere at the beginning
// id must be != 0 (0 is reserved)
do
{
if( sizeof(long) == 8 )
{
id = ((unsigned long)std::rand()) << 32 + std::rand();
}
else
{
id = std::rand();
}
id += std::time(0);
if( id < 0 )
id = -id;
}
while( id == 0 ); // 0 reserved for a temporary session
return id;
}
void SessionManager::CreateTemporarySession()
{
SessionContainer::Iterator i = session_tab.FindById( 0 );
if( i == session_tab.End() )
{
Session s;
s.id = 0;
session_tab.PushBack(s);
request->session = &session_tab.Back();
}
else
{
request->session = &(*i);
}
}
void SessionManager::CreateSession()
{
Session s;
int attempts = 100;
for( ; attempts > 0 ; --attempts )
{
s.id = CreateSessionId();
bool added = session_tab.PushBack(s);
if( added )
{
request->session = &session_tab.Back();
request->session->new_session = true;
log << log2 << "SM: created a new session: " << request->session->id << logend;
return;
}
}
// there is a problem with generating a new session id
// we do not set a session cookie
CreateTemporarySession();
log << log1 << "SM: cannot create a session id (temporary used: with id 0)" << logend;
}
bool SessionManager::SetSessionFromCookie(const std::string & cookie)
{
long id = Tol(cookie.c_str());
SessionContainer::Iterator s = session_tab.FindById(id);
if( s == session_tab.End() )
return false;
// that session is in the table
request->session = &(*s);
request->session->new_session = false;
session_tab.UpdateLastTime(s, std::time(0));
if( request->method == Request::get )
request->session->last_time_get = request->session->last_time;
log << log2 << "SM: session: " << s->id;
if( request->session->puser )
log << log2 << ", user: " << request->session->puser->name << ", id: " << request->session->puser->id;
log << log2 << logend;
return true;
}
void SessionManager::SetSession()
{
CookieTab::iterator i = request->cookie_tab.find(config->http_session_id_name);
if( i == request->cookie_tab.end() )
{
CreateSession();
}
else
{
if( !SetSessionFromCookie(i->second) )
{
// there is no such a session
// deleting the old cookie
request->cookie_tab.erase(i);
// and creating a new one
CreateSession();
}
}
// request->session is set now
if( request->session->new_session )
{
request->session->plugin_data.Resize(plugin.Size());
plugin.Call(WINIX_SESSION_CREATED);
}
plugin.Call(WINIX_SESSION_CHANGED);
}
SessionContainer::Iterator SessionManager::SessionBegin()
{
return session_tab.Begin();
}
SessionContainer::Iterator SessionManager::SessionEnd()
{
return session_tab.End();
}
void SessionManager::DeleteOldSessions()
{
session_tab.DelFirstByTimeInterval(config->session_max_idle);
if( ++session_checker > 1000 )
{
// we make the test after 1000 requests
log << log3 << "SM: checking sessions which have 'remember me' flag set" << logend;
session_checker = 0;
session_tab.DelFirstByTimeInterval(config->session_remember_max_idle, false);
}
}
void SessionManager::DeleteSessions()
{
// first we delete all plugins date
/*
SessionContainer::Iterator i = session_tab.Begin();
Session * old_session = request->session;
for( ; i!=session_tab.End() ; ++i )
{
request->session = &(*i);
i->plugin_data.DeleteAll();
}
request->session = old_session;
*/
// and now we delete all sessions
session_tab.Clear();
}
void SessionManager::LoadSessions()
{
SessionParser sp;
SessionContainer::Iterator i;
sp.SetUsers(&system->users);
Session * old_session = request->session;
sp.Parse(config->session_file, session_tab);
i = session_tab.Begin();
for( ; i!=session_tab.End() ; ++i )
{
i->plugin_data.Resize(plugin.Size());
request->session = &(*i);
plugin.Call(WINIX_SESSION_CREATED);
}
request->session = old_session;
}
void SessionManager::SaveSessions()
{
if( config->session_file.empty() )
return;
std::ofstream file(config->session_file.c_str());
if( !file )
{
log << log1 << "SM: cannot open the session file for writing - sessions lost" << logend;
return;
}
log << log2 << "SM: saving sessions" << logend;
long len = 0;
SessionContainer::Iterator i = session_tab.Begin();
for( ; i!=session_tab.End() ; ++i )
{
if( i->id != 0 && i->puser )
{
file << i->id << ' ' << i->puser->id << ' ' << i->remember_me << ' ';
file << (long)i->time << ' ' << (long)i->last_time << std::endl;
++len;
}
}
file.close();
chmod(config->session_file.c_str(), 0600);
log << log2 << "SM: saved " << len << " session(s)" << logend;
}