diff options
-rw-r--r-- | sessions_manager.cpp | 166 | ||||
-rw-r--r-- | sessions_manager.hpp | 96 |
2 files changed, 262 insertions, 0 deletions
diff --git a/sessions_manager.cpp b/sessions_manager.cpp new file mode 100644 index 0000000..ff17727 --- /dev/null +++ b/sessions_manager.cpp @@ -0,0 +1,166 @@ +#include "sessions_manager.hpp" + +#include <algorithm> +#include <cstdlib> +#include <iomanip> +#include <iostream> +#include <memory> + +#include "session.hpp" + +namespace session +{ + +Manager::Manager() +{ + /* + * Session ID is 0000_0000h for messages that are sent outside the session. + * The session setup commands are sent on this session, so when the session + * manager comes up, is creates the Session ID 0000_0000h. It is active + * through the lifetime of the Session Manager. + */ + sessionsMap.emplace(0, std::make_shared<Session>()); + // Seeding the pseudo-random generator + std::srand(std::time(0)); +} + +std::weak_ptr<Session> Manager::startSession(SessionID remoteConsoleSessID, + Privilege priv, cipher::rakp_auth::Algorithms authAlgo) +{ + std::shared_ptr<Session> session = nullptr; + SessionID sessionID = 0; + cleanStaleEntries(); + auto activeSessions = sessionsMap.size() - MAX_SESSIONLESS_COUNT; + + if (activeSessions < MAX_SESSION_COUNT) + { + do + { + session = std::make_shared<Session>(remoteConsoleSessID, priv); + + /* + * Every IPMI Session has two ID's attached to it Remote Console + * Session ID and BMC Session ID. The remote console ID is passed + * along with the Open Session request command. The BMC session ID + * is the key for the session map and is generated using std::rand. + * There is a rare chance for collision of BMC session ID, so the + * following check validates that. In the case of collision the + * created session is reseted and a new session is created for + * validating collision. + */ + auto iterator = sessionsMap.find(session->getBMCSessionID()); + if (iterator != sessionsMap.end()) + { + //Detected BMC Session ID collisions + session.reset(); + continue; + } + else + { + break; + } + } + while (1); + + // Set the Authentication Algorithm to RAKP_HMAC_SHA1 + switch (authAlgo) + { + case cipher::rakp_auth::Algorithms::RAKP_HMAC_SHA1: + { + session->setAuthAlgo( + std::make_unique<cipher::rakp_auth::AlgoSHA1>()); + break; + } + default: + { + throw std::runtime_error("Invalid Authentication Algorithm"); + } + } + sessionID = session->getBMCSessionID(); + sessionsMap.emplace(sessionID, std::move(session)); + } + else + { + std::cerr << "E> No free sessions left: Active: " << activeSessions << + " Allowed: " << + MAX_SESSION_COUNT << "\n"; + + for (const auto& iterator : sessionsMap) + { + std::cerr << "E> Active Session: 0x" << std::hex + << std::setfill('0') << std::setw(8) + << (iterator.second)->getBMCSessionID() << "\n"; + } + throw std::runtime_error("No free sessions left"); + } + + return getSession(sessionID); +} + +void Manager::stopSession(SessionID bmcSessionID) +{ + // If the session is valid and not session zero + if(bmcSessionID != SESSION_ZERO) + { + auto iter = sessionsMap.find(bmcSessionID); + if (iter != sessionsMap.end()) + { + iter->second->state = State::TEAR_DOWN_IN_PROGRESS; + } + } +} + +std::weak_ptr<Session> Manager::getSession(SessionID sessionID, + RetrieveOption option) +{ + switch (option) + { + case RetrieveOption::BMC_SESSION_ID: + { + auto iter = sessionsMap.find(sessionID); + if (iter != sessionsMap.end()) + { + return iter->second; + } + } + case RetrieveOption::RC_SESSION_ID: + { + auto iter = std::find_if(sessionsMap.begin(), + sessionsMap.end(), + [sessionID](const std::pair<const uint32_t, + std::shared_ptr<Session>>& in) + -> bool + { + return sessionID == in.second->getRCSessionID(); + }); + + if (iter != sessionsMap.end()) + { + return iter->second; + } + } + default: + throw std::runtime_error("Invalid retrieval option"); + } + + throw std::runtime_error("Session ID not found"); +} + +void Manager::cleanStaleEntries() +{ + for(auto iter = sessionsMap.begin(); iter != sessionsMap.end();) + { + auto session = iter->second; + if ((session->getBMCSessionID() != SESSION_ZERO) && + !(session->isSessionActive())) + { + iter = sessionsMap.erase(iter); + } + else + { + ++iter; + } + } +} + +} // namespace session diff --git a/sessions_manager.hpp b/sessions_manager.hpp new file mode 100644 index 0000000..71bb7e4 --- /dev/null +++ b/sessions_manager.hpp @@ -0,0 +1,96 @@ +#pragma once + +#include <map> +#include <memory> +#include <mutex> + +#include "session.hpp" + +namespace session +{ + +enum class RetrieveOption +{ + BMC_SESSION_ID, + RC_SESSION_ID, +}; + +constexpr size_t SESSION_ZERO = 0; +constexpr size_t MAX_SESSIONLESS_COUNT = 1; +constexpr size_t MAX_SESSION_COUNT = 5; + +/* + * @class Manager + * + * Manager class acts a manager for the IPMI sessions and provides interfaces + * to start a session, stop a session and get reference to the session objects. + * + */ + +class Manager +{ + public: + + // BMC Session ID is the key for the map + using SessionMap = std::map<SessionID, std::shared_ptr<Session>>; + + Manager(); + ~Manager() = default; + Manager(const Manager&) = delete; + Manager& operator=(const Manager&) = delete; + Manager(Manager&&) = default; + Manager& operator=(Manager&&) = default; + + /* + * @brief Start an IPMI session + * + * @param[in] remoteConsoleSessID - Remote Console Session ID mentioned + * in the Open SessionRequest Command + * @param[in] priv - Privilege level requested + * @param[in] authAlgo - Authentication Algorithm + * + * @return session handle on success and nullptr on failure + * + */ + std::weak_ptr<Session> startSession(SessionID remoteConsoleSessID, + Privilege priv, cipher::rakp_auth::Algorithms authAlgo); + + /* + * @brief Stop IPMI Session + * + * @param[in] bmcSessionID - BMC Session ID + * + */ + void stopSession(SessionID bmcSessionID); + + /* + * @brief Get Session Handle + * + * @param[in] sessionID - Session ID + * @param[in] option - Select between BMC Session ID and Remote Console + * Session ID, Default option is BMC Session ID + * + * @return session handle on success and nullptr on failure + * + */ + std::weak_ptr<Session> getSession( + SessionID sessionID, + RetrieveOption option = RetrieveOption::BMC_SESSION_ID); + + private: + + /* + * @brief Session Manager keeps the session objects as a sorted + * associative container with Session ID as the unique key + */ + SessionMap sessionsMap; + + /* + * @brief Clean Session Stale Entries + * + * Removes the inactive sessions entries from the Session Map + */ + void cleanStaleEntries(); +}; + +} // namespace session |