summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sessions_manager.cpp166
-rw-r--r--sessions_manager.hpp96
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
OpenPOWER on IntegriCloud