blob: ff17727a1ee6f3318ecffdca038f760c96770762 [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
100void Manager::stopSession(SessionID bmcSessionID)
101{
102 // If the session is valid and not session zero
103 if(bmcSessionID != SESSION_ZERO)
104 {
105 auto iter = sessionsMap.find(bmcSessionID);
106 if (iter != sessionsMap.end())
107 {
108 iter->second->state = State::TEAR_DOWN_IN_PROGRESS;
109 }
110 }
111}
112
113std::weak_ptr<Session> Manager::getSession(SessionID sessionID,
114 RetrieveOption option)
115{
116 switch (option)
117 {
118 case RetrieveOption::BMC_SESSION_ID:
119 {
120 auto iter = sessionsMap.find(sessionID);
121 if (iter != sessionsMap.end())
122 {
123 return iter->second;
124 }
125 }
126 case RetrieveOption::RC_SESSION_ID:
127 {
128 auto iter = std::find_if(sessionsMap.begin(),
129 sessionsMap.end(),
130 [sessionID](const std::pair<const uint32_t,
131 std::shared_ptr<Session>>& in)
132 -> bool
133 {
134 return sessionID == in.second->getRCSessionID();
135 });
136
137 if (iter != sessionsMap.end())
138 {
139 return iter->second;
140 }
141 }
142 default:
143 throw std::runtime_error("Invalid retrieval option");
144 }
145
146 throw std::runtime_error("Session ID not found");
147}
148
149void Manager::cleanStaleEntries()
150{
151 for(auto iter = sessionsMap.begin(); iter != sessionsMap.end();)
152 {
153 auto session = iter->second;
154 if ((session->getBMCSessionID() != SESSION_ZERO) &&
155 !(session->isSessionActive()))
156 {
157 iter = sessionsMap.erase(iter);
158 }
159 else
160 {
161 ++iter;
162 }
163 }
164}
165
166} // namespace session