diff options
author | lloyd <[email protected]> | 2012-03-22 12:00:58 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2012-03-22 12:00:58 +0000 |
commit | 931a64ed4af06ef912dc43ff122a09cb96e24ea4 (patch) | |
tree | 3ee5bbb5d74b4d0ed6918fe58d6373a6990c9caa /src/tls/sessions_sqlite | |
parent | 1abb402dcc4037e283546852dbc2e587f564d611 (diff) |
Expire old sessions and limit the cache size in the sqlite session manager.
Also when pulling a session via host info, try the most recent session
first (rather than the oldest!).
Diffstat (limited to 'src/tls/sessions_sqlite')
-rw-r--r-- | src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp | 69 | ||||
-rw-r--r-- | src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h | 9 |
2 files changed, 62 insertions, 16 deletions
diff --git a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp index 5150fb3c3..3b68939fa 100644 --- a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp +++ b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp @@ -8,6 +8,7 @@ #include <botan/tls_sqlite_sess_mgr.h> #include <botan/internal/assert.h> #include <botan/hex.h> +#include <botan/time.h> #include <sqlite3.h> namespace Botan { @@ -16,10 +17,10 @@ namespace TLS { namespace { -class sqlite3_statment +class sqlite3_statement { public: - sqlite3_statment(sqlite3* db, const std::string& base_sql) + sqlite3_statement(sqlite3* db, const std::string& base_sql) { int rc = sqlite3_prepare_v2(db, base_sql.c_str(), -1, &m_stmt, 0); @@ -48,6 +49,12 @@ class sqlite3_statment throw std::runtime_error("sqlite3_bind_text failed, code " + to_string(rc)); } + void spin() + { + while(sqlite3_step(m_stmt) == SQLITE_ROW) + {} + } + int step() { return sqlite3_step(m_stmt); @@ -55,7 +62,7 @@ class sqlite3_statment sqlite3_stmt* stmt() { return m_stmt; } - ~sqlite3_statment() { sqlite3_finalize(m_stmt); } + ~sqlite3_statement() { sqlite3_finalize(m_stmt); } private: sqlite3_stmt* m_stmt; }; @@ -66,7 +73,9 @@ Session_Manager_SQLite::Session_Manager_SQLite(const std::string& db_filename, const std::string& table_name, size_t max_sessions, size_t session_lifetime) : - m_table_name(table_name) + m_table_name(table_name), + m_max_sessions(max_sessions), + m_session_lifetime(session_lifetime) { int rc = sqlite3_open(db_filename.c_str(), &m_db); if(rc) @@ -106,7 +115,7 @@ Session_Manager_SQLite::~Session_Manager_SQLite() bool Session_Manager_SQLite::load_from_session_id(const MemoryRegion<byte>& session_id, Session& session) { - sqlite3_statment stmt(m_db, "select session from " + m_table_name + " where session_id = ?1"); + sqlite3_statement stmt(m_db, "select session from " + m_table_name + " where session_id = ?1"); stmt.bind(1, hex_encode(session_id)); @@ -139,9 +148,9 @@ bool Session_Manager_SQLite::load_from_host_info(const std::string& hostname, u16bit port, Session& session) { - sqlite3_statment stmt(m_db, "select session from " + m_table_name + - " where hostname = ?1 and hostport = ?2" - " order by session_start limit 1"); + sqlite3_statement stmt(m_db, "select session from " + m_table_name + + " where hostname = ?1 and hostport = ?2" + " order by session_start desc"); stmt.bind(1, hostname); stmt.bind(2, port); @@ -173,17 +182,16 @@ bool Session_Manager_SQLite::load_from_host_info(const std::string& hostname, void Session_Manager_SQLite::remove_entry(const MemoryRegion<byte>& session_id) { - sqlite3_statment stmt(m_db, "delete from " + m_table_name + " where session_id = ?1"); + sqlite3_statement stmt(m_db, "delete from " + m_table_name + " where session_id = ?1"); stmt.bind(1, hex_encode(session_id)); - while(stmt.step() == SQLITE_ROW) - ; + stmt.spin(); } void Session_Manager_SQLite::save(const Session& session) { - sqlite3_statment stmt(m_db, "insert into " + m_table_name + " values(?1, ?2, ?3, ?4, ?5)"); + sqlite3_statement stmt(m_db, "insert into " + m_table_name + " values(?1, ?2, ?3, ?4, ?5)"); stmt.bind(1, session.sni_hostname()); stmt.bind(2, 0); @@ -191,8 +199,41 @@ void Session_Manager_SQLite::save(const Session& session) stmt.bind(4, hex_encode(session.session_id())); stmt.bind(5, session.DER_encode()); - while(stmt.step() == SQLITE_ROW) - ; + stmt.spin(); + + prune_session_cache(); + } + +void Session_Manager_SQLite::prune_session_cache() + { + sqlite3_statement remove_expired(m_db, "delete from " + m_table_name + " where session_start <= ?1"); + + remove_expired.bind(1, system_time() - m_session_lifetime); + + remove_expired.spin(); + + sqlite3_statement row_count(m_db, "select count(*) from " + m_table_name); + + if(row_count.step() == SQLITE_ROW) + { + BOTAN_ASSERT(sqlite3_column_type(row_count.stmt(), 0) == SQLITE_INTEGER, + "Return count is a blob"); + + const int sessions_int = sqlite3_column_int(row_count.stmt(), 0); + + BOTAN_ASSERT(sessions_int >= 0, "SQLite returned positive row count"); + + const size_t sessions = static_cast<size_t>(sessions_int); + + if(sessions > m_max_sessions) + { + sqlite3_statement remove_some(m_db, "delete from " + m_table_name + " where session_id in " + "(select session_id from " + m_table_name + " limit ?1)"); + + remove_some.bind(1, sessions - m_max_sessions); + remove_some.spin(); + } + } } } diff --git a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h index 2bc435da3..35a37d206 100644 --- a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h +++ b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h @@ -22,13 +22,15 @@ class BOTAN_DLL Session_Manager_SQLite : public Session_Manager { public: /** + * @param db_filename filename of the SQLite database file + * @param table_name names the table to store sessions in * @param max_sessions a hint on the maximum number of sessions * to keep in memory at any one time. (If zero, don't cap) * @param session_lifetime sessions are expired after this many * seconds have elapsed from initial handshake. */ Session_Manager_SQLite(const std::string& db_filename, - const std::string& table_name, + const std::string& table_name = "tls_sessions", size_t max_sessions = 1000, size_t session_lifetime = 7200); @@ -47,7 +49,10 @@ class BOTAN_DLL Session_Manager_SQLite : public Session_Manager Session_Manager_SQLite(const Session_Manager_SQLite&) {} Session_Manager_SQLite& operator=(const Session_Manager_SQLite&) { return (*this); } - const std::string m_table_name; + void prune_session_cache(); + + std::string m_table_name; + size_t m_max_sessions, m_session_lifetime; class sqlite3* m_db; }; |