blob: 2a29f82ee7e0b352e60caec41998f80175e75fd6 [file] [log] [blame]
Deepak Kodihalli4de4d002019-11-11 02:41:43 -06001#pragma once
2
Andrew Jeffery4668f5c2024-01-15 14:59:17 +10303#include <libpldm/instance-id.h>
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +09304
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +09305#include <cerrno>
Andrew Jefferyda4b13c2023-04-28 12:56:20 +09306#include <cstdint>
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +09307#include <exception>
Eric Yang70262ed2025-07-02 06:35:03 +00008#include <expected>
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +09309#include <string>
10#include <system_error>
11
Deepak Kodihalli4de4d002019-11-11 02:41:43 -060012namespace pldm
13{
14
Eric Yang70262ed2025-07-02 06:35:03 +000015/**
16 * @class InstanceIdError
17 * @brief Exception for PLDM instance ID allocation and management errors.
18 */
19class InstanceIdError : public std::exception
20{
21 public:
22 InstanceIdError(const InstanceIdError&) noexcept = default;
23 InstanceIdError(InstanceIdError&&) noexcept = default;
24 InstanceIdError& operator=(const InstanceIdError&) noexcept = default;
25 InstanceIdError& operator=(InstanceIdError&&) noexcept = default;
26 ~InstanceIdError() noexcept override = default;
27
28 /** @brief Construct with an error code. */
29 explicit InstanceIdError(int rc) : rc_(rc), msg_(rcToMsg(rc)) {}
30
31 /** @brief Construct with an error code and a string message (copied). */
32 InstanceIdError(int rc, const std::string& m) : rc_(rc), msg_(m) {}
33
34 /** @brief Construct with an error code and a string message (moved). */
35 InstanceIdError(int rc, std::string&& m) : rc_(rc), msg_(std::move(m)) {}
36
37 /** @brief Get the error code. */
38 int rc() const noexcept
39 {
40 return rc_;
41 }
42
43 /** @brief Get the error message. */
44 const std::string& msg() const noexcept
45 {
46 return msg_;
47 }
48
49 /** @brief Convert an error code to a message. */
50 static std::string rcToMsg(int rc)
51 {
52 switch (rc)
53 {
54 case -EAGAIN:
55 return "No free instance ids";
56 default:
57 return std::system_category().message(rc);
58 }
59 }
60
61 /** @brief Get the error message (for std::exception). */
62 const char* what() const noexcept override
63 {
64 return msg_.c_str();
65 }
66
67 private:
68 int rc_;
69 std::string msg_;
70};
71
Deepak Kodihalli4de4d002019-11-11 02:41:43 -060072/** @class InstanceId
73 * @brief Implementation of PLDM instance id as per DSP0240 v1.0.0
74 */
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +093075class InstanceIdDb
Deepak Kodihalli4de4d002019-11-11 02:41:43 -060076{
77 public:
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +093078 InstanceIdDb()
79 {
80 int rc = pldm_instance_db_init_default(&pldmInstanceIdDb);
81 if (rc)
82 {
83 throw std::system_category().default_error_condition(rc);
84 }
85 }
86
87 /** @brief Constructor
88 *
89 * @param[in] path - instance ID database path
Deepak Kodihalli4de4d002019-11-11 02:41:43 -060090 */
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +093091 InstanceIdDb(const std::string& path)
92 {
93 int rc = pldm_instance_db_init(&pldmInstanceIdDb, path.c_str());
94 if (rc)
95 {
96 throw std::system_category().default_error_condition(rc);
97 }
98 }
99
100 ~InstanceIdDb()
101 {
Andrew Jeffery68a525e2023-10-18 10:09:33 +1030102 /*
103 * Abandon error-reporting. We shouldn't throw an exception from the
104 * destructor, and the class has multiple consumers using incompatible
105 * logging strategies.
106 *
107 * Broadly, it should be possible to use strace to investigate.
108 */
109 pldm_instance_db_destroy(pldmInstanceIdDb);
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +0930110 }
111
112 /** @brief Allocate an instance ID for the given terminus
113 * @param[in] tid - the terminus ID the instance ID is associated with
Eric Yang70262ed2025-07-02 06:35:03 +0000114 * @return - PLDM instance id on success, or InstanceIdError on failure
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +0930115 */
Eric Yang70262ed2025-07-02 06:35:03 +0000116 std::expected<uint8_t, InstanceIdError> next(uint8_t tid)
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +0930117 {
118 uint8_t id;
119 int rc = pldm_instance_id_alloc(pldmInstanceIdDb, tid, &id);
120
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +0930121 if (rc)
122 {
Eric Yang70262ed2025-07-02 06:35:03 +0000123 return std::unexpected(
124 InstanceIdError{rc, "Failed to allocate instance ID for EID " +
125 std::to_string(tid) + ": " +
126 InstanceIdError::rcToMsg(rc)});
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +0930127 }
128
129 return id;
130 }
Deepak Kodihalli4de4d002019-11-11 02:41:43 -0600131
132 /** @brief Mark an instance id as unused
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +0930133 * @param[in] tid - the terminus ID the instance ID is associated with
Deepak Kodihalli4de4d002019-11-11 02:41:43 -0600134 * @param[in] instanceId - PLDM instance id to be freed
135 */
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +0930136 void free(uint8_t tid, uint8_t instanceId)
Deepak Kodihalli4de4d002019-11-11 02:41:43 -0600137 {
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +0930138 int rc = pldm_instance_id_free(pldmInstanceIdDb, tid, instanceId);
139 if (rc == -EINVAL)
140 {
Rashmica Guptaf4117422023-05-16 09:46:58 +1000141 throw std::runtime_error(
142 "Instance ID " + std::to_string(instanceId) + " for TID " +
143 std::to_string(tid) + " was not previously allocated");
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +0930144 }
145 if (rc)
146 {
147 throw std::system_category().default_error_condition(rc);
148 }
Deepak Kodihalli4de4d002019-11-11 02:41:43 -0600149 }
150
151 private:
Rashmica Guptaf4117422023-05-16 09:46:58 +1000152 pldm_instance_db* pldmInstanceIdDb = nullptr;
Deepak Kodihalli4de4d002019-11-11 02:41:43 -0600153};
154
155} // namespace pldm