blob: a2d2d8dce9084c866d03dde4add09fbf18f0da01 [file] [log] [blame]
Tom Joseph3e61aa02016-08-08 08:42:39 -05001#include "sessions_manager.hpp"
2
3#include <algorithm>
4#include <cstdlib>
5#include <iomanip>
6#include <iostream>
7#include <memory>
8
9#include "session.hpp"
10
11namespace session
12{
13
14Manager::Manager()
15{
16 /*
17 * Session ID is 0000_0000h for messages that are sent outside the session.
18 * The session setup commands are sent on this session, so when the session
19 * manager comes up, is creates the Session ID 0000_0000h. It is active
20 * through the lifetime of the Session Manager.
21 */
22 sessionsMap.emplace(0, std::make_shared<Session>());
23 // Seeding the pseudo-random generator
24 std::srand(std::time(0));
25}
26
27std::weak_ptr<Session> Manager::startSession(SessionID remoteConsoleSessID,
28 Privilege priv, cipher::rakp_auth::Algorithms authAlgo)
29{
30 std::shared_ptr<Session> session = nullptr;
31 SessionID sessionID = 0;
32 cleanStaleEntries();
33 auto activeSessions = sessionsMap.size() - MAX_SESSIONLESS_COUNT;
34
35 if (activeSessions < MAX_SESSION_COUNT)
36 {
37 do
38 {
39 session = std::make_shared<Session>(remoteConsoleSessID, priv);
40
41 /*
42 * Every IPMI Session has two ID's attached to it Remote Console
43 * Session ID and BMC Session ID. The remote console ID is passed
44 * along with the Open Session request command. The BMC session ID
45 * is the key for the session map and is generated using std::rand.
46 * There is a rare chance for collision of BMC session ID, so the
47 * following check validates that. In the case of collision the
48 * created session is reseted and a new session is created for
49 * validating collision.
50 */
51 auto iterator = sessionsMap.find(session->getBMCSessionID());
52 if (iterator != sessionsMap.end())
53 {
54 //Detected BMC Session ID collisions
55 session.reset();
56 continue;
57 }
58 else
59 {
60 break;
61 }
62 }
63 while (1);
64
65 // Set the Authentication Algorithm to RAKP_HMAC_SHA1
66 switch (authAlgo)
67 {
68 case cipher::rakp_auth::Algorithms::RAKP_HMAC_SHA1:
69 {
70 session->setAuthAlgo(
71 std::make_unique<cipher::rakp_auth::AlgoSHA1>());
72 break;
73 }
74 default:
75 {
76 throw std::runtime_error("Invalid Authentication Algorithm");
77 }
78 }
79 sessionID = session->getBMCSessionID();
80 sessionsMap.emplace(sessionID, std::move(session));
81 }
82 else
83 {
84 std::cerr << "E> No free sessions left: Active: " << activeSessions <<
85 " Allowed: " <<
86 MAX_SESSION_COUNT << "\n";
87
88 for (const auto& iterator : sessionsMap)
89 {
90 std::cerr << "E> Active Session: 0x" << std::hex
91 << std::setfill('0') << std::setw(8)
92 << (iterator.second)->getBMCSessionID() << "\n";
93 }
94 throw std::runtime_error("No free sessions left");
95 }
96
97 return getSession(sessionID);
98}
99
Tom Joseph9662c3a2016-12-06 17:52:16 +0530100bool Manager::stopSession(SessionID bmcSessionID)
Tom Joseph3e61aa02016-08-08 08:42:39 -0500101{
Tom Joseph9662c3a2016-12-06 17:52:16 +0530102 auto iter = sessionsMap.find(bmcSessionID);
103 if (iter != sessionsMap.end())
Tom Joseph3e61aa02016-08-08 08:42:39 -0500104 {
Tom Joseph9662c3a2016-12-06 17:52:16 +0530105 iter->second->state = State::TEAR_DOWN_IN_PROGRESS;
106 return true;
107 }
108 else
109 {
110 return false;
Tom Joseph3e61aa02016-08-08 08:42:39 -0500111 }
112}
113
114std::weak_ptr<Session> Manager::getSession(SessionID sessionID,
115 RetrieveOption option)
116{
117 switch (option)
118 {
119 case RetrieveOption::BMC_SESSION_ID:
120 {
121 auto iter = sessionsMap.find(sessionID);
122 if (iter != sessionsMap.end())
123 {
124 return iter->second;
125 }
126 }
127 case RetrieveOption::RC_SESSION_ID:
128 {
129 auto iter = std::find_if(sessionsMap.begin(),
130 sessionsMap.end(),
131 [sessionID](const std::pair<const uint32_t,
132 std::shared_ptr<Session>>& in)
133 -> bool
134 {
135 return sessionID == in.second->getRCSessionID();
136 });
137
138 if (iter != sessionsMap.end())
139 {
140 return iter->second;
141 }
142 }
143 default:
144 throw std::runtime_error("Invalid retrieval option");
145 }
146
147 throw std::runtime_error("Session ID not found");
148}
149
150void Manager::cleanStaleEntries()
151{
152 for(auto iter = sessionsMap.begin(); iter != sessionsMap.end();)
153 {
154 auto session = iter->second;
155 if ((session->getBMCSessionID() != SESSION_ZERO) &&
156 !(session->isSessionActive()))
157 {
158 iter = sessionsMap.erase(iter);
159 }
160 else
161 {
162 ++iter;
163 }
164 }
165}
166
167} // namespace session