blob: 2c216daedba8a9cfd0ed50aa9c014e08722dd18a [file] [log] [blame]
Tom Joseph74f27c72021-05-16 07:58:53 -07001#pragma once
2
Manojkiran Edaef773052021-07-29 09:29:28 +05303#include "common/flight_recorder.hpp"
Tom Joseph74f27c72021-05-16 07:58:53 -07004#include "common/types.hpp"
Tom Josephe5268cd2021-09-07 13:04:03 +05305#include "common/utils.hpp"
Tom Joseph74f27c72021-05-16 07:58:53 -07006
George Liuc453e162022-12-21 17:16:23 +08007#include <libpldm/base.h>
8#include <libpldm/pldm.h>
Manojkiran Eda9fffea22021-10-27 16:03:27 +05309#include <sys/socket.h>
10
Riya Dixit49cfb132023-03-02 04:26:53 -060011#include <phosphor-logging/lg2.hpp>
Tom Joseph74f27c72021-05-16 07:58:53 -070012#include <sdbusplus/timer.hpp>
13#include <sdeventplus/event.hpp>
14
15#include <chrono>
16#include <functional>
17#include <iostream>
18
Riya Dixit49cfb132023-03-02 04:26:53 -060019PHOSPHOR_LOG2_USING;
20
Tom Joseph74f27c72021-05-16 07:58:53 -070021namespace pldm
22{
Tom Joseph74f27c72021-05-16 07:58:53 -070023namespace requester
24{
Tom Joseph74f27c72021-05-16 07:58:53 -070025/** @class RequestRetryTimer
26 *
27 * The abstract base class for implementing the PLDM request retry logic. This
28 * class handles number of times the PLDM request needs to be retried if the
29 * response is not received and the time to wait between each retry. It
30 * provides APIs to start and stop the request flow.
31 */
32class RequestRetryTimer
33{
34 public:
35 RequestRetryTimer() = delete;
36 RequestRetryTimer(const RequestRetryTimer&) = delete;
37 RequestRetryTimer(RequestRetryTimer&&) = default;
38 RequestRetryTimer& operator=(const RequestRetryTimer&) = delete;
39 RequestRetryTimer& operator=(RequestRetryTimer&&) = default;
40 virtual ~RequestRetryTimer() = default;
41
42 /** @brief Constructor
43 *
44 * @param[in] event - reference to PLDM daemon's main event loop
45 * @param[in] numRetries - number of request retries
46 * @param[in] timeout - time to wait between each retry in milliseconds
47 */
48 explicit RequestRetryTimer(sdeventplus::Event& event, uint8_t numRetries,
Brad Bishop5079ac42021-08-19 18:35:06 -040049 std::chrono::milliseconds timeout) :
Tom Joseph74f27c72021-05-16 07:58:53 -070050
51 event(event),
52 numRetries(numRetries), timeout(timeout),
53 timer(event.get(), std::bind_front(&RequestRetryTimer::callback, this))
54 {}
55
56 /** @brief Starts the request flow and arms the timer for request retries
57 *
58 * @return return PLDM_SUCCESS on success and PLDM_ERROR otherwise
59 */
60 int start()
61 {
62 auto rc = send();
Tom Josepha5ed6582021-06-17 22:08:47 -070063 if (rc)
Tom Joseph74f27c72021-05-16 07:58:53 -070064 {
65 return rc;
66 }
67
68 try
69 {
70 if (numRetries)
71 {
Brad Bishop5079ac42021-08-19 18:35:06 -040072 timer.start(duration_cast<std::chrono::microseconds>(timeout),
73 true);
Tom Joseph74f27c72021-05-16 07:58:53 -070074 }
75 }
76 catch (const std::runtime_error& e)
77 {
Riya Dixit49cfb132023-03-02 04:26:53 -060078 error("Failed to start the request timer. RC = {ERR_EXCEP}",
79 "ERR_EXCEP", e.what());
Tom Joseph74f27c72021-05-16 07:58:53 -070080 return PLDM_ERROR;
81 }
82
83 return PLDM_SUCCESS;
84 }
85
86 /** @brief Stops the timer and no further request retries happen */
87 void stop()
88 {
89 auto rc = timer.stop();
90 if (rc)
91 {
Riya Dixit49cfb132023-03-02 04:26:53 -060092 error("Failed to stop the request timer. RC = {RC}", "RC",
93 static_cast<int>(rc));
Tom Joseph74f27c72021-05-16 07:58:53 -070094 }
95 }
96
97 protected:
98 sdeventplus::Event& event; //!< reference to PLDM daemon's main event loop
99 uint8_t numRetries; //!< number of request retries
Brad Bishop5079ac42021-08-19 18:35:06 -0400100 std::chrono::milliseconds
101 timeout; //!< time to wait between each retry in milliseconds
Tom Joseph74f27c72021-05-16 07:58:53 -0700102 phosphor::Timer timer; //!< manages starting timers and handling timeouts
103
104 /** @brief Sends the PLDM request message
105 *
106 * @return return PLDM_SUCCESS on success and PLDM_ERROR otherwise
107 */
108 virtual int send() const = 0;
109
110 /** @brief Callback function invoked when the timeout happens */
111 void callback()
112 {
113 if (numRetries--)
114 {
115 send();
116 }
117 else
118 {
119 stop();
120 }
121 }
122};
123
124/** @class Request
125 *
126 * The concrete implementation of RequestIntf. This class implements the send()
127 * to send the PLDM request message over MCTP socket.
128 * This class encapsulates the PLDM request message, the number of times the
129 * request needs to retried if the response is not received and the amount of
130 * time to wait between each retry. It provides APIs to start and stop the
131 * request flow.
132 */
133class Request final : public RequestRetryTimer
134{
135 public:
136 Request() = delete;
137 Request(const Request&) = delete;
138 Request(Request&&) = default;
139 Request& operator=(const Request&) = delete;
140 Request& operator=(Request&&) = default;
141 ~Request() = default;
142
143 /** @brief Constructor
144 *
145 * @param[in] fd - fd of the MCTP communication socket
146 * @param[in] eid - endpoint ID of the remote MCTP endpoint
Manojkiran Eda9fffea22021-10-27 16:03:27 +0530147 * @param[in] currrentSendbuffSize - the current send buffer size
Tom Joseph74f27c72021-05-16 07:58:53 -0700148 * @param[in] event - reference to PLDM daemon's main event loop
149 * @param[in] requestMsg - PLDM request message
150 * @param[in] numRetries - number of request retries
151 * @param[in] timeout - time to wait between each retry in milliseconds
Tom Josephe5268cd2021-09-07 13:04:03 +0530152 * @param[in] verbose - verbose tracing flag
Tom Joseph74f27c72021-05-16 07:58:53 -0700153 */
154 explicit Request(int fd, mctp_eid_t eid, sdeventplus::Event& event,
155 pldm::Request&& requestMsg, uint8_t numRetries,
Manojkiran Eda9fffea22021-10-27 16:03:27 +0530156 std::chrono::milliseconds timeout, int currentSendbuffSize,
157 bool verbose) :
Tom Joseph74f27c72021-05-16 07:58:53 -0700158 RequestRetryTimer(event, numRetries, timeout),
Manojkiran Eda9fffea22021-10-27 16:03:27 +0530159 fd(fd), eid(eid), requestMsg(std::move(requestMsg)),
160 currentSendbuffSize(currentSendbuffSize), verbose(verbose)
Tom Joseph74f27c72021-05-16 07:58:53 -0700161 {}
162
163 private:
Sampa Misra42336b52021-08-18 01:07:07 -0500164 int fd; //!< file descriptor of MCTP communications socket
165 mctp_eid_t eid; //!< endpoint ID of the remote MCTP endpoint
166 pldm::Request requestMsg; //!< PLDM request message
Manojkiran Eda9fffea22021-10-27 16:03:27 +0530167 mutable int currentSendbuffSize; //!< current Send Buffer size
168 bool verbose; //!< verbose tracing flag
Tom Joseph74f27c72021-05-16 07:58:53 -0700169
170 /** @brief Sends the PLDM request message on the socket
171 *
172 * @return return PLDM_SUCCESS on success and PLDM_ERROR otherwise
173 */
174 int send() const
175 {
Tom Josephe5268cd2021-09-07 13:04:03 +0530176 if (verbose)
177 {
178 pldm::utils::printBuffer(pldm::utils::Tx, requestMsg);
179 }
Manojkiran Eda9fffea22021-10-27 16:03:27 +0530180 if (currentSendbuffSize >= 0 &&
181 (size_t)currentSendbuffSize < requestMsg.size())
182 {
183 int oldSendbuffSize = currentSendbuffSize;
184 currentSendbuffSize = requestMsg.size();
Patrick Williams6da4f912023-05-10 07:50:53 -0500185 int res = setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
186 &currentSendbuffSize,
187 sizeof(currentSendbuffSize));
Manojkiran Eda9fffea22021-10-27 16:03:27 +0530188 if (res == -1)
189 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600190 error(
191 "Requester : Failed to set the new send buffer size [bytes] : {CURR_SND_BUF_SIZE} from current size [bytes]: {OLD_BUF_SIZE} , Error : {ERR}",
192 "CURR_SND_BUF_SIZE", currentSendbuffSize, "OLD_BUF_SIZE",
193 oldSendbuffSize, "ERR", strerror(errno));
Manojkiran Eda9fffea22021-10-27 16:03:27 +0530194 return PLDM_ERROR;
195 }
196 }
Manojkiran Edaef773052021-07-29 09:29:28 +0530197 pldm::flightrecorder::FlightRecorder::GetInstance().saveRecord(
198 requestMsg, true);
Tom Joseph74f27c72021-05-16 07:58:53 -0700199 auto rc = pldm_send(eid, fd, requestMsg.data(), requestMsg.size());
200 if (rc < 0)
201 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600202 error("Failed to send PLDM message. RC = {RC}, errno = {ERR}", "RC",
203 static_cast<int>(rc), "ERR", errno);
Tom Joseph74f27c72021-05-16 07:58:53 -0700204 return PLDM_ERROR;
205 }
206 return PLDM_SUCCESS;
207 }
208};
209
210} // namespace requester
211
Sampa Misrac0c79482021-06-02 08:01:54 -0500212} // namespace pldm