/
zOMGdev
/
cppcms
Обзор
Документация
Войти
/
zOMGdev
/
cppcms
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
v1.0.5
src/session_pool.cpp
351 строка
10 KB
Artyom Beilis
- Update copyright notice,
03 янв 2012, 17:58
03 янв 2012, 17:58
068d3f9
Код
Авторство
О чём код?
/////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com> // // See accompanying file COPYING.TXT file for licensing details. // /////////////////////////////////////////////////////////////////////////////// #define CPPCMS_SOURCE #include <cppcms/session_pool.h> #include <cppcms/service.h> #include <cppcms/thread_pool.h> #include <cppcms/session_cookies.h> #include <cppcms/session_sid.h> #include <cppcms/session_dual.h> #include "hmac_encryptor.h" #include <cppcms/json.h> #include <cppcms/cppcms_error.h> #include <booster/shared_ptr.h> #include <booster/shared_object.h> #include <booster/enable_shared_from_this.h> #include <cppcms/config.h> #include <cppcms_boost/bind.hpp> namespace boost = cppcms_boost; #include "aes_encryptor.h" #ifdef CPPCMS_WIN_NATIVE #include "session_win32_file_storage.h" #else #include "session_posix_file_storage.h" #endif #include "session_memory_storage.h" #ifndef CPPCMS_NO_TCP_CACHE #include "session_tcp_storage.h" #endif #include <booster/aio/deadline_timer.h> #include <booster/callback.h> #include <booster/posix_time.h> namespace cppcms { struct session_pool::_data { booster::shared_object module; }; using namespace cppcms::sessions; struct session_pool::sid_factory : public session_api_factory { sid_factory(session_pool *pool) : pool_(pool) {} bool requires_gc() { if(pool_->storage_.get()) return pool_->storage_->requires_gc(); else return false; } void gc() { if(pool_->storage_.get()) pool_->storage_->gc_job(); } booster::shared_ptr<session_api> get() { booster::shared_ptr<session_api> p; if(pool_->storage_.get()) p.reset(new session_sid(pool_->storage_->get())); return p; } private: session_pool *pool_; }; struct session_pool::cookies_factory : public session_api_factory { cookies_factory(session_pool *pool) : pool_(pool) {} bool requires_gc() { return false; } void gc() {} booster::shared_ptr<session_api> get() { booster::shared_ptr<session_api> p; if(pool_->encryptor_.get()) p.reset(new session_cookies(pool_->encryptor_->get())); return p; } private: session_pool *pool_; }; struct session_pool::dual_factory : public session_api_factory { dual_factory(unsigned limit,session_pool *pool) : limit_(limit), pool_(pool) {} bool requires_gc() { if(pool_->storage_.get()) return pool_->storage_->requires_gc(); else return false; } void gc() { if(pool_->storage_.get()) pool_->storage_->gc_job(); } booster::shared_ptr<session_api> get() { booster::shared_ptr<session_api> p; if(pool_->storage_.get() && pool_->encryptor_.get()) p.reset(new session_dual(pool_->encryptor_->get(),pool_->storage_->get(),limit_)); return p; } private: unsigned limit_; session_pool *pool_; }; class session_pool::gc_job : public booster::enable_shared_from_this<gc_job> { public: gc_job(service *ser,double freq,session_pool *pool) : timer_(new booster::aio::deadline_timer(ser->get_io_service())), service_(ser), freq_(freq), pool_(pool) { } void async_run() const { service_->thread_pool().post(boost::bind(&gc_job::gc,shared_from_this())); } private: void gc() const { booster::ptime start = booster::ptime::now(); booster::ptime restart = start + booster::ptime::from_number(freq_); pool_->backend_->gc(); timer_->expires_at(restart); timer_->async_wait(boost::bind(&gc_job::async_run,shared_from_this())); } booster::shared_ptr<booster::aio::deadline_timer> timer_; service *service_; double freq_; session_pool *pool_; }; void session_pool::init() { service &srv=*service_; if(backend_.get()) return; std::string location=srv.settings().get("session.location","none"); if((location == "client" || location=="both") && !encryptor_.get()) { using namespace cppcms::sessions::impl; std::string enc=srv.settings().get("session.client.encryptor",""); std::string mac=srv.settings().get("session.client.hmac",""); std::string cbc=srv.settings().get("session.client.cbc",""); if(enc.empty() && mac.empty() && cbc.empty()) { throw cppcms_error("Using clinet session storage without encryption method"); } if(!enc.empty() && (!mac.empty() || !cbc.empty())) { throw cppcms_error("Can't specify both session.client.encryptor and session.client.hmac or session.client.cbc"); } if(!cbc.empty() && mac.empty()) { throw cppcms_error("Can't use session encryption without MAC"); } std::auto_ptr<cppcms::sessions::encryptor_factory> factory; if(!enc.empty()) { crypto::key k; std::string key_file = srv.settings().get("session.client.key_file",""); if(key_file.empty()) k=crypto::key(srv.settings().get<std::string>("session.client.key")); else k.read_from_file(key_file); if(enc=="hmac") { factory.reset(new hmac_factory("sha1",k)); } else if(enc.compare(0,5,"hmac-") == 0) { std::string algo = enc.substr(5); factory.reset(new hmac_factory(algo,k)); } else if(enc.compare(0,3,"aes") == 0) { factory.reset(new aes_factory(enc,k)); } else throw cppcms_error("Unknown encryptor: "+enc); } else { crypto::key hmac_key; std::string hmac_key_file = srv.settings().get("session.client.hmac_key_file",""); if(hmac_key_file.empty()) hmac_key = crypto::key(srv.settings().get<std::string>("session.client.hmac_key")); else hmac_key.read_from_file(hmac_key_file); if(cbc.empty()) { factory.reset(new hmac_factory(mac,hmac_key)); } else { crypto::key cbc_key; std::string cbc_key_file = srv.settings().get("session.client.cbc_key_file",""); if(cbc_key_file.empty()) cbc_key = crypto::key(srv.settings().get<std::string>("session.client.cbc_key")); else cbc_key.read_from_file(cbc_key_file); factory.reset(new aes_factory(cbc,cbc_key,mac,hmac_key)); } } encryptor(factory); } if((location == "server" || location == "both") && !storage_.get()) { std::string stor=srv.settings().get<std::string>("session.server.storage"); std::auto_ptr<sessions::session_storage_factory> factory; if(stor == "files") { std::string dir = srv.settings().get("session.server.dir",""); #ifdef CPPCMS_WIN_NATIVE factory.reset(new session_file_storage_factory(dir)); #else bool sharing = srv.settings().get("session.server.shared",true); int threads = srv.threads_no(); int procs = srv.procs_no(); if(procs == 0) procs=1; factory.reset(new session_file_storage_factory(dir,threads*procs,procs,sharing)); #endif } else if(stor == "memory") { if(srv.procs_no() > 1) throw cppcms_error("Can't use memory storage with more then 1 worker process"); factory.reset(new session_memory_storage_factory()); } else if(stor == "external") { std::string so = srv.settings().get<std::string>("session.server.shared_object",""); std::string module = srv.settings().get<std::string>("session.server.module",""); std::string entry_point = srv.settings().get<std::string>("session.server.entry_point","sessions_generator"); if(so.empty() && module.empty()) throw cppcms_error( "sessions_pool: session.storage=external " "and neither session.server.shared_object " "nor session.server.module is defined"); if(!so.empty() && !module.empty()) throw cppcms_error( "sessions_pool: both session.server.shared_object " "and session.server.module are defined"); if(so.empty()) { so = booster::shared_object::name(module); } std::string error; if(!d->module.open(so,error)) { throw cppcms_error("sessions_pool: failed to load shared object " + so + ": " + error); } cppcms_session_storage_generator_type f=0; d->module.symbol(f,entry_point); factory.reset(f(srv.settings().find("session.server.settings"))); } #ifndef CPPCMS_NO_TCP_CACHE else if(stor == "network") { typedef std::vector<std::string> ips_type; typedef std::vector<int> ports_type; ips_type ips = srv.settings().get<ips_type>("session.server.ips"); ports_type ports = srv.settings().get<ports_type>("session.server.ports"); if(ips.size() != ports.size()) throw cppcms_error( "sessions_pool: session.server.ips and " "session.server.ports are not of the same size"); if(ips.empty()) { throw cppcms_error("sessions_pool:session.server.ips is empty"); } factory.reset(new tcp_factory(ips,ports)); } #endif else throw cppcms_error("sessions_pool: unknown server side storage:"+stor); storage(factory); } if(location == "server") { std::auto_ptr<session_api_factory> f(new sid_factory(this)); backend(f); } else if(location == "client") { std::auto_ptr<session_api_factory> f(new cookies_factory(this)); backend(f); } else if(location == "both") { unsigned limit=srv.settings().get("session.client_size_limit",2048); std::auto_ptr<session_api_factory> f(new dual_factory(limit,this)); backend(f); } else if(location == "none") ; else throw cppcms_error("Unknown location"); service_->after_fork(boost::bind(&session_pool::after_fork,this)); } session_pool::session_pool(service &srv) : d(new _data()), service_(&srv) { } void session_pool::after_fork() { if(backend_.get() && backend_->requires_gc()) { if(service_->process_id()!=1) return; double frequency = service_->settings().get("session.gc",0.0); if(frequency > 0) { booster::shared_ptr<gc_job> job(new gc_job(service_,frequency,this)); job->async_run(); } } } session_pool::~session_pool() { } booster::shared_ptr<session_api> session_pool::get() { booster::shared_ptr<session_api> p; if(backend_.get()) p=backend_->get(); return p; } void session_pool::backend(std::auto_ptr<session_api_factory> b) { backend_=b; } void session_pool::encryptor(std::auto_ptr<sessions::encryptor_factory> e) { encryptor_=e; } void session_pool::storage(std::auto_ptr<sessions::session_storage_factory> s) { storage_=s; } } /// cppcms