netipmid: move sol timers to asio
The IPMI SOL console was using sd_event-based timers directly (without
any abstraction). This moves to a much higher level abstraction that is
very easy to use: asio timers.
Change-Id: Id5df76a1918cdfae420e01884d664234810b7abd
Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
diff --git a/sol/sol_context.cpp b/sol/sol_context.cpp
index fffb66f..215f725 100644
--- a/sol/sol_context.cpp
+++ b/sol/sol_context.cpp
@@ -8,9 +8,62 @@
namespace sol
{
-
using namespace phosphor::logging;
+Context::Context(std::shared_ptr<boost::asio::io_context> io,
+ uint8_t maxRetryCount, uint8_t sendThreshold, uint8_t instance,
+ session::SessionID sessionID) :
+ accumulateTimer(*io),
+ retryTimer(*io), maxRetryCount(maxRetryCount), retryCounter(maxRetryCount),
+ sendThreshold(sendThreshold), payloadInstance(instance),
+ sessionID(sessionID)
+{
+ session = std::get<session::Manager&>(singletonPool).getSession(sessionID);
+ enableAccumulateTimer(true);
+}
+
+void Context::enableAccumulateTimer(bool enable)
+{
+ // fetch the timeout from the SOL manager
+ std::chrono::microseconds interval =
+ std::get<sol::Manager&>(singletonPool).accumulateInterval;
+ if (enable)
+ {
+ accumulateTimer.expires_after(interval);
+ accumulateTimer.async_wait([this](const boost::system::error_code& ec) {
+ if (!ec)
+ {
+ charAccTimerHandler();
+ }
+ });
+ }
+ else
+ {
+ accumulateTimer.cancel();
+ }
+}
+
+void Context::enableRetryTimer(bool enable)
+{
+ if (enable)
+ {
+ // fetch the timeout from the SOL manager
+ std::chrono::microseconds interval =
+ std::get<sol::Manager&>(singletonPool).retryInterval;
+ retryTimer.expires_after(interval);
+ retryTimer.async_wait([this](const boost::system::error_code& ec) {
+ if (!ec)
+ {
+ retryTimerHandler();
+ }
+ });
+ }
+ else
+ {
+ retryTimer.cancel();
+ }
+}
+
void Context::processInboundPayload(uint8_t seqNum, uint8_t ackSeqNum,
uint8_t count, bool status,
const std::vector<uint8_t>& input)
@@ -54,10 +107,8 @@
if (status || ((count != expectedCharCount) && ackSeqNum))
{
resendPayload(noClear);
- std::get<eventloop::EventLoop&>(singletonPool)
- .switchTimer(payloadInstance, eventloop::Timers::RETRY, false);
- std::get<eventloop::EventLoop&>(singletonPool)
- .switchTimer(payloadInstance, eventloop::Timers::RETRY, true);
+ enableRetryTimer(false);
+ enableRetryTimer(true);
return;
}
/*
@@ -70,8 +121,7 @@
std::get<sol::Manager&>(singletonPool).dataBuffer.erase(count);
// Once it is acknowledged stop the retry interval timer
- std::get<eventloop::EventLoop&>(singletonPool)
- .switchTimer(payloadInstance, eventloop::Timers::RETRY, false);
+ enableRetryTimer(false);
retryCounter = maxRetryCount;
expectedCharCount = 0;
@@ -111,8 +161,7 @@
}
else
{
- std::get<eventloop::EventLoop&>(singletonPool)
- .switchTimer(payloadInstance, eventloop::Timers::ACCUMULATE, true);
+ enableAccumulateTimer(true);
}
}
@@ -123,8 +172,7 @@
/* Sent a ACK only response */
if (payloadCache.size() != 0 || (bufferSize < sendThreshold))
{
- std::get<eventloop::EventLoop&>(singletonPool)
- .switchTimer(payloadInstance, eventloop::Timers::ACCUMULATE, true);
+ enableAccumulateTimer(true);
std::vector<uint8_t> outPayload(sizeof(Payload));
auto response = reinterpret_cast<Payload*>(outPayload.data());
@@ -148,10 +196,8 @@
std::copy_n(handle, readSize, payloadCache.data() + sizeof(Payload));
expectedCharCount = readSize;
- std::get<eventloop::EventLoop&>(singletonPool)
- .switchTimer(payloadInstance, eventloop::Timers::RETRY, true);
- std::get<eventloop::EventLoop&>(singletonPool)
- .switchTimer(payloadInstance, eventloop::Timers::ACCUMULATE, false);
+ enableRetryTimer(true);
+ enableAccumulateTimer(false);
sendPayload(payloadCache);
}
@@ -160,8 +206,7 @@
{
if (payloadCache.size() != 0)
{
- std::get<eventloop::EventLoop&>(singletonPool)
- .switchTimer(payloadInstance, eventloop::Timers::ACCUMULATE, true);
+ enableAccumulateTimer(true);
return -1;
}
@@ -179,10 +224,8 @@
std::copy_n(handle, readSize, payloadCache.data() + sizeof(Payload));
expectedCharCount = readSize;
- std::get<eventloop::EventLoop&>(singletonPool)
- .switchTimer(payloadInstance, eventloop::Timers::RETRY, true);
- std::get<eventloop::EventLoop&>(singletonPool)
- .switchTimer(payloadInstance, eventloop::Timers::ACCUMULATE, false);
+ enableRetryTimer(true);
+ enableAccumulateTimer(false);
sendPayload(payloadCache);
@@ -204,12 +247,54 @@
void Context::sendPayload(const std::vector<uint8_t>& out) const
{
- auto session =
- std::get<session::Manager&>(singletonPool).getSession(sessionID);
-
message::Handler msgHandler(session->channelPtr, sessionID);
msgHandler.sendSOLPayload(out);
}
+void Context::charAccTimerHandler()
+{
+ auto bufferSize = std::get<sol::Manager&>(singletonPool).dataBuffer.size();
+
+ try
+ {
+ if (bufferSize > 0)
+ {
+ int rc = sendOutboundPayload();
+ if (rc == 0)
+ {
+ return;
+ }
+ }
+ enableAccumulateTimer(true);
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>(e.what());
+ }
+}
+
+void Context::retryTimerHandler()
+{
+ try
+ {
+ if (retryCounter)
+ {
+ --retryCounter;
+ enableRetryTimer(true);
+ resendPayload(sol::Context::noClear);
+ }
+ else
+ {
+ retryCounter = maxRetryCount;
+ resendPayload(sol::Context::clear);
+ enableRetryTimer(false);
+ enableAccumulateTimer(true);
+ }
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>(e.what());
+ }
+}
} // namespace sol
diff --git a/sol/sol_context.hpp b/sol/sol_context.hpp
index 220040b..8d0fc87 100644
--- a/sol/sol_context.hpp
+++ b/sol/sol_context.hpp
@@ -3,6 +3,9 @@
#include "console_buffer.hpp"
#include "session.hpp"
+#include <boost/asio/io_context.hpp>
+#include <boost/asio/steady_timer.hpp>
+
namespace sol
{
@@ -149,34 +152,37 @@
class Context
{
public:
- Context() = default;
+ Context() = delete;
~Context() = default;
Context(const Context&) = delete;
Context& operator=(const Context&) = delete;
- Context(Context&&) = default;
- Context& operator=(Context&&) = default;
+ Context(Context&&) = delete;
+ Context& operator=(Context&&) = delete;
/** @brief Context Constructor.
*
* This is issued by the SOL Manager when a SOL payload instance is
* started for the activate payload command.
*
+ * @param[in] io - boost::asio io context for event scheduling.
* @param[in] maxRetryCount - Retry count max value.
* @param[in] sendThreshold - Character send threshold.
* @param[in] instance - SOL payload instance.
* @param[in] sessionID - BMC session ID.
*/
- Context(uint8_t maxRetryCount, uint8_t sendThreshold, uint8_t instance,
- session::SessionID sessionID) :
- maxRetryCount(maxRetryCount),
- retryCounter(maxRetryCount), sendThreshold(sendThreshold),
- payloadInstance(instance), sessionID(sessionID)
- {
- }
+ Context(std::shared_ptr<boost::asio::io_context> io, uint8_t maxRetryCount,
+ uint8_t sendThreshold, uint8_t instance,
+ session::SessionID sessionID);
static constexpr auto clear = true;
static constexpr auto noClear = false;
+ /** @brief accumulate timer */
+ boost::asio::steady_timer accumulateTimer;
+
+ /** @brief retry timer */
+ boost::asio::steady_timer retryTimer;
+
/** @brief Retry count max value. */
const uint8_t maxRetryCount = 0;
@@ -192,6 +198,28 @@
/** @brief Session ID. */
const session::SessionID sessionID = 0;
+ /** @brief session pointer
+ */
+ std::shared_ptr<session::Session> session;
+
+ /** @brief enable/disable accumulate timer
+ *
+ * The timeout interval is managed by the SOL Manager;
+ * this function only enables or disable the timer
+ *
+ * @param[in] enable - enable(true) or disable(false) accumulation timer
+ */
+ void enableAccumulateTimer(bool enable);
+
+ /** @brief enable/disable retry timer
+ *
+ * The timeout interval is managed by the SOL Manager;
+ * this function only enables or disable the timer
+ *
+ * @param[in] enable - enable(true) or disable(false) retry timer
+ */
+ void enableRetryTimer(bool enable);
+
/** @brief Process the Inbound SOL payload.
*
* The SOL payload from the remote console is processed and the
@@ -253,6 +281,12 @@
* @param[in] out - buffer containing the SOL payload.
*/
void sendPayload(const std::vector<uint8_t>& out) const;
+
+ /** @brief accumlate timer handler called by timer */
+ void charAccTimerHandler();
+
+ /** @brief retry timer handler called by timer */
+ void retryTimerHandler();
};
} // namespace sol
diff --git a/sol/sol_manager.cpp b/sol/sol_manager.cpp
index fc0efe9..2046fe4 100644
--- a/sol/sol_manager.cpp
+++ b/sol/sol_manager.cpp
@@ -102,16 +102,9 @@
}
// Create the SOL Context data for payload instance
- auto context = std::make_unique<Context>(retryCount, sendThreshold,
+ auto context = std::make_unique<Context>(io, retryCount, sendThreshold,
payloadInstance, sessionID);
- std::get<eventloop::EventLoop&>(singletonPool)
- .startSOLPayloadInstance(
- payloadInstance,
- std::chrono::duration_cast<eventloop::IntervalType>(
- accumulateInterval),
- std::chrono::duration_cast<eventloop::IntervalType>(retryInterval));
-
payloadMap.emplace(payloadInstance, std::move(context));
}
@@ -125,9 +118,6 @@
payloadMap.erase(iter);
- std::get<eventloop::EventLoop&>(singletonPool)
- .stopSOLPayloadInstance(payloadInstance);
-
if (payloadMap.empty())
{
stopHostConsole();