174f27c73STom Joseph #pragma once 274f27c73STom Joseph 3ef773059SManojkiran Eda #include "common/flight_recorder.hpp" 474f27c73STom Joseph #include "common/types.hpp" 5e5268cdaSTom Joseph #include "common/utils.hpp" 674f27c73STom Joseph 7*c453e164SGeorge Liu #include <libpldm/base.h> 8*c453e164SGeorge Liu #include <libpldm/pldm.h> 99fffea2cSManojkiran Eda #include <sys/socket.h> 109fffea2cSManojkiran Eda 1174f27c73STom Joseph #include <sdbusplus/timer.hpp> 1274f27c73STom Joseph #include <sdeventplus/event.hpp> 1374f27c73STom Joseph 1474f27c73STom Joseph #include <chrono> 1574f27c73STom Joseph #include <functional> 1674f27c73STom Joseph #include <iostream> 1774f27c73STom Joseph 1874f27c73STom Joseph namespace pldm 1974f27c73STom Joseph { 2074f27c73STom Joseph 2174f27c73STom Joseph namespace requester 2274f27c73STom Joseph { 2374f27c73STom Joseph 2474f27c73STom Joseph /** @class RequestRetryTimer 2574f27c73STom Joseph * 2674f27c73STom Joseph * The abstract base class for implementing the PLDM request retry logic. This 2774f27c73STom Joseph * class handles number of times the PLDM request needs to be retried if the 2874f27c73STom Joseph * response is not received and the time to wait between each retry. It 2974f27c73STom Joseph * provides APIs to start and stop the request flow. 3074f27c73STom Joseph */ 3174f27c73STom Joseph class RequestRetryTimer 3274f27c73STom Joseph { 3374f27c73STom Joseph public: 3474f27c73STom Joseph RequestRetryTimer() = delete; 3574f27c73STom Joseph RequestRetryTimer(const RequestRetryTimer&) = delete; 3674f27c73STom Joseph RequestRetryTimer(RequestRetryTimer&&) = default; 3774f27c73STom Joseph RequestRetryTimer& operator=(const RequestRetryTimer&) = delete; 3874f27c73STom Joseph RequestRetryTimer& operator=(RequestRetryTimer&&) = default; 3974f27c73STom Joseph virtual ~RequestRetryTimer() = default; 4074f27c73STom Joseph 4174f27c73STom Joseph /** @brief Constructor 4274f27c73STom Joseph * 4374f27c73STom Joseph * @param[in] event - reference to PLDM daemon's main event loop 4474f27c73STom Joseph * @param[in] numRetries - number of request retries 4574f27c73STom Joseph * @param[in] timeout - time to wait between each retry in milliseconds 4674f27c73STom Joseph */ 4774f27c73STom Joseph explicit RequestRetryTimer(sdeventplus::Event& event, uint8_t numRetries, 485079ac4aSBrad Bishop std::chrono::milliseconds timeout) : 4974f27c73STom Joseph 5074f27c73STom Joseph event(event), 5174f27c73STom Joseph numRetries(numRetries), timeout(timeout), 5274f27c73STom Joseph timer(event.get(), std::bind_front(&RequestRetryTimer::callback, this)) 5374f27c73STom Joseph {} 5474f27c73STom Joseph 5574f27c73STom Joseph /** @brief Starts the request flow and arms the timer for request retries 5674f27c73STom Joseph * 5774f27c73STom Joseph * @return return PLDM_SUCCESS on success and PLDM_ERROR otherwise 5874f27c73STom Joseph */ 5974f27c73STom Joseph int start() 6074f27c73STom Joseph { 6174f27c73STom Joseph auto rc = send(); 62a5ed6585STom Joseph if (rc) 6374f27c73STom Joseph { 6474f27c73STom Joseph return rc; 6574f27c73STom Joseph } 6674f27c73STom Joseph 6774f27c73STom Joseph try 6874f27c73STom Joseph { 6974f27c73STom Joseph if (numRetries) 7074f27c73STom Joseph { 715079ac4aSBrad Bishop timer.start(duration_cast<std::chrono::microseconds>(timeout), 725079ac4aSBrad Bishop true); 7374f27c73STom Joseph } 7474f27c73STom Joseph } 7574f27c73STom Joseph catch (const std::runtime_error& e) 7674f27c73STom Joseph { 7774f27c73STom Joseph std::cerr << "Failed to start the request timer. RC = " << e.what() 7874f27c73STom Joseph << "\n"; 7974f27c73STom Joseph return PLDM_ERROR; 8074f27c73STom Joseph } 8174f27c73STom Joseph 8274f27c73STom Joseph return PLDM_SUCCESS; 8374f27c73STom Joseph } 8474f27c73STom Joseph 8574f27c73STom Joseph /** @brief Stops the timer and no further request retries happen */ 8674f27c73STom Joseph void stop() 8774f27c73STom Joseph { 8874f27c73STom Joseph auto rc = timer.stop(); 8974f27c73STom Joseph if (rc) 9074f27c73STom Joseph { 9174f27c73STom Joseph std::cerr << "Failed to stop the request timer. RC = " << rc 9274f27c73STom Joseph << "\n"; 9374f27c73STom Joseph } 9474f27c73STom Joseph } 9574f27c73STom Joseph 9674f27c73STom Joseph protected: 9774f27c73STom Joseph sdeventplus::Event& event; //!< reference to PLDM daemon's main event loop 9874f27c73STom Joseph uint8_t numRetries; //!< number of request retries 995079ac4aSBrad Bishop std::chrono::milliseconds 1005079ac4aSBrad Bishop timeout; //!< time to wait between each retry in milliseconds 10174f27c73STom Joseph phosphor::Timer timer; //!< manages starting timers and handling timeouts 10274f27c73STom Joseph 10374f27c73STom Joseph /** @brief Sends the PLDM request message 10474f27c73STom Joseph * 10574f27c73STom Joseph * @return return PLDM_SUCCESS on success and PLDM_ERROR otherwise 10674f27c73STom Joseph */ 10774f27c73STom Joseph virtual int send() const = 0; 10874f27c73STom Joseph 10974f27c73STom Joseph /** @brief Callback function invoked when the timeout happens */ 11074f27c73STom Joseph void callback() 11174f27c73STom Joseph { 11274f27c73STom Joseph if (numRetries--) 11374f27c73STom Joseph { 11474f27c73STom Joseph send(); 11574f27c73STom Joseph } 11674f27c73STom Joseph else 11774f27c73STom Joseph { 11874f27c73STom Joseph stop(); 11974f27c73STom Joseph } 12074f27c73STom Joseph } 12174f27c73STom Joseph }; 12274f27c73STom Joseph 12374f27c73STom Joseph /** @class Request 12474f27c73STom Joseph * 12574f27c73STom Joseph * The concrete implementation of RequestIntf. This class implements the send() 12674f27c73STom Joseph * to send the PLDM request message over MCTP socket. 12774f27c73STom Joseph * This class encapsulates the PLDM request message, the number of times the 12874f27c73STom Joseph * request needs to retried if the response is not received and the amount of 12974f27c73STom Joseph * time to wait between each retry. It provides APIs to start and stop the 13074f27c73STom Joseph * request flow. 13174f27c73STom Joseph */ 13274f27c73STom Joseph class Request final : public RequestRetryTimer 13374f27c73STom Joseph { 13474f27c73STom Joseph public: 13574f27c73STom Joseph Request() = delete; 13674f27c73STom Joseph Request(const Request&) = delete; 13774f27c73STom Joseph Request(Request&&) = default; 13874f27c73STom Joseph Request& operator=(const Request&) = delete; 13974f27c73STom Joseph Request& operator=(Request&&) = default; 14074f27c73STom Joseph ~Request() = default; 14174f27c73STom Joseph 14274f27c73STom Joseph /** @brief Constructor 14374f27c73STom Joseph * 14474f27c73STom Joseph * @param[in] fd - fd of the MCTP communication socket 14574f27c73STom Joseph * @param[in] eid - endpoint ID of the remote MCTP endpoint 1469fffea2cSManojkiran Eda * @param[in] currrentSendbuffSize - the current send buffer size 14774f27c73STom Joseph * @param[in] event - reference to PLDM daemon's main event loop 14874f27c73STom Joseph * @param[in] requestMsg - PLDM request message 14974f27c73STom Joseph * @param[in] numRetries - number of request retries 15074f27c73STom Joseph * @param[in] timeout - time to wait between each retry in milliseconds 151e5268cdaSTom Joseph * @param[in] verbose - verbose tracing flag 15274f27c73STom Joseph */ 15374f27c73STom Joseph explicit Request(int fd, mctp_eid_t eid, sdeventplus::Event& event, 15474f27c73STom Joseph pldm::Request&& requestMsg, uint8_t numRetries, 1559fffea2cSManojkiran Eda std::chrono::milliseconds timeout, int currentSendbuffSize, 1569fffea2cSManojkiran Eda bool verbose) : 15774f27c73STom Joseph RequestRetryTimer(event, numRetries, timeout), 1589fffea2cSManojkiran Eda fd(fd), eid(eid), requestMsg(std::move(requestMsg)), 1599fffea2cSManojkiran Eda currentSendbuffSize(currentSendbuffSize), verbose(verbose) 16074f27c73STom Joseph {} 16174f27c73STom Joseph 16274f27c73STom Joseph private: 16374f27c73STom Joseph int fd; //!< file descriptor of MCTP communications socket 16474f27c73STom Joseph mctp_eid_t eid; //!< endpoint ID of the remote MCTP endpoint 16542336b5cSSampa Misra pldm::Request requestMsg; //!< PLDM request message 1669fffea2cSManojkiran Eda mutable int currentSendbuffSize; //!< current Send Buffer size 167e5268cdaSTom Joseph bool verbose; //!< verbose tracing flag 16874f27c73STom Joseph 16974f27c73STom Joseph /** @brief Sends the PLDM request message on the socket 17074f27c73STom Joseph * 17174f27c73STom Joseph * @return return PLDM_SUCCESS on success and PLDM_ERROR otherwise 17274f27c73STom Joseph */ 17374f27c73STom Joseph int send() const 17474f27c73STom Joseph { 175e5268cdaSTom Joseph if (verbose) 176e5268cdaSTom Joseph { 177e5268cdaSTom Joseph pldm::utils::printBuffer(pldm::utils::Tx, requestMsg); 178e5268cdaSTom Joseph } 1799fffea2cSManojkiran Eda if (currentSendbuffSize >= 0 && 1809fffea2cSManojkiran Eda (size_t)currentSendbuffSize < requestMsg.size()) 1819fffea2cSManojkiran Eda { 1829fffea2cSManojkiran Eda int oldSendbuffSize = currentSendbuffSize; 1839fffea2cSManojkiran Eda currentSendbuffSize = requestMsg.size(); 1849fffea2cSManojkiran Eda int res = 1859fffea2cSManojkiran Eda setsockopt(fd, SOL_SOCKET, SO_SNDBUF, ¤tSendbuffSize, 1869fffea2cSManojkiran Eda sizeof(currentSendbuffSize)); 1879fffea2cSManojkiran Eda if (res == -1) 1889fffea2cSManojkiran Eda { 1899fffea2cSManojkiran Eda std::cerr 1909fffea2cSManojkiran Eda << "Requester : Failed to set the new send buffer size [bytes] : " 1919fffea2cSManojkiran Eda << currentSendbuffSize 1929fffea2cSManojkiran Eda << " from current size [bytes]: " << oldSendbuffSize 1939fffea2cSManojkiran Eda << " , Error : " << strerror(errno) << std::endl; 1949fffea2cSManojkiran Eda return PLDM_ERROR; 1959fffea2cSManojkiran Eda } 1969fffea2cSManojkiran Eda } 197ef773059SManojkiran Eda pldm::flightrecorder::FlightRecorder::GetInstance().saveRecord( 198ef773059SManojkiran Eda requestMsg, true); 19974f27c73STom Joseph auto rc = pldm_send(eid, fd, requestMsg.data(), requestMsg.size()); 20074f27c73STom Joseph if (rc < 0) 20174f27c73STom Joseph { 20274f27c73STom Joseph std::cerr << "Failed to send PLDM message. RC = " << rc 20374f27c73STom Joseph << ", errno = " << errno << "\n"; 20474f27c73STom Joseph return PLDM_ERROR; 20574f27c73STom Joseph } 20674f27c73STom Joseph return PLDM_SUCCESS; 20774f27c73STom Joseph } 20874f27c73STom Joseph }; 20974f27c73STom Joseph 21074f27c73STom Joseph } // namespace requester 21174f27c73STom Joseph 21274f27c73STom Joseph } // namespace pldm 213