xref: /openbmc/phosphor-net-ipmid/sessions_manager.cpp (revision 8425624a9046f5a853e8596cc74441e622028494)
13e61aa0dSTom Joseph #include "sessions_manager.hpp"
23e61aa0dSTom Joseph 
3f8a34fc4SSuryakanth Sekar #include "main.hpp"
49e801a2bSVernon Mauery #include "session.hpp"
59e801a2bSVernon Mauery 
67b7f25f7SGeorge Liu #include <phosphor-logging/lg2.hpp>
7bc8958feSGeorge Liu #include <sdbusplus/asio/connection.hpp>
8bc8958feSGeorge Liu #include <user_channel/channel_layer.hpp>
9bc8958feSGeorge Liu 
103e61aa0dSTom Joseph #include <algorithm>
113e61aa0dSTom Joseph #include <cstdlib>
123e61aa0dSTom Joseph #include <iomanip>
133e61aa0dSTom Joseph #include <memory>
14fc37e59eSVernon Mauery 
153e61aa0dSTom Joseph namespace session
163e61aa0dSTom Joseph {
173e61aa0dSTom Joseph 
18f8a34fc4SSuryakanth Sekar static std::array<uint8_t, session::maxNetworkInstanceSupported>
19f8a34fc4SSuryakanth Sekar     ipmiNetworkChannelNumList = {0};
20f8a34fc4SSuryakanth Sekar 
setNetworkInstance(void)21f8a34fc4SSuryakanth Sekar void Manager::setNetworkInstance(void)
22f8a34fc4SSuryakanth Sekar {
23f8a34fc4SSuryakanth Sekar     uint8_t index = 0, ch = 1;
24f8a34fc4SSuryakanth Sekar     // Constructing net-ipmid instances list based on channel info
25f8a34fc4SSuryakanth Sekar     // valid channel start from 1 to 15  and assuming max 4 LAN channel
26f8a34fc4SSuryakanth Sekar     // supported
27f8a34fc4SSuryakanth Sekar 
28f8a34fc4SSuryakanth Sekar     while (ch < ipmi::maxIpmiChannels &&
29f8a34fc4SSuryakanth Sekar            index < session::maxNetworkInstanceSupported)
30f8a34fc4SSuryakanth Sekar     {
31f8a34fc4SSuryakanth Sekar         ipmi::ChannelInfo chInfo;
32f8a34fc4SSuryakanth Sekar         ipmi::getChannelInfo(ch, chInfo);
33f8a34fc4SSuryakanth Sekar         if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
34f8a34fc4SSuryakanth Sekar             ipmi::EChannelMediumType::lan8032)
35f8a34fc4SSuryakanth Sekar         {
36f8a34fc4SSuryakanth Sekar             if (getInterfaceIndex() == ch)
37f8a34fc4SSuryakanth Sekar             {
38f8a34fc4SSuryakanth Sekar                 ipmiNetworkInstance = index;
39f8a34fc4SSuryakanth Sekar             }
40f8a34fc4SSuryakanth Sekar 
41f8a34fc4SSuryakanth Sekar             ipmiNetworkChannelNumList[index] = ch;
42f8a34fc4SSuryakanth Sekar             index++;
43f8a34fc4SSuryakanth Sekar         }
44f8a34fc4SSuryakanth Sekar         ch++;
45f8a34fc4SSuryakanth Sekar     }
46f8a34fc4SSuryakanth Sekar }
47f8a34fc4SSuryakanth Sekar 
getNetworkInstance(void)48f8a34fc4SSuryakanth Sekar uint8_t Manager::getNetworkInstance(void)
49f8a34fc4SSuryakanth Sekar {
50f8a34fc4SSuryakanth Sekar     return ipmiNetworkInstance;
51f8a34fc4SSuryakanth Sekar }
52f8a34fc4SSuryakanth Sekar 
managerInit(const std::string & channel)53f8a34fc4SSuryakanth Sekar void Manager::managerInit(const std::string& channel)
54f8a34fc4SSuryakanth Sekar {
553e61aa0dSTom Joseph     /*
563e61aa0dSTom Joseph      * Session ID is 0000_0000h for messages that are sent outside the session.
573e61aa0dSTom Joseph      * The session setup commands are sent on this session, so when the session
583e61aa0dSTom Joseph      * manager comes up, is creates the Session ID  0000_0000h. It is active
593e61aa0dSTom Joseph      * through the lifetime of the Session Manager.
603e61aa0dSTom Joseph      */
61f8a34fc4SSuryakanth Sekar 
620a59062cSPatrick Williams     objManager = std::make_unique<sdbusplus::server::manager_t>(
63f8a34fc4SSuryakanth Sekar         *getSdBus(), session::sessionManagerRootPath);
64f8a34fc4SSuryakanth Sekar 
65099fb097SPatrick Williams     auto objPath = std::string(session::sessionManagerRootPath) + "/" +
66099fb097SPatrick Williams                    channel + "/0";
67f8a34fc4SSuryakanth Sekar 
68f8a34fc4SSuryakanth Sekar     chName = channel;
69f8a34fc4SSuryakanth Sekar     setNetworkInstance();
70f8a34fc4SSuryakanth Sekar     sessionsMap.emplace(
71f8a34fc4SSuryakanth Sekar         0, std::make_shared<Session>(*getSdBus(), objPath.c_str(), 0, 0, 0));
72ecc8efadSVernon Mauery 
73ecc8efadSVernon Mauery     // set up the timer for clearing out stale sessions
74ecc8efadSVernon Mauery     scheduleSessionCleaner(std::chrono::microseconds(3 * 1000 * 1000));
753e61aa0dSTom Joseph }
763e61aa0dSTom Joseph 
startSession(SessionID remoteConsoleSessID,Privilege priv,cipher::rakp_auth::Algorithms authAlgo,cipher::integrity::Algorithms intAlgo,cipher::crypt::Algorithms cryptAlgo)77*8425624aSPatrick Williams std::shared_ptr<Session> Manager::startSession(
78*8425624aSPatrick Williams     SessionID remoteConsoleSessID, Privilege priv,
799e801a2bSVernon Mauery     cipher::rakp_auth::Algorithms authAlgo,
80*8425624aSPatrick Williams     cipher::integrity::Algorithms intAlgo, cipher::crypt::Algorithms cryptAlgo)
813e61aa0dSTom Joseph {
823e61aa0dSTom Joseph     std::shared_ptr<Session> session = nullptr;
83f8a34fc4SSuryakanth Sekar     SessionID bmcSessionID = 0;
843e61aa0dSTom Joseph     cleanStaleEntries();
852528dfbdSVernon Mauery     // set up the timer for monitoring this session
862528dfbdSVernon Mauery     scheduleSessionCleaner(std::chrono::microseconds(1 * 1000 * 1000));
872528dfbdSVernon Mauery 
88f8a34fc4SSuryakanth Sekar     uint8_t sessionHandle = 0;
893e61aa0dSTom Joseph 
90f8a34fc4SSuryakanth Sekar     auto activeSessions = sessionsMap.size() - session::maxSessionlessCount;
91f8a34fc4SSuryakanth Sekar 
92ecc8efadSVernon Mauery     if (activeSessions < maxSessionHandles)
933e61aa0dSTom Joseph     {
943e61aa0dSTom Joseph         do
953e61aa0dSTom Joseph         {
96f8a34fc4SSuryakanth Sekar             bmcSessionID = (crypto::prng::rand());
97f8a34fc4SSuryakanth Sekar             bmcSessionID &= session::multiIntfaceSessionIDMask;
98f8a34fc4SSuryakanth Sekar             // In sessionID , BIT 31 BIT30 are used for netipmid instance
9902d17e83SP Dheeraj Srujan Kumar             bmcSessionID |= static_cast<uint32_t>(ipmiNetworkInstance) << 30;
1003e61aa0dSTom Joseph             /*
1013e61aa0dSTom Joseph              * Every IPMI Session has two ID's attached to it Remote Console
1023e61aa0dSTom Joseph              * Session ID and BMC Session ID. The remote console ID is passed
1033e61aa0dSTom Joseph              * along with the Open Session request command. The BMC session ID
1043e61aa0dSTom Joseph              * is the key for the session map and is generated using std::rand.
1053e61aa0dSTom Joseph              * There is a rare chance for collision of BMC session ID, so the
1063e61aa0dSTom Joseph              * following check validates that. In the case of collision the
10762ec622eSGunnar Mills              * created session is reset and a new session is created for
1083e61aa0dSTom Joseph              * validating collision.
1093e61aa0dSTom Joseph              */
110f8a34fc4SSuryakanth Sekar             auto iterator = sessionsMap.find(bmcSessionID);
1113e61aa0dSTom Joseph             if (iterator != sessionsMap.end())
1123e61aa0dSTom Joseph             {
1133e61aa0dSTom Joseph                 // Detected BMC Session ID collisions
1143e61aa0dSTom Joseph                 continue;
1153e61aa0dSTom Joseph             }
1163e61aa0dSTom Joseph             else
1173e61aa0dSTom Joseph             {
1183e61aa0dSTom Joseph                 break;
1193e61aa0dSTom Joseph             }
1209e801a2bSVernon Mauery         } while (1);
1213e61aa0dSTom Joseph 
122f8a34fc4SSuryakanth Sekar         sessionHandle = storeSessionHandle(bmcSessionID);
123f8a34fc4SSuryakanth Sekar 
124f8a34fc4SSuryakanth Sekar         if (!sessionHandle)
125f8a34fc4SSuryakanth Sekar         {
126f8a34fc4SSuryakanth Sekar             throw std::runtime_error(
127f8a34fc4SSuryakanth Sekar                 "Invalid sessionHandle - No sessionID slot ");
128f8a34fc4SSuryakanth Sekar         }
129f8a34fc4SSuryakanth Sekar         sessionHandle &= session::multiIntfaceSessionHandleMask;
130f8a34fc4SSuryakanth Sekar         // In sessionID , BIT 31 BIT30 are used for netipmid instance
13102d17e83SP Dheeraj Srujan Kumar         sessionHandle |= static_cast<uint8_t>(ipmiNetworkInstance) << 6;
132f8a34fc4SSuryakanth Sekar         std::stringstream sstream;
133f8a34fc4SSuryakanth Sekar         sstream << std::hex << bmcSessionID;
134f8a34fc4SSuryakanth Sekar         std::stringstream shstream;
135f8a34fc4SSuryakanth Sekar         shstream << std::hex << (int)sessionHandle;
136f8a34fc4SSuryakanth Sekar         auto objPath = std::string(session::sessionManagerRootPath) + "/" +
137f8a34fc4SSuryakanth Sekar                        chName + "/" + sstream.str() + "_" + shstream.str();
138f8a34fc4SSuryakanth Sekar         session = std::make_shared<Session>(*getSdBus(), objPath.c_str(),
139f8a34fc4SSuryakanth Sekar                                             remoteConsoleSessID, bmcSessionID,
140f8a34fc4SSuryakanth Sekar                                             static_cast<uint8_t>(priv));
141f8a34fc4SSuryakanth Sekar 
1429b307be6SVernon Mauery         // Set the Authentication Algorithm
1433e61aa0dSTom Joseph         switch (authAlgo)
1443e61aa0dSTom Joseph         {
1453e61aa0dSTom Joseph             case cipher::rakp_auth::Algorithms::RAKP_HMAC_SHA1:
1463e61aa0dSTom Joseph             {
1473e61aa0dSTom Joseph                 session->setAuthAlgo(
148ba11f792STom Joseph                     std::make_unique<cipher::rakp_auth::AlgoSHA1>(intAlgo,
149ba11f792STom Joseph                                                                   cryptAlgo));
1503e61aa0dSTom Joseph                 break;
1513e61aa0dSTom Joseph             }
1527e9e2ef6SVernon Mauery             case cipher::rakp_auth::Algorithms::RAKP_HMAC_SHA256:
1537e9e2ef6SVernon Mauery             {
1547e9e2ef6SVernon Mauery                 session->setAuthAlgo(
1559e801a2bSVernon Mauery                     std::make_unique<cipher::rakp_auth::AlgoSHA256>(intAlgo,
1569e801a2bSVernon Mauery                                                                     cryptAlgo));
1577e9e2ef6SVernon Mauery                 break;
1587e9e2ef6SVernon Mauery             }
1593e61aa0dSTom Joseph             default:
1603e61aa0dSTom Joseph             {
1613e61aa0dSTom Joseph                 throw std::runtime_error("Invalid Authentication Algorithm");
1623e61aa0dSTom Joseph             }
1633e61aa0dSTom Joseph         }
164f8a34fc4SSuryakanth Sekar 
165f8a34fc4SSuryakanth Sekar         sessionsMap.emplace(bmcSessionID, session);
166f8a34fc4SSuryakanth Sekar         session->sessionHandle(sessionHandle);
167f8a34fc4SSuryakanth Sekar 
1684cb73595SVernon Mauery         return session;
1693e61aa0dSTom Joseph     }
1704cb73595SVernon Mauery 
1717b7f25f7SGeorge Liu     lg2::info("No free RMCP+ sessions left");
1723e61aa0dSTom Joseph 
1733e61aa0dSTom Joseph     throw std::runtime_error("No free sessions left");
1743e61aa0dSTom Joseph }
1753e61aa0dSTom Joseph 
stopSession(SessionID bmcSessionID)1769662c3a9STom Joseph bool Manager::stopSession(SessionID bmcSessionID)
1773e61aa0dSTom Joseph {
1783e61aa0dSTom Joseph     auto iter = sessionsMap.find(bmcSessionID);
1793e61aa0dSTom Joseph     if (iter != sessionsMap.end())
1803e61aa0dSTom Joseph     {
181f8a34fc4SSuryakanth Sekar         iter->second->state(
182f8a34fc4SSuryakanth Sekar             static_cast<uint8_t>(session::State::tearDownInProgress));
1839662c3a9STom Joseph         return true;
1843e61aa0dSTom Joseph     }
1859662c3a9STom Joseph     else
1869662c3a9STom Joseph     {
1879662c3a9STom Joseph         return false;
1883e61aa0dSTom Joseph     }
1893e61aa0dSTom Joseph }
1903e61aa0dSTom Joseph 
191*8425624aSPatrick Williams std::shared_ptr<Session>
getSession(SessionID sessionID,RetrieveOption option)192*8425624aSPatrick Williams     Manager::getSession(SessionID sessionID, RetrieveOption option)
1933e61aa0dSTom Joseph {
1943e61aa0dSTom Joseph     switch (option)
1953e61aa0dSTom Joseph     {
1963e61aa0dSTom Joseph         case RetrieveOption::BMC_SESSION_ID:
1973e61aa0dSTom Joseph         {
1983e61aa0dSTom Joseph             auto iter = sessionsMap.find(sessionID);
1993e61aa0dSTom Joseph             if (iter != sessionsMap.end())
2003e61aa0dSTom Joseph             {
2013e61aa0dSTom Joseph                 return iter->second;
2023e61aa0dSTom Joseph             }
2036516cef4STom Joseph             break;
2043e61aa0dSTom Joseph         }
2053e61aa0dSTom Joseph         case RetrieveOption::RC_SESSION_ID:
2063e61aa0dSTom Joseph         {
2079e801a2bSVernon Mauery             auto iter = std::find_if(
2089e801a2bSVernon Mauery                 sessionsMap.begin(), sessionsMap.end(),
2099e801a2bSVernon Mauery                 [sessionID](
2109e801a2bSVernon Mauery                     const std::pair<const uint32_t, std::shared_ptr<Session>>&
2119e801a2bSVernon Mauery                         in) -> bool {
2123e61aa0dSTom Joseph                     return sessionID == in.second->getRCSessionID();
2133e61aa0dSTom Joseph                 });
2143e61aa0dSTom Joseph 
2153e61aa0dSTom Joseph             if (iter != sessionsMap.end())
2163e61aa0dSTom Joseph             {
2173e61aa0dSTom Joseph                 return iter->second;
2183e61aa0dSTom Joseph             }
2196516cef4STom Joseph             break;
2203e61aa0dSTom Joseph         }
2213e61aa0dSTom Joseph         default:
2223e61aa0dSTom Joseph             throw std::runtime_error("Invalid retrieval option");
2233e61aa0dSTom Joseph     }
2243e61aa0dSTom Joseph 
2253e61aa0dSTom Joseph     throw std::runtime_error("Session ID not found");
2263e61aa0dSTom Joseph }
2273e61aa0dSTom Joseph 
cleanStaleEntries()2283e61aa0dSTom Joseph void Manager::cleanStaleEntries()
2293e61aa0dSTom Joseph {
230ecc8efadSVernon Mauery     // with overflow = min(1, max - active sessions)
231ecc8efadSVernon Mauery     // active idle time in seconds = 60 / overflow^3
232ecc8efadSVernon Mauery     constexpr int baseIdleMicros = 60 * 1000 * 1000;
233ecc8efadSVernon Mauery     // no +1 for the zero session here because this is just active sessions
234*8425624aSPatrick Williams     int sessionDivisor =
235*8425624aSPatrick Williams         getActiveSessionCount() - session::maxSessionCountPerChannel;
236ecc8efadSVernon Mauery     sessionDivisor = std::max(0, sessionDivisor) + 1;
237ecc8efadSVernon Mauery     sessionDivisor = sessionDivisor * sessionDivisor * sessionDivisor;
238ecc8efadSVernon Mauery     int activeMicros = baseIdleMicros / sessionDivisor;
239ecc8efadSVernon Mauery 
240ecc8efadSVernon Mauery     // with overflow = min(1, max - total sessions)
241ecc8efadSVernon Mauery     // setup idle time in seconds = max(3, 60 / overflow^3)
242ecc8efadSVernon Mauery 
243ecc8efadSVernon Mauery     // +1 for the zero session here because size() counts that too
244*8425624aSPatrick Williams     int setupDivisor =
245*8425624aSPatrick Williams         sessionsMap.size() - (session::maxSessionCountPerChannel + 1);
246ecc8efadSVernon Mauery     setupDivisor = std::max(0, setupDivisor) + 1;
247ecc8efadSVernon Mauery     setupDivisor = setupDivisor * setupDivisor * setupDivisor;
248ecc8efadSVernon Mauery     constexpr int maxSetupMicros = 3 * 1000 * 1000;
249ecc8efadSVernon Mauery     int setupMicros = std::min(maxSetupMicros, baseIdleMicros / setupDivisor);
250ecc8efadSVernon Mauery 
251ecc8efadSVernon Mauery     std::chrono::microseconds activeGrace(activeMicros);
252ecc8efadSVernon Mauery     std::chrono::microseconds setupGrace(setupMicros);
253ecc8efadSVernon Mauery 
2543e61aa0dSTom Joseph     for (auto iter = sessionsMap.begin(); iter != sessionsMap.end();)
2553e61aa0dSTom Joseph     {
2563e61aa0dSTom Joseph         auto session = iter->second;
257ecc8efadSVernon Mauery         // special handling for sessionZero
258ecc8efadSVernon Mauery         if (session->getBMCSessionID() == session::sessionZero)
259ecc8efadSVernon Mauery         {
260ecc8efadSVernon Mauery             iter++;
261ecc8efadSVernon Mauery             continue;
262ecc8efadSVernon Mauery         }
263ecc8efadSVernon Mauery         if (!(session->isSessionActive(activeGrace, setupGrace)))
2643e61aa0dSTom Joseph         {
2657b7f25f7SGeorge Liu             lg2::info(
2667b7f25f7SGeorge Liu                 "Removing idle IPMI LAN session, id: {ID}, handler: {HANDLE}",
2677b7f25f7SGeorge Liu                 "ID", session->getBMCSessionID(), "HANDLE",
2687b7f25f7SGeorge Liu                 getSessionHandle(session->getBMCSessionID()));
269f8a34fc4SSuryakanth Sekar             sessionHandleMap[getSessionHandle(session->getBMCSessionID())] = 0;
2703e61aa0dSTom Joseph             iter = sessionsMap.erase(iter);
2713e61aa0dSTom Joseph         }
2723e61aa0dSTom Joseph         else
2733e61aa0dSTom Joseph         {
274ecc8efadSVernon Mauery             iter++;
2753e61aa0dSTom Joseph         }
2763e61aa0dSTom Joseph     }
277ecc8efadSVernon Mauery     if (sessionsMap.size() > 1)
278ecc8efadSVernon Mauery     {
2792528dfbdSVernon Mauery         constexpr int maxCleanupDelay = 1 * 1000 * 1000;
2802528dfbdSVernon Mauery         std::chrono::microseconds cleanupDelay(
2812528dfbdSVernon Mauery             std::min(setupMicros, maxCleanupDelay));
2822528dfbdSVernon Mauery         scheduleSessionCleaner(cleanupDelay);
283ecc8efadSVernon Mauery     }
2843e61aa0dSTom Joseph }
2853e61aa0dSTom Joseph 
storeSessionHandle(SessionID bmcSessionID)286f8a34fc4SSuryakanth Sekar uint8_t Manager::storeSessionHandle(SessionID bmcSessionID)
287f8a34fc4SSuryakanth Sekar {
288f8a34fc4SSuryakanth Sekar     // Handler index 0 is  reserved for invalid session.
289f8a34fc4SSuryakanth Sekar     // index starts with 1, for direct usage. Index 0 reserved
290ecc8efadSVernon Mauery     for (size_t i = 1; i < session::maxSessionHandles; i++)
291f8a34fc4SSuryakanth Sekar     {
292f8a34fc4SSuryakanth Sekar         if (sessionHandleMap[i] == 0)
293f8a34fc4SSuryakanth Sekar         {
294f8a34fc4SSuryakanth Sekar             sessionHandleMap[i] = bmcSessionID;
295f8a34fc4SSuryakanth Sekar             return i;
296f8a34fc4SSuryakanth Sekar         }
297f8a34fc4SSuryakanth Sekar     }
298f8a34fc4SSuryakanth Sekar     return 0;
299f8a34fc4SSuryakanth Sekar }
300f8a34fc4SSuryakanth Sekar 
getSessionIDbyHandle(uint8_t sessionHandle) const301f8a34fc4SSuryakanth Sekar uint32_t Manager::getSessionIDbyHandle(uint8_t sessionHandle) const
302f8a34fc4SSuryakanth Sekar {
303ecc8efadSVernon Mauery     if (sessionHandle < session::maxSessionHandles)
304f8a34fc4SSuryakanth Sekar     {
305f8a34fc4SSuryakanth Sekar         return sessionHandleMap[sessionHandle];
306f8a34fc4SSuryakanth Sekar     }
307f8a34fc4SSuryakanth Sekar     return 0;
308f8a34fc4SSuryakanth Sekar }
309f8a34fc4SSuryakanth Sekar 
getSessionHandle(SessionID bmcSessionID) const310f8a34fc4SSuryakanth Sekar uint8_t Manager::getSessionHandle(SessionID bmcSessionID) const
311f8a34fc4SSuryakanth Sekar {
312f8a34fc4SSuryakanth Sekar     // Handler index 0 is reserved for invalid session.
313f8a34fc4SSuryakanth Sekar     // index starts with 1, for direct usage. Index 0 reserved
314ecc8efadSVernon Mauery     for (size_t i = 1; i < session::maxSessionHandles; i++)
315f8a34fc4SSuryakanth Sekar     {
316f8a34fc4SSuryakanth Sekar         if (sessionHandleMap[i] == bmcSessionID)
317f8a34fc4SSuryakanth Sekar         {
318f8a34fc4SSuryakanth Sekar             return (i);
319f8a34fc4SSuryakanth Sekar         }
320f8a34fc4SSuryakanth Sekar     }
321f8a34fc4SSuryakanth Sekar     return 0;
322f8a34fc4SSuryakanth Sekar }
getActiveSessionCount() const323f8a34fc4SSuryakanth Sekar uint8_t Manager::getActiveSessionCount() const
324f8a34fc4SSuryakanth Sekar {
325f8a34fc4SSuryakanth Sekar     return (std::count_if(
326f8a34fc4SSuryakanth Sekar         sessionsMap.begin(), sessionsMap.end(),
327f8a34fc4SSuryakanth Sekar         [](const std::pair<const uint32_t, std::shared_ptr<Session>>& in)
328f8a34fc4SSuryakanth Sekar             -> bool {
329f8a34fc4SSuryakanth Sekar             return in.second->state() ==
330f8a34fc4SSuryakanth Sekar                    static_cast<uint8_t>(session::State::active);
331f8a34fc4SSuryakanth Sekar         }));
332f8a34fc4SSuryakanth Sekar }
333ecc8efadSVernon Mauery 
scheduleSessionCleaner(const std::chrono::microseconds & when)334ecc8efadSVernon Mauery void Manager::scheduleSessionCleaner(const std::chrono::microseconds& when)
335ecc8efadSVernon Mauery {
3366d206811SEd Tanous     std::chrono::duration expTime =
3376d206811SEd Tanous         timer.expiry() - boost::asio::steady_timer::clock_type::now();
3382528dfbdSVernon Mauery     if (expTime > std::chrono::microseconds(0) && expTime < when)
3392528dfbdSVernon Mauery     {
340bc8958feSGeorge Liu         // if timer has not already expired AND requested timeout is greater
341bc8958feSGeorge Liu         // than current timeout then ignore this new requested timeout
3422528dfbdSVernon Mauery         return;
3432528dfbdSVernon Mauery     }
3446d206811SEd Tanous     timer.expires_after(when);
345ecc8efadSVernon Mauery     timer.async_wait([this](const boost::system::error_code& ec) {
346ecc8efadSVernon Mauery         if (!ec)
347ecc8efadSVernon Mauery         {
348ecc8efadSVernon Mauery             cleanStaleEntries();
349ecc8efadSVernon Mauery         }
350ecc8efadSVernon Mauery     });
351ecc8efadSVernon Mauery }
352ecc8efadSVernon Mauery 
3533e61aa0dSTom Joseph } // namespace session
354