From b61a88bacdd5fdd2507cb218afcf95c40a2565f2 Mon Sep 17 00:00:00 2001 From: Kun Yi Date: Tue, 12 Nov 2019 22:50:34 -0800 Subject: Implement session expiration If the caller opens sessions but doesn't close them, either intentionally or unintentionally, session IDs will leak. Once the maximum number of sessions are reached, no new session can be opened. Implement a cleanup procedure to automatically remove stale sessions. If a session hasn't seen activity for a while, call the expire() functions on the handler, and remove the session from tracking table. For handlers that haven't implemented the expire() call this change will be a no-op. Signed-off-by: Kun Yi Change-Id: I895ae19b4003d2d6f7a0b2e73370fe5aa664adee --- manager.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) (limited to 'manager.cpp') diff --git a/manager.cpp b/manager.cpp index 684f20c..286b81a 100644 --- a/manager.cpp +++ b/manager.cpp @@ -17,6 +17,7 @@ #include "manager.hpp" #include +#include #include #include #include @@ -67,6 +68,52 @@ int BlobManager::getOpen(const std::string& path) const return 0; } +void BlobManager::eraseSession(GenericBlobInterface* handler, uint16_t session) +{ + sessions.erase(session); + /* Ok for openSessions[handler] to be an empty set */ + openSessions[handler].erase(session); + decrementOpen(getPath(session)); +} + +void BlobManager::cleanUpStaleSessions(GenericBlobInterface* handler) +{ + if (openSessions.count(handler) == 0) + { + return; + } + + auto timeNow = std::chrono::steady_clock::now(); + std::set expiredSet; + + for (auto sessionId : openSessions[handler]) + { + if (timeNow - sessions[sessionId].lastActionTime >= sessionTimeout) + { + expiredSet.insert(sessionId); + } + } + + for (auto sessionId : expiredSet) + { + std::cerr << "phosphor-ipmi-blobs: expiring stale session " << sessionId + << std::endl; + + /* We do a best case recovery by issuing an expire call. If it fails + * don't erase sessions since the handler side might be still tracking + * it as open. */ + if (handler->expire(sessionId)) + { + eraseSession(handler, sessionId); + } + else + { + std::cerr << "phosphor-ipmi-blobs: failed to expire session " + << sessionId << std::endl; + } + } +} + bool BlobManager::registerHandler(std::unique_ptr handler) { if (!handler) @@ -130,6 +177,10 @@ bool BlobManager::open(uint16_t flags, const std::string& path, return false; } + /* Try to clean up anything that's falling out of cleanup timeout for this + * handler */ + cleanUpStaleSessions(handler); + if (!handler->open(*session, flags, path)) { return false; @@ -137,6 +188,7 @@ bool BlobManager::open(uint16_t flags, const std::string& path, /* Associate session with handler */ sessions[*session] = SessionInfo(path, handler, flags); + openSessions[handler].insert(*session); incrementOpen(path); return true; } @@ -206,8 +258,7 @@ bool BlobManager::close(uint16_t session) { return false; } - sessions.erase(session); - decrementOpen(getPath(session)); + eraseSession(handler, session); return true; } return false; -- cgit v1.2.3