ipmid/handler: Support exceptions with completion codes
Handlers don't always have a clear way to propagate error codes up to
the top level ipmi executor logic. This change defines an exception they
can throw that will provide a message + code for the executor.
Change-Id: I5491111e4471910669ddba1c3f4469dc004232eb
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/include/ipmid/handler.hpp b/include/ipmid/handler.hpp
index b6c6c0f..3b40762 100644
--- a/include/ipmid/handler.hpp
+++ b/include/ipmid/handler.hpp
@@ -24,6 +24,7 @@
#include <memory>
#include <optional>
#include <phosphor-logging/log.hpp>
+#include <stdexcept>
#include <tuple>
#include <user_channel/channel_layer.hpp>
#include <utility>
@@ -54,6 +55,38 @@
return response;
}
+/** @brief Exception extension that allows setting an IPMI return code */
+class HandlerCompletion
+{
+ public:
+ HandlerCompletion(Cc cc) noexcept : cc(cc)
+ {
+ }
+
+ Cc code() const noexcept
+ {
+ return cc;
+ }
+
+ private:
+ Cc cc;
+};
+
+/** @brief Exception extension that allows setting an IPMI return code and
+ * printing out a logged error */
+class HandlerException : public HandlerCompletion, public std::runtime_error
+{
+ public:
+ HandlerException(Cc cc, const char* what) :
+ HandlerCompletion(cc), std::runtime_error(what)
+ {
+ }
+ HandlerException(Cc cc, const std::string& what) :
+ HandlerException(cc, what.c_str())
+ {
+ }
+};
+
/**
* @brief Handler base class for dealing with IPMI request/response
*
@@ -224,6 +257,16 @@
// ipmi::RspType<>
result = std::apply(handler_, *inputArgs);
}
+ catch (const HandlerException& e)
+ {
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "Handler produced exception",
+ phosphor::logging::entry("CC=%x", e.code()),
+ phosphor::logging::entry("EXCEPTION=%s", e.what()),
+ phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
+ phosphor::logging::entry("CMD=%x", request->ctx->cmd));
+ return errorResponse(request, e.code());
+ }
catch (const std::exception& e)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
@@ -233,6 +276,10 @@
phosphor::logging::entry("CMD=%x", request->ctx->cmd));
return errorResponse(request, ccUnspecifiedError);
}
+ catch (const HandlerCompletion& c)
+ {
+ return errorResponse(request, c.code());
+ }
catch (...)
{
std::exception_ptr eptr;
@@ -323,6 +370,16 @@
request->payload.data() + request->payload.rawIndex,
response->payload.data(), &len, handlerCtx);
}
+ catch (const HandlerException& e)
+ {
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "Legacy Handler produced exception",
+ phosphor::logging::entry("CC=%x", e.code()),
+ phosphor::logging::entry("EXCEPTION=%s", e.what()),
+ phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
+ phosphor::logging::entry("CMD=%x", request->ctx->cmd));
+ return errorResponse(request, e.code());
+ }
catch (const std::exception& e)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
@@ -332,6 +389,10 @@
phosphor::logging::entry("CMD=%x", request->ctx->cmd));
return errorResponse(request, ccUnspecifiedError);
}
+ catch (const HandlerCompletion& c)
+ {
+ return errorResponse(request, c.code());
+ }
catch (...)
{
std::exception_ptr eptr;
@@ -412,6 +473,16 @@
request->payload.data() + request->payload.rawIndex,
response->payload.data(), &len);
}
+ catch (const HandlerException& e)
+ {
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "Legacy OEM Handler produced exception",
+ phosphor::logging::entry("CC=%x", e.code()),
+ phosphor::logging::entry("EXCEPTION=%s", e.what()),
+ phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
+ phosphor::logging::entry("CMD=%x", request->ctx->cmd));
+ return errorResponse(request, e.code());
+ }
catch (const std::exception& e)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
@@ -421,6 +492,10 @@
phosphor::logging::entry("CMD=%x", request->ctx->cmd));
return errorResponse(request, ccUnspecifiedError);
}
+ catch (const HandlerCompletion& c)
+ {
+ return errorResponse(request, c.code());
+ }
catch (...)
{
std::exception_ptr eptr;