blob: 24e6942b1771f8db53ce1506c269dad3052685e5 [file] [log] [blame]
Tom Joseph74f27c72021-05-16 07:58:53 -07001#pragma once
2
3#include "libpldm/base.h"
4#include "libpldm/requester/pldm.h"
5
6#include "common/types.hpp"
Tom Josephe5268cd2021-09-07 13:04:03 +05307#include "common/utils.hpp"
Tom Joseph74f27c72021-05-16 07:58:53 -07008
9#include <sdbusplus/timer.hpp>
10#include <sdeventplus/event.hpp>
11
12#include <chrono>
13#include <functional>
14#include <iostream>
15
16namespace pldm
17{
18
19namespace requester
20{
21
Tom Joseph74f27c72021-05-16 07:58:53 -070022/** @class RequestRetryTimer
23 *
24 * The abstract base class for implementing the PLDM request retry logic. This
25 * class handles number of times the PLDM request needs to be retried if the
26 * response is not received and the time to wait between each retry. It
27 * provides APIs to start and stop the request flow.
28 */
29class RequestRetryTimer
30{
31 public:
32 RequestRetryTimer() = delete;
33 RequestRetryTimer(const RequestRetryTimer&) = delete;
34 RequestRetryTimer(RequestRetryTimer&&) = default;
35 RequestRetryTimer& operator=(const RequestRetryTimer&) = delete;
36 RequestRetryTimer& operator=(RequestRetryTimer&&) = default;
37 virtual ~RequestRetryTimer() = default;
38
39 /** @brief Constructor
40 *
41 * @param[in] event - reference to PLDM daemon's main event loop
42 * @param[in] numRetries - number of request retries
43 * @param[in] timeout - time to wait between each retry in milliseconds
44 */
45 explicit RequestRetryTimer(sdeventplus::Event& event, uint8_t numRetries,
Brad Bishop5079ac42021-08-19 18:35:06 -040046 std::chrono::milliseconds timeout) :
Tom Joseph74f27c72021-05-16 07:58:53 -070047
48 event(event),
49 numRetries(numRetries), timeout(timeout),
50 timer(event.get(), std::bind_front(&RequestRetryTimer::callback, this))
51 {}
52
53 /** @brief Starts the request flow and arms the timer for request retries
54 *
55 * @return return PLDM_SUCCESS on success and PLDM_ERROR otherwise
56 */
57 int start()
58 {
59 auto rc = send();
Tom Josepha5ed6582021-06-17 22:08:47 -070060 if (rc)
Tom Joseph74f27c72021-05-16 07:58:53 -070061 {
62 return rc;
63 }
64
65 try
66 {
67 if (numRetries)
68 {
Brad Bishop5079ac42021-08-19 18:35:06 -040069 timer.start(duration_cast<std::chrono::microseconds>(timeout),
70 true);
Tom Joseph74f27c72021-05-16 07:58:53 -070071 }
72 }
73 catch (const std::runtime_error& e)
74 {
75 std::cerr << "Failed to start the request timer. RC = " << e.what()
76 << "\n";
77 return PLDM_ERROR;
78 }
79
80 return PLDM_SUCCESS;
81 }
82
83 /** @brief Stops the timer and no further request retries happen */
84 void stop()
85 {
86 auto rc = timer.stop();
87 if (rc)
88 {
89 std::cerr << "Failed to stop the request timer. RC = " << rc
90 << "\n";
91 }
92 }
93
94 protected:
95 sdeventplus::Event& event; //!< reference to PLDM daemon's main event loop
96 uint8_t numRetries; //!< number of request retries
Brad Bishop5079ac42021-08-19 18:35:06 -040097 std::chrono::milliseconds
98 timeout; //!< time to wait between each retry in milliseconds
Tom Joseph74f27c72021-05-16 07:58:53 -070099 phosphor::Timer timer; //!< manages starting timers and handling timeouts
100
101 /** @brief Sends the PLDM request message
102 *
103 * @return return PLDM_SUCCESS on success and PLDM_ERROR otherwise
104 */
105 virtual int send() const = 0;
106
107 /** @brief Callback function invoked when the timeout happens */
108 void callback()
109 {
110 if (numRetries--)
111 {
112 send();
113 }
114 else
115 {
116 stop();
117 }
118 }
119};
120
121/** @class Request
122 *
123 * The concrete implementation of RequestIntf. This class implements the send()
124 * to send the PLDM request message over MCTP socket.
125 * This class encapsulates the PLDM request message, the number of times the
126 * request needs to retried if the response is not received and the amount of
127 * time to wait between each retry. It provides APIs to start and stop the
128 * request flow.
129 */
130class Request final : public RequestRetryTimer
131{
132 public:
133 Request() = delete;
134 Request(const Request&) = delete;
135 Request(Request&&) = default;
136 Request& operator=(const Request&) = delete;
137 Request& operator=(Request&&) = default;
138 ~Request() = default;
139
140 /** @brief Constructor
141 *
142 * @param[in] fd - fd of the MCTP communication socket
143 * @param[in] eid - endpoint ID of the remote MCTP endpoint
144 * @param[in] event - reference to PLDM daemon's main event loop
145 * @param[in] requestMsg - PLDM request message
146 * @param[in] numRetries - number of request retries
147 * @param[in] timeout - time to wait between each retry in milliseconds
Tom Josephe5268cd2021-09-07 13:04:03 +0530148 * @param[in] verbose - verbose tracing flag
Tom Joseph74f27c72021-05-16 07:58:53 -0700149 */
150 explicit Request(int fd, mctp_eid_t eid, sdeventplus::Event& event,
151 pldm::Request&& requestMsg, uint8_t numRetries,
Tom Josephe5268cd2021-09-07 13:04:03 +0530152 std::chrono::milliseconds timeout, bool verbose) :
Tom Joseph74f27c72021-05-16 07:58:53 -0700153 RequestRetryTimer(event, numRetries, timeout),
Tom Josephe5268cd2021-09-07 13:04:03 +0530154 fd(fd), eid(eid), requestMsg(std::move(requestMsg)), verbose(verbose)
Tom Joseph74f27c72021-05-16 07:58:53 -0700155 {}
156
157 private:
Sampa Misra42336b52021-08-18 01:07:07 -0500158 int fd; //!< file descriptor of MCTP communications socket
159 mctp_eid_t eid; //!< endpoint ID of the remote MCTP endpoint
160 pldm::Request requestMsg; //!< PLDM request message
Tom Josephe5268cd2021-09-07 13:04:03 +0530161 bool verbose; //!< verbose tracing flag
Tom Joseph74f27c72021-05-16 07:58:53 -0700162
163 /** @brief Sends the PLDM request message on the socket
164 *
165 * @return return PLDM_SUCCESS on success and PLDM_ERROR otherwise
166 */
167 int send() const
168 {
Tom Josephe5268cd2021-09-07 13:04:03 +0530169 if (verbose)
170 {
171 pldm::utils::printBuffer(pldm::utils::Tx, requestMsg);
172 }
Tom Joseph74f27c72021-05-16 07:58:53 -0700173 auto rc = pldm_send(eid, fd, requestMsg.data(), requestMsg.size());
174 if (rc < 0)
175 {
176 std::cerr << "Failed to send PLDM message. RC = " << rc
177 << ", errno = " << errno << "\n";
178 return PLDM_ERROR;
179 }
180 return PLDM_SUCCESS;
181 }
182};
183
184} // namespace requester
185
Sampa Misrac0c79482021-06-02 08:01:54 -0500186} // namespace pldm