replace tuple-based singleton with individual singletons

The tuple-based singletons did not actually enforce singleton behavior
and the requirement of the accessor mechanism to include all of the
member types at once was starting to cause a header prerequisite
tangle. This removes the cross-dependencies and enforces actual
singletons by making a single way to access the class.

Tested: Run ipmitool to show that behavior has not changed

Change-Id: Ie966e1142363d279365b1095066380c8383e9f9b
Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
diff --git a/comm_module.cpp b/comm_module.cpp
index acc9089..7b6b496 100644
--- a/comm_module.cpp
+++ b/comm_module.cpp
@@ -6,7 +6,6 @@
 #include "command/rakp34.hpp"
 #include "command/session_cmds.hpp"
 #include "command_table.hpp"
-#include "main.hpp"
 #include "session.hpp"
 
 #include <algorithm>
@@ -57,11 +56,10 @@
 
     for (auto& iter : commands)
     {
-        std::get<command::Table&>(singletonPool)
-            .registerCommand(iter.command,
-                             std::make_unique<command::NetIpmidEntry>(
-                                 iter.command, iter.functor, iter.privilege,
-                                 iter.sessionless));
+        command::Table::get().registerCommand(
+            iter.command,
+            std::make_unique<command::NetIpmidEntry>(
+                iter.command, iter.functor, iter.privilege, iter.sessionless));
     }
 }
 
diff --git a/command/open_session.cpp b/command/open_session.cpp
index 9ba00ec..2887d37 100644
--- a/command/open_session.cpp
+++ b/command/open_session.cpp
@@ -2,7 +2,7 @@
 
 #include "comm_module.hpp"
 #include "endian.hpp"
-#include "main.hpp"
+#include "sessions_manager.hpp"
 
 #include <phosphor-logging/log.hpp>
 
@@ -77,15 +77,11 @@
     try
     {
         // Start an IPMI session
-        session =
-            std::get<session::Manager&>(singletonPool)
-                .startSession(
-                    endian::from_ipmi<>(request->remoteConsoleSessionID), priv,
-                    static_cast<cipher::rakp_auth::Algorithms>(
-                        request->authAlgo),
-                    static_cast<cipher::integrity::Algorithms>(
-                        request->intAlgo),
-                    static_cast<cipher::crypt::Algorithms>(request->confAlgo));
+        session = session::Manager::get().startSession(
+            endian::from_ipmi<>(request->remoteConsoleSessionID), priv,
+            static_cast<cipher::rakp_auth::Algorithms>(request->authAlgo),
+            static_cast<cipher::integrity::Algorithms>(request->intAlgo),
+            static_cast<cipher::crypt::Algorithms>(request->confAlgo));
     }
     catch (std::exception& e)
     {
diff --git a/command/payload_cmds.cpp b/command/payload_cmds.cpp
index bc987c5..ecb86e7 100644
--- a/command/payload_cmds.cpp
+++ b/command/payload_cmds.cpp
@@ -1,6 +1,6 @@
 #include "payload_cmds.hpp"
 
-#include "main.hpp"
+#include "sessions_manager.hpp"
 #include "sol/sol_manager.hpp"
 #include "sol_cmds.hpp"
 
@@ -41,10 +41,9 @@
         return outPayload;
     }
 
-    std::get<sol::Manager&>(singletonPool)
-        .updateSOLParameter(ipmi::convertCurrentChannelNum(
-            ipmi::currentChNum, getInterfaceIndex()));
-    if (!std::get<sol::Manager&>(singletonPool).enable)
+    sol::Manager::get().updateSOLParameter(ipmi::convertCurrentChannelNum(
+        ipmi::currentChNum, getInterfaceIndex()));
+    if (!sol::Manager::get().enable)
     {
         response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED;
         return outPayload;
@@ -57,8 +56,7 @@
         return outPayload;
     }
 
-    auto session = std::get<session::Manager&>(singletonPool)
-                       .getSession(handler.sessionID);
+    auto session = session::Manager::get().getSession(handler.sessionID);
 
     if (!request->encryption && session->isCryptAlgoEnabled())
     {
@@ -78,8 +76,7 @@
         return outPayload;
     }
 
-    auto status = std::get<sol::Manager&>(singletonPool)
-                      .isPayloadActive(request->payloadInstance);
+    auto status = sol::Manager::get().isPayloadActive(request->payloadInstance);
     if (status)
     {
         response->completionCode = IPMI_CC_PAYLOAD_ALREADY_ACTIVE;
@@ -92,8 +89,8 @@
     // Start the SOL payload
     try
     {
-        std::get<sol::Manager&>(singletonPool)
-            .startPayloadInstance(request->payloadInstance, handler.sessionID);
+        sol::Manager::get().startPayloadInstance(request->payloadInstance,
+                                                 handler.sessionID);
     }
     catch (std::exception& e)
     {
@@ -142,8 +139,7 @@
         return outPayload;
     }
 
-    auto status = std::get<sol::Manager&>(singletonPool)
-                      .isPayloadActive(request->payloadInstance);
+    auto status = sol::Manager::get().isPayloadActive(request->payloadInstance);
     if (!status)
     {
         response->completionCode = IPMI_CC_PAYLOAD_DEACTIVATED;
@@ -152,12 +148,11 @@
 
     try
     {
-        auto& context = std::get<sol::Manager&>(singletonPool)
-                            .getContext(request->payloadInstance);
+        auto& context =
+            sol::Manager::get().getContext(request->payloadInstance);
         auto sessionID = context.sessionID;
 
-        std::get<sol::Manager&>(singletonPool)
-            .stopPayloadInstance(request->payloadInstance);
+        sol::Manager::get().stopPayloadInstance(request->payloadInstance);
 
         try
         {
@@ -213,8 +208,7 @@
     response->capacity = maxSolPayloadInstances;
 
     // Currently we support only one SOL session
-    response->instance1 =
-        std::get<sol::Manager&>(singletonPool).isPayloadActive(1);
+    response->instance1 = sol::Manager::get().isPayloadActive(1);
 
     return outPayload;
 }
@@ -244,13 +238,12 @@
         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
         return outPayload;
     }
-    auto status = std::get<sol::Manager&>(singletonPool)
-                      .isPayloadActive(request->payloadInstance);
+    auto status = sol::Manager::get().isPayloadActive(request->payloadInstance);
 
     if (status)
     {
-        auto& context = std::get<sol::Manager&>(singletonPool)
-                            .getContext(request->payloadInstance);
+        auto& context =
+            sol::Manager::get().getContext(request->payloadInstance);
         response->sessionID = context.sessionID;
     }
     else
diff --git a/command/rakp12.cpp b/command/rakp12.cpp
index 099c5dc..7d349c6 100644
--- a/command/rakp12.cpp
+++ b/command/rakp12.cpp
@@ -3,7 +3,7 @@
 #include "comm_module.hpp"
 #include "endian.hpp"
 #include "guid.hpp"
-#include "main.hpp"
+#include "sessions_manager.hpp"
 
 #include <openssl/rand.h>
 
@@ -50,9 +50,8 @@
     std::shared_ptr<session::Session> session;
     try
     {
-        session =
-            std::get<session::Manager&>(singletonPool)
-                .getSession(endian::from_ipmi(request->managedSystemSessionID));
+        session = session::Manager::get().getSession(
+            endian::from_ipmi(request->managedSystemSessionID));
     }
     catch (std::exception& e)
     {
diff --git a/command/rakp34.cpp b/command/rakp34.cpp
index b106b6f..a8ad86a 100644
--- a/command/rakp34.cpp
+++ b/command/rakp34.cpp
@@ -3,8 +3,8 @@
 #include "comm_module.hpp"
 #include "endian.hpp"
 #include "guid.hpp"
-#include "main.hpp"
 #include "rmcp.hpp"
+#include "sessions_manager.hpp"
 
 #include <algorithm>
 #include <cstring>
@@ -17,8 +17,7 @@
 
 void applyIntegrityAlgo(const uint32_t bmcSessionID)
 {
-    auto session =
-        std::get<session::Manager&>(singletonPool).getSession(bmcSessionID);
+    auto session = session::Manager::get().getSession(bmcSessionID);
 
     auto authAlgo = session->getAuthAlgo();
 
@@ -45,8 +44,7 @@
 
 void applyCryptAlgo(const uint32_t bmcSessionID)
 {
-    auto session =
-        std::get<session::Manager&>(singletonPool).getSession(bmcSessionID);
+    auto session = session::Manager::get().getSession(bmcSessionID);
 
     auto authAlgo = session->getAuthAlgo();
 
@@ -97,8 +95,7 @@
     try
     {
         session =
-            std::get<session::Manager&>(singletonPool)
-                .getSession(endian::from_ipmi(request->managedSystemSessionID));
+            session::Manager::get().getSession(request->managedSystemSessionID);
     }
     catch (std::exception& e)
     {
@@ -174,8 +171,7 @@
         response->remoteConsoleSessionID = rcSessionID;
 
         // close the session
-        std::get<session::Manager&>(singletonPool)
-            .stopSession(session->getBMCSessionID());
+        session::Manager::get().stopSession(session->getBMCSessionID());
 
         return outPayload;
     }
diff --git a/command/session_cmds.cpp b/command/session_cmds.cpp
index 98016c9..84c6e85 100644
--- a/command/session_cmds.cpp
+++ b/command/session_cmds.cpp
@@ -1,7 +1,7 @@
 #include "session_cmds.hpp"
 
 #include "endian.hpp"
-#include "main.hpp"
+#include "sessions_manager.hpp"
 
 #include <ipmid/api.h>
 
@@ -34,8 +34,7 @@
     response->completionCode = IPMI_CC_OK;
     uint8_t reqPrivilegeLevel = request->reqPrivLevel;
 
-    auto session = std::get<session::Manager&>(singletonPool)
-                       .getSession(handler.sessionID);
+    auto session = session::Manager::get().getSession(handler.sessionID);
 
     if (reqPrivilegeLevel == 0) // Just return present privilege level
     {
@@ -176,10 +175,8 @@
     {
         if (reqSessionId == session::sessionZero)
         {
-            reqSessionId = std::get<session::Manager&>(singletonPool)
-                               .getSessionIDbyHandle(
-                                   reqSessionHandle &
-                                   session::multiIntfaceSessionHandleMask);
+            reqSessionId = session::Manager::get().getSessionIDbyHandle(
+                reqSessionHandle & session::multiIntfaceSessionHandleMask);
             if (!reqSessionId)
             {
                 return session::ccInvalidSessionHandle;
@@ -187,15 +184,14 @@
         }
 
         auto closeSessionInstance =
-            std::get<session::Manager&>(singletonPool).getSession(reqSessionId);
+            session::Manager::get().getSession(reqSessionId);
         uint8_t closeSessionPriv = closeSessionInstance->currentPrivilege();
 
         if (currentSessionPriv < closeSessionPriv)
         {
             return ipmi::ccInsufficientPrivilege;
         }
-        status = std::get<session::Manager&>(singletonPool)
-                     .stopSession(reqSessionId);
+        status = session::Manager::get().stopSession(reqSessionId);
 
         if (!status)
         {
@@ -262,10 +258,9 @@
 
     try
     {
-        ipmiNetworkInstance =
-            std::get<session::Manager&>(singletonPool).getNetworkInstance();
-        auto currentSession = std::get<session::Manager&>(singletonPool)
-                                  .getSession(handler.sessionID);
+        ipmiNetworkInstance = session::Manager::get().getNetworkInstance();
+        auto currentSession =
+            session::Manager::get().getSession(handler.sessionID);
         currentSessionPriv = currentSession->currentPrivilege();
     }
     catch (sdbusplus::exception::SdBusError& e)
@@ -285,8 +280,7 @@
     {
         response->completionCode = closeMyNetInstanceSession(
             reqSessionId, reqSessionHandle, currentSessionPriv);
-        std::get<session::Manager&>(singletonPool)
-            .scheduleSessionCleaner(100us);
+        session::Manager::get().scheduleSessionCleaner(100us);
     }
     else
     {
diff --git a/command/sol_cmds.cpp b/command/sol_cmds.cpp
index a1e820f..1253ac5 100644
--- a/command/sol_cmds.cpp
+++ b/command/sol_cmds.cpp
@@ -1,6 +1,6 @@
 #include "sol_cmds.hpp"
 
-#include "main.hpp"
+#include "sessions_manager.hpp"
 #include "sol/sol_context.hpp"
 #include "sol/sol_manager.hpp"
 
@@ -35,8 +35,7 @@
 
     try
     {
-        auto& context = std::get<sol::Manager&>(singletonPool)
-                            .getContext(handler.sessionID);
+        auto& context = sol::Manager::get().getContext(handler.sessionID);
 
         context.processInboundPayload(
             request->packetSeqNum, request->packetAckSeqNum,
@@ -62,8 +61,7 @@
     request->majorVersion = MAJOR_VERSION;
     request->minorVersion = MINOR_VERSION;
 
-    auto session =
-        std::get<session::Manager&>(singletonPool).getSession(sessionID);
+    auto session = session::Manager::get().getSession(sessionID);
 
     message::Handler msgHandler(session->channelPtr, sessionID);
 
@@ -90,23 +88,22 @@
     {
         case Parameter::PROGRESS:
         {
-            outPayload.push_back(
-                std::get<sol::Manager&>(singletonPool).progress);
+            outPayload.push_back(sol::Manager::get().progress);
             break;
         }
         case Parameter::ENABLE:
         {
-            outPayload.push_back(std::get<sol::Manager&>(singletonPool).enable);
+            outPayload.push_back(sol::Manager::get().enable);
             break;
         }
         case Parameter::AUTHENTICATION:
         {
             Auth value{0};
 
-            value.encrypt = std::get<sol::Manager&>(singletonPool).forceEncrypt;
-            value.auth = std::get<sol::Manager&>(singletonPool).forceAuth;
-            value.privilege = static_cast<uint8_t>(
-                std::get<sol::Manager&>(singletonPool).solMinPrivilege);
+            value.encrypt = sol::Manager::get().forceEncrypt;
+            value.auth = sol::Manager::get().forceAuth;
+            value.privilege =
+                static_cast<uint8_t>(sol::Manager::get().solMinPrivilege);
             auto buffer = reinterpret_cast<const uint8_t*>(&value);
 
             std::copy_n(buffer, sizeof(value), std::back_inserter(outPayload));
@@ -116,11 +113,9 @@
         {
             Accumulate value{0};
 
-            value.interval = std::get<sol::Manager&>(singletonPool)
-                                 .accumulateInterval.count() /
+            value.interval = sol::Manager::get().accumulateInterval.count() /
                              sol::accIntervalFactor;
-            value.threshold =
-                std::get<sol::Manager&>(singletonPool).sendThreshold;
+            value.threshold = sol::Manager::get().sendThreshold;
             auto buffer = reinterpret_cast<const uint8_t*>(&value);
 
             std::copy_n(buffer, sizeof(value), std::back_inserter(outPayload));
@@ -130,10 +125,9 @@
         {
             Retry value{0};
 
-            value.count = std::get<sol::Manager&>(singletonPool).retryCount;
-            value.interval =
-                std::get<sol::Manager&>(singletonPool).retryInterval.count() /
-                sol::retryIntervalFactor;
+            value.count = sol::Manager::get().retryCount;
+            value.interval = sol::Manager::get().retryInterval.count() /
+                             sol::retryIntervalFactor;
             auto buffer = reinterpret_cast<const uint8_t*>(&value);
 
             std::copy_n(buffer, sizeof(value), std::back_inserter(outPayload));
@@ -149,8 +143,7 @@
         }
         case Parameter::CHANNEL:
         {
-            outPayload.push_back(
-                std::get<sol::Manager&>(singletonPool).channel);
+            outPayload.push_back(sol::Manager::get().channel);
             break;
         }
         case Parameter::NVBITRATE:
diff --git a/command_table.cpp b/command_table.cpp
index 1d9e063..a42d981 100644
--- a/command_table.cpp
+++ b/command_table.cpp
@@ -62,8 +62,7 @@
             return;
         }
         std::shared_ptr<session::Session> session =
-            std::get<session::Manager&>(singletonPool)
-                .getSession(handler->sessionID);
+            session::Manager::get().getSession(handler->sessionID);
 
         // Ignore messages that are not part of an active session
         auto state = static_cast<session::State>(session->state());
@@ -122,8 +121,7 @@
         if (handler->sessionID != session::sessionZero)
         {
             std::shared_ptr<session::Session> session =
-                std::get<session::Manager&>(singletonPool)
-                    .getSession(handler->sessionID);
+                session::Manager::get().getSession(handler->sessionID);
             auto state = static_cast<session::State>(session->state());
             if ((state != session::State::setupInProgress) &&
                 (state != session::State::active))
diff --git a/command_table.hpp b/command_table.hpp
index e882300..172c015 100644
--- a/command_table.hpp
+++ b/command_table.hpp
@@ -216,8 +216,16 @@
  */
 class Table
 {
+  private:
+    struct Private
+    {
+    };
+
   public:
-    Table() = default;
+    explicit Table(const Private&)
+    {
+    }
+    Table() = delete;
     ~Table() = default;
     // Command Table is a singleton so copy, copy-assignment, move and
     // move assignment is deleted
@@ -226,6 +234,21 @@
     Table(Table&&) = default;
     Table& operator=(Table&&) = default;
 
+    /**
+     * @brief Get a reference to the singleton Table
+     *
+     * @return Table reference
+     */
+    static Table& get()
+    {
+        static std::shared_ptr<Table> ptr = nullptr;
+        if (!ptr)
+        {
+            ptr = std::make_shared<Table>(Private());
+        }
+        return *ptr;
+    }
+
     using CommandTable = std::map<uint32_t, std::unique_ptr<Entry>>;
 
     /**
diff --git a/main.cpp b/main.cpp
index 4092211..eab9a2f 100644
--- a/main.cpp
+++ b/main.cpp
@@ -5,6 +5,8 @@
 #include "command_table.hpp"
 #include "message.hpp"
 #include "message_handler.hpp"
+#include "sd_event_loop.hpp"
+#include "sessions_manager.hpp"
 #include "socket_channel.hpp"
 #include "sol_module.hpp"
 
@@ -24,16 +26,11 @@
 
 using namespace phosphor::logging;
 
-// Tuple of Global Singletons
 static auto io = std::make_shared<boost::asio::io_context>();
-session::Manager manager(io);
-command::Table table;
-eventloop::EventLoop loop(io);
-sol::Manager solManager(io);
-
-std::tuple<session::Manager&, command::Table&, eventloop::EventLoop&,
-           sol::Manager&>
-    singletonPool(manager, table, loop, solManager);
+std::shared_ptr<boost::asio::io_context> getIo()
+{
+    return io;
+}
 
 sd_bus* bus = nullptr;
 
@@ -102,7 +99,7 @@
         setInterfaceIndex(channel);
     }
 
-    std::get<session::Manager&>(singletonPool).managerInit(channel);
+    session::Manager::get().managerInit(channel);
     // Register callback to update cache for a GUID change and cache the GUID
     command::registerGUIDChangeCallback();
     cache::guid = command::getSystemGUID();
@@ -113,7 +110,7 @@
     // Register the phosphor-net-ipmid SOL commands
     sol::command::registerCommands();
 
-    auto& loop = std::get<eventloop::EventLoop&>(singletonPool);
+    auto& loop = eventloop::EventLoop::get();
     if (loop.setupSocket(sdbusp, channel))
     {
         return EXIT_FAILURE;
diff --git a/main.hpp b/main.hpp
index 7c78554..fa7584b 100644
--- a/main.hpp
+++ b/main.hpp
@@ -1,18 +1,9 @@
 #pragma once
 
-#include "command/guid.hpp"
-#include "sd_event_loop.hpp"
-#include "sol/sol_manager.hpp"
-
-#include <command_table.hpp>
+#include <boost/asio/io_context.hpp>
 #include <cstddef>
+#include <memory>
 #include <sdbusplus/asio/connection.hpp>
-#include <sessions_manager.hpp>
-#include <tuple>
-
-extern std::tuple<session::Manager&, command::Table&, eventloop::EventLoop&,
-                  sol::Manager&>
-    singletonPool;
 
 // Select call timeout is set arbitrarily set to 30 sec
 static constexpr size_t SELECT_CALL_TIMEOUT = 30;
@@ -21,3 +12,4 @@
 extern sd_bus* bus;
 
 std::shared_ptr<sdbusplus::asio::connection> getSdBus();
+std::shared_ptr<boost::asio::io_context> getIo();
diff --git a/message_handler.cpp b/message_handler.cpp
index 6dadbfc..33bb195 100644
--- a/message_handler.cpp
+++ b/message_handler.cpp
@@ -42,8 +42,7 @@
 
 void Handler::updSessionData(std::shared_ptr<Message>& inMessage)
 {
-    auto session = std::get<session::Manager&>(singletonPool)
-                       .getSession(inMessage->bmcSessionID);
+    auto session = session::Manager::get().getSession(inMessage->bmcSessionID);
 
     sessionID = inMessage->bmcSessionID;
     inMessage->rcSessionID = session->getRCSessionID();
@@ -114,8 +113,7 @@
     auto command = inMessage->getCommand();
     if (inMessage->payloadType == PayloadType::IPMI)
     {
-        auto session =
-            std::get<session::Manager&>(singletonPool).getSession(sessionID);
+        auto session = session::Manager::get().getSession(sessionID);
         // Process PayloadType::IPMI only if ipmi is enabled or for sessionless
         // or for session establisbment command
         if (this->sessionID == session::sessionZero ||
@@ -131,8 +129,8 @@
                 inMessage->payload.begin() + sizeof(LAN::header::Request);
             auto end = inMessage->payload.end() - sizeof(LAN::trailer::Request);
             std::vector<uint8_t> inPayload(start, end);
-            std::get<command::Table&>(singletonPool)
-                .executeCommand(command, inPayload, shared_from_this());
+            command::Table::get().executeCommand(command, inPayload,
+                                                 shared_from_this());
         }
         else
         {
@@ -142,8 +140,8 @@
     }
     else
     {
-        std::get<command::Table&>(singletonPool)
-            .executeCommand(command, inMessage->payload, shared_from_this());
+        command::Table::get().executeCommand(command, inMessage->payload,
+                                             shared_from_this());
     }
 }
 
@@ -169,8 +167,7 @@
 
 void Handler::send(std::shared_ptr<Message> outMessage)
 {
-    auto session =
-        std::get<session::Manager&>(singletonPool).getSession(sessionID);
+    auto session = session::Manager::get().getSession(sessionID);
 
     // Flatten the packet
     auto packet = parser::flatten(outMessage, sessionHeader, session);
@@ -181,16 +178,14 @@
 
 void Handler::setChannelInSession() const
 {
-    auto session =
-        std::get<session::Manager&>(singletonPool).getSession(sessionID);
+    auto session = session::Manager::get().getSession(sessionID);
 
     session->channelPtr = channel;
 }
 
 void Handler::sendSOLPayload(const std::vector<uint8_t>& input)
 {
-    auto session =
-        std::get<session::Manager&>(singletonPool).getSession(sessionID);
+    auto session = session::Manager::get().getSession(sessionID);
 
     auto outMessage = std::make_shared<Message>();
     outMessage->payloadType = PayloadType::SOL;
@@ -206,8 +201,7 @@
 void Handler::sendUnsolicitedIPMIPayload(uint8_t netfn, uint8_t cmd,
                                          const std::vector<uint8_t>& output)
 {
-    auto session =
-        std::get<session::Manager&>(singletonPool).getSession(sessionID);
+    auto session = session::Manager::get().getSession(sessionID);
 
     auto outMessage = std::make_shared<Message>();
     outMessage->payloadType = PayloadType::IPMI;
diff --git a/message_parsers.cpp b/message_parsers.cpp
index 7b8d832..4271c13 100644
--- a/message_parsers.cpp
+++ b/message_parsers.cpp
@@ -181,8 +181,7 @@
 
     uint32_t sessionID = endian::from_ipmi(header->sessId);
 
-    auto session =
-        std::get<session::Manager&>(singletonPool).getSession(sessionID);
+    auto session = session::Manager::get().getSession(sessionID);
     if (!session)
     {
         throw std::runtime_error("RMCP+ message from unknown session");
@@ -345,8 +344,7 @@
         return false;
     }
 
-    auto session = std::get<session::Manager&>(singletonPool)
-                       .getSession(message->bmcSessionID);
+    auto session = session::Manager::get().getSession(message->bmcSessionID);
 
     auto integrityAlgo = session->getIntegrityAlgo();
 
@@ -386,8 +384,7 @@
     trailer->padLength = paddingLen;
     trailer->nextHeader = parser::RMCP_MESSAGE_CLASS_IPMI;
 
-    auto session = std::get<session::Manager&>(singletonPool)
-                       .getSession(message->bmcSessionID);
+    auto session = session::Manager::get().getSession(message->bmcSessionID);
 
     auto integrityData =
         session->getIntegrityAlgo()->generateIntegrityData(packet);
@@ -399,8 +396,7 @@
                                     const std::shared_ptr<Message> message,
                                     size_t payloadLen)
 {
-    auto session = std::get<session::Manager&>(singletonPool)
-                       .getSession(message->bmcSessionID);
+    auto session = session::Manager::get().getSession(message->bmcSessionID);
 
     return session->getCryptAlgo()->decryptPayload(
         packet, sizeof(SessionHeader_t), payloadLen);
@@ -408,8 +404,7 @@
 
 std::vector<uint8_t> encryptPayload(std::shared_ptr<Message> message)
 {
-    auto session = std::get<session::Manager&>(singletonPool)
-                       .getSession(message->bmcSessionID);
+    auto session = session::Manager::get().getSession(message->bmcSessionID);
 
     return session->getCryptAlgo()->encryptPayload(message->payload);
 }
diff --git a/sd_event_loop.hpp b/sd_event_loop.hpp
index 60b4434..1c3d1c2 100644
--- a/sd_event_loop.hpp
+++ b/sd_event_loop.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "main.hpp"
 #include "sol/sol_manager.hpp"
 
 #include <systemd/sd-event.h>
@@ -40,8 +41,14 @@
 
 class EventLoop
 {
+  private:
+    struct Private
+    {
+    };
+
   public:
-    explicit EventLoop(std::shared_ptr<boost::asio::io_context> io) : io(io)
+    EventLoop(std::shared_ptr<boost::asio::io_context>& io, const Private&) :
+        io(io)
     {
     }
     EventLoop() = delete;
@@ -51,6 +58,22 @@
     EventLoop(EventLoop&&) = delete;
     EventLoop& operator=(EventLoop&&) = delete;
 
+    /**
+     * @brief Get a reference to the singleton EventLoop
+     *
+     * @return EventLoop reference
+     */
+    static EventLoop& get()
+    {
+        static std::shared_ptr<EventLoop> ptr = nullptr;
+        if (!ptr)
+        {
+            std::shared_ptr<boost::asio::io_context> io = getIo();
+            ptr = std::make_shared<EventLoop>(io, Private());
+        }
+        return *ptr;
+    }
+
     /** @brief Initialise the event loop and add the handler for incoming
      *         IPMI packets.
      *
diff --git a/sessions_manager.hpp b/sessions_manager.hpp
index f1d060e..14027db 100644
--- a/sessions_manager.hpp
+++ b/sessions_manager.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "main.hpp"
 #include "session.hpp"
 
 #include <boost/asio/steady_timer.hpp>
@@ -32,12 +33,17 @@
 
 class Manager
 {
+  private:
+    struct Private
+    {
+    };
+
   public:
     // BMC Session ID is the key for the map
     using SessionMap = std::map<SessionID, std::shared_ptr<Session>>;
 
     Manager() = delete;
-    explicit Manager(std::shared_ptr<boost::asio::io_context>& io) :
+    Manager(std::shared_ptr<boost::asio::io_context>& io, const Private&) :
         io(io), timer(*io){};
     ~Manager() = default;
     Manager(const Manager&) = delete;
@@ -46,6 +52,26 @@
     Manager& operator=(Manager&&) = default;
 
     /**
+     * @brief Get a reference to the singleton Manager
+     *
+     * @return Manager reference
+     */
+    static Manager& get()
+    {
+        static std::shared_ptr<Manager> ptr = nullptr;
+        if (!ptr)
+        {
+            std::shared_ptr<boost::asio::io_context> io = getIo();
+            ptr = std::make_shared<Manager>(io, Private());
+            if (!ptr)
+            {
+                throw std::runtime_error("failed to create session manager");
+            }
+        }
+        return *ptr;
+    }
+
+    /**
      * @brief Start an IPMI session
      *
      * @param[in] remoteConsoleSessID - Remote Console Session ID mentioned
diff --git a/sol/sol_context.cpp b/sol/sol_context.cpp
index 3b2b892..f0e036c 100644
--- a/sol/sol_context.cpp
+++ b/sol/sol_context.cpp
@@ -1,7 +1,9 @@
 #include "sol_context.hpp"
 
 #include "main.hpp"
+#include "message_handler.hpp"
 #include "sd_event_loop.hpp"
+#include "sessions_manager.hpp"
 #include "sol_manager.hpp"
 
 #include <phosphor-logging/log.hpp>
@@ -18,7 +20,7 @@
     sendThreshold(sendThreshold), payloadInstance(instance),
     sessionID(sessionID)
 {
-    session = std::get<session::Manager&>(singletonPool).getSession(sessionID);
+    session = session::Manager::get().getSession(sessionID);
 }
 
 std::shared_ptr<Context>
@@ -35,8 +37,7 @@
 void Context::enableAccumulateTimer(bool enable)
 {
     // fetch the timeout from the SOL manager
-    std::chrono::microseconds interval =
-        std::get<sol::Manager&>(singletonPool).accumulateInterval;
+    std::chrono::microseconds interval = sol::Manager::get().accumulateInterval;
     if (enable)
     {
         accumulateTimer.expires_after(interval);
@@ -61,8 +62,7 @@
     if (enable)
     {
         // fetch the timeout from the SOL manager
-        std::chrono::microseconds interval =
-            std::get<sol::Manager&>(singletonPool).retryInterval;
+        std::chrono::microseconds interval = sol::Manager::get().retryInterval;
         retryTimer.expires_after(interval);
         std::weak_ptr<Context> weakRef = weak_from_this();
         retryTimer.async_wait([weakRef](const boost::system::error_code& ec) {
@@ -133,7 +133,7 @@
     else if ((count == expectedCharCount) && ackSeqNum)
     {
         // Clear the Host Console Buffer
-        std::get<sol::Manager&>(singletonPool).dataBuffer.erase(count);
+        sol::Manager::get().dataBuffer.erase(count);
 
         // Once it is acknowledged stop the retry interval timer
         enableRetryTimer(false);
@@ -146,8 +146,7 @@
     // Write character data to the Host Console
     if (!input.empty() && seqNum)
     {
-        auto rc =
-            std::get<sol::Manager&>(singletonPool).writeConsoleSocket(input);
+        auto rc = sol::Manager::get().writeConsoleSocket(input);
         if (rc)
         {
             log<level::ERR>("Writing to console socket descriptor failed");
@@ -182,7 +181,7 @@
 
 void Context::prepareResponse(uint8_t ackSeqNum, uint8_t count, bool ack)
 {
-    auto bufferSize = std::get<sol::Manager&>(singletonPool).dataBuffer.size();
+    auto bufferSize = sol::Manager::get().dataBuffer.size();
 
     /* Sent a ACK only response */
     if (payloadCache.size() != 0 || (bufferSize < sendThreshold))
@@ -207,7 +206,7 @@
     response->outOperation.ack = ack;
     response->packetSeqNum = seqNums.incOutboundSeqNum();
 
-    auto handle = std::get<sol::Manager&>(singletonPool).dataBuffer.read();
+    auto handle = sol::Manager::get().dataBuffer.read();
     std::copy_n(handle, readSize, payloadCache.data() + sizeof(Payload));
     expectedCharCount = readSize;
 
@@ -225,7 +224,7 @@
         return -1;
     }
 
-    auto bufferSize = std::get<sol::Manager&>(singletonPool).dataBuffer.size();
+    auto bufferSize = sol::Manager::get().dataBuffer.size();
     auto readSize = std::min(bufferSize, MAX_PAYLOAD_SIZE);
 
     payloadCache.resize(sizeof(Payload) + readSize);
@@ -235,7 +234,7 @@
     response->outOperation.ack = false;
     response->packetSeqNum = seqNums.incOutboundSeqNum();
 
-    auto handle = std::get<sol::Manager&>(singletonPool).dataBuffer.read();
+    auto handle = sol::Manager::get().dataBuffer.read();
     std::copy_n(handle, readSize, payloadCache.data() + sizeof(Payload));
     expectedCharCount = readSize;
 
@@ -255,8 +254,7 @@
     {
         payloadCache.clear();
         expectedCharCount = 0;
-        std::get<sol::Manager&>(singletonPool)
-            .dataBuffer.erase(expectedCharCount);
+        sol::Manager::get().dataBuffer.erase(expectedCharCount);
     }
 }
 
@@ -269,7 +267,7 @@
 
 void Context::charAccTimerHandler()
 {
-    auto bufferSize = std::get<sol::Manager&>(singletonPool).dataBuffer.size();
+    auto bufferSize = sol::Manager::get().dataBuffer.size();
 
     try
     {
diff --git a/sol/sol_manager.cpp b/sol/sol_manager.cpp
index 8407292..2102032 100644
--- a/sol/sol_manager.cpp
+++ b/sol/sol_manager.cpp
@@ -255,8 +255,7 @@
                         if (state != nullptr && *state == false)
                         {
                             // Stop all the payload session.
-                            std::get<sol::Manager&>(singletonPool)
-                                .stopAllPayloadInstance();
+                            sol::Manager::get().stopAllPayloadInstance();
                         }
                     }
                 });
diff --git a/sol/sol_manager.hpp b/sol/sol_manager.hpp
index 4e797d4..b266519 100644
--- a/sol/sol_manager.hpp
+++ b/sol/sol_manager.hpp
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "console_buffer.hpp"
+#include "main.hpp"
 #include "session.hpp"
 #include "sol_context.hpp"
 
@@ -36,6 +37,11 @@
  */
 class Manager
 {
+  private:
+    struct Private
+    {
+    };
+
   public:
     /** @brief SOL Payload Instance is the key for the map, the value is the
      *         SOL context.
@@ -49,10 +55,27 @@
     Manager(Manager&&) = default;
     Manager& operator=(Manager&&) = default;
 
-    Manager(std::shared_ptr<boost::asio::io_context> io) : io(io)
+    Manager(std::shared_ptr<boost::asio::io_context>& io, const Private&) :
+        io(io)
     {
     }
 
+    /**
+     * @brief Get a reference to the singleton Manager
+     *
+     * @return Manager reference
+     */
+    static Manager& get()
+    {
+        static std::shared_ptr<Manager> ptr = nullptr;
+        if (!ptr)
+        {
+            std::shared_ptr<boost::asio::io_context> io = getIo();
+            ptr = std::make_shared<Manager>(io, Private());
+        }
+        return *ptr;
+    }
+
     /** @brief io context to add events to */
     std::shared_ptr<boost::asio::io_context> io;
 
diff --git a/sol_module.cpp b/sol_module.cpp
index 2b1fb46..d9a9a7c 100644
--- a/sol_module.cpp
+++ b/sol_module.cpp
@@ -1,7 +1,6 @@
 #include "command/payload_cmds.hpp"
 #include "command/sol_cmds.hpp"
 #include "command_table.hpp"
-#include "main.hpp"
 #include "session.hpp"
 
 namespace sol
@@ -52,11 +51,10 @@
 
     for (const auto& iter : commands)
     {
-        std::get<::command::Table&>(singletonPool)
-            .registerCommand(iter.command,
-                             std::make_unique<::command::NetIpmidEntry>(
-                                 iter.command, iter.functor, iter.privilege,
-                                 iter.sessionless));
+        ::command::Table::get().registerCommand(
+            iter.command,
+            std::make_unique<::command::NetIpmidEntry>(
+                iter.command, iter.functor, iter.privilege, iter.sessionless));
     }
 }