174f27c73STom Joseph #pragma once 274f27c73STom Joseph 3ef773059SManojkiran Eda #include "common/flight_recorder.hpp" 41ed5f7a6SRashmica Gupta #include "common/transport.hpp" 574f27c73STom Joseph #include "common/types.hpp" 6e5268cdaSTom Joseph #include "common/utils.hpp" 774f27c73STom Joseph 8c453e164SGeorge Liu #include <libpldm/base.h> 99fffea2cSManojkiran Eda #include <sys/socket.h> 109fffea2cSManojkiran Eda 1149cfb138SRiya Dixit #include <phosphor-logging/lg2.hpp> 1274f27c73STom Joseph #include <sdbusplus/timer.hpp> 1374f27c73STom Joseph #include <sdeventplus/event.hpp> 1474f27c73STom Joseph 1574f27c73STom Joseph #include <chrono> 1674f27c73STom Joseph #include <functional> 1774f27c73STom Joseph #include <iostream> 1874f27c73STom Joseph 1949cfb138SRiya Dixit PHOSPHOR_LOG2_USING; 2049cfb138SRiya Dixit 2174f27c73STom Joseph namespace pldm 2274f27c73STom Joseph { 2374f27c73STom Joseph namespace requester 2474f27c73STom Joseph { 2574f27c73STom Joseph /** @class RequestRetryTimer 2674f27c73STom Joseph * 2774f27c73STom Joseph * The abstract base class for implementing the PLDM request retry logic. This 2874f27c73STom Joseph * class handles number of times the PLDM request needs to be retried if the 2974f27c73STom Joseph * response is not received and the time to wait between each retry. It 3074f27c73STom Joseph * provides APIs to start and stop the request flow. 3174f27c73STom Joseph */ 3274f27c73STom Joseph class RequestRetryTimer 3374f27c73STom Joseph { 3474f27c73STom Joseph public: 3574f27c73STom Joseph RequestRetryTimer() = delete; 3674f27c73STom Joseph RequestRetryTimer(const RequestRetryTimer&) = delete; 37a7dbca53SPavithra Barithaya RequestRetryTimer(RequestRetryTimer&&) = delete; 3874f27c73STom Joseph RequestRetryTimer& operator=(const RequestRetryTimer&) = delete; 39a7dbca53SPavithra Barithaya RequestRetryTimer& operator=(RequestRetryTimer&&) = delete; 4074f27c73STom Joseph virtual ~RequestRetryTimer() = default; 4174f27c73STom Joseph 4274f27c73STom Joseph /** @brief Constructor 4374f27c73STom Joseph * 4474f27c73STom Joseph * @param[in] event - reference to PLDM daemon's main event loop 4574f27c73STom Joseph * @param[in] numRetries - number of request retries 4674f27c73STom Joseph * @param[in] timeout - time to wait between each retry in milliseconds 4774f27c73STom Joseph */ RequestRetryTimer(sdeventplus::Event & event,uint8_t numRetries,std::chrono::milliseconds timeout)4874f27c73STom Joseph explicit RequestRetryTimer(sdeventplus::Event& event, uint8_t numRetries, 495079ac4aSBrad Bishop std::chrono::milliseconds timeout) : 5074f27c73STom Joseph 5174f27c73STom Joseph event(event), 5274f27c73STom Joseph numRetries(numRetries), timeout(timeout), 5374f27c73STom Joseph timer(event.get(), std::bind_front(&RequestRetryTimer::callback, this)) 5474f27c73STom Joseph {} 5574f27c73STom Joseph 5674f27c73STom Joseph /** @brief Starts the request flow and arms the timer for request retries 5774f27c73STom Joseph * 5874f27c73STom Joseph * @return return PLDM_SUCCESS on success and PLDM_ERROR otherwise 5974f27c73STom Joseph */ start()6074f27c73STom Joseph int start() 6174f27c73STom Joseph { 6274f27c73STom Joseph auto rc = send(); 63a5ed6585STom Joseph if (rc) 6474f27c73STom Joseph { 6574f27c73STom Joseph return rc; 6674f27c73STom Joseph } 6774f27c73STom Joseph 6874f27c73STom Joseph try 6974f27c73STom Joseph { 7074f27c73STom Joseph if (numRetries) 7174f27c73STom Joseph { 725079ac4aSBrad Bishop timer.start(duration_cast<std::chrono::microseconds>(timeout), 735079ac4aSBrad Bishop true); 7474f27c73STom Joseph } 7574f27c73STom Joseph } 7674f27c73STom Joseph catch (const std::runtime_error& e) 7774f27c73STom Joseph { 78087a751fSRiya Dixit error("Failed to start the request timer, error - {ERROR}", "ERROR", 79087a751fSRiya Dixit e); 8074f27c73STom Joseph return PLDM_ERROR; 8174f27c73STom Joseph } 8274f27c73STom Joseph 8374f27c73STom Joseph return PLDM_SUCCESS; 8474f27c73STom Joseph } 8574f27c73STom Joseph 8674f27c73STom Joseph /** @brief Stops the timer and no further request retries happen */ stop()8774f27c73STom Joseph void stop() 8874f27c73STom Joseph { 8974f27c73STom Joseph auto rc = timer.stop(); 9074f27c73STom Joseph if (rc) 9174f27c73STom Joseph { 92087a751fSRiya Dixit error("Failed to stop the request timer, response code '{RC}'", 93*1e5c81e0SRiya Dixit "RC", rc); 9474f27c73STom Joseph } 9574f27c73STom Joseph } 9674f27c73STom Joseph 9774f27c73STom Joseph protected: 9874f27c73STom Joseph sdeventplus::Event& event; //!< reference to PLDM daemon's main event loop 9974f27c73STom Joseph uint8_t numRetries; //!< number of request retries 1005079ac4aSBrad Bishop std::chrono::milliseconds 1015079ac4aSBrad Bishop timeout; //!< time to wait between each retry in milliseconds 10235535cf2SPatrick Williams sdbusplus::Timer timer; //!< manages starting timers and handling timeouts 10374f27c73STom Joseph 10474f27c73STom Joseph /** @brief Sends the PLDM request message 10574f27c73STom Joseph * 10674f27c73STom Joseph * @return return PLDM_SUCCESS on success and PLDM_ERROR otherwise 10774f27c73STom Joseph */ 10874f27c73STom Joseph virtual int send() const = 0; 10974f27c73STom Joseph 11074f27c73STom Joseph /** @brief Callback function invoked when the timeout happens */ callback()11174f27c73STom Joseph void callback() 11274f27c73STom Joseph { 11374f27c73STom Joseph if (numRetries--) 11474f27c73STom Joseph { 11574f27c73STom Joseph send(); 11674f27c73STom Joseph } 11774f27c73STom Joseph else 11874f27c73STom Joseph { 11974f27c73STom Joseph stop(); 12074f27c73STom Joseph } 12174f27c73STom Joseph } 12274f27c73STom Joseph }; 12374f27c73STom Joseph 12474f27c73STom Joseph /** @class Request 12574f27c73STom Joseph * 12674f27c73STom Joseph * The concrete implementation of RequestIntf. This class implements the send() 12774f27c73STom Joseph * to send the PLDM request message over MCTP socket. 12874f27c73STom Joseph * This class encapsulates the PLDM request message, the number of times the 12974f27c73STom Joseph * request needs to retried if the response is not received and the amount of 13074f27c73STom Joseph * time to wait between each retry. It provides APIs to start and stop the 13174f27c73STom Joseph * request flow. 13274f27c73STom Joseph */ 13374f27c73STom Joseph class Request final : public RequestRetryTimer 13474f27c73STom Joseph { 13574f27c73STom Joseph public: 13674f27c73STom Joseph Request() = delete; 13774f27c73STom Joseph Request(const Request&) = delete; 138a7dbca53SPavithra Barithaya Request(Request&&) = delete; 13974f27c73STom Joseph Request& operator=(const Request&) = delete; 140a7dbca53SPavithra Barithaya Request& operator=(Request&&) = delete; 14174f27c73STom Joseph ~Request() = default; 14274f27c73STom Joseph 14374f27c73STom Joseph /** @brief Constructor 14474f27c73STom Joseph * 1451ed5f7a6SRashmica Gupta * @param[in] pldm_transport - PLDM transport object 14674f27c73STom Joseph * @param[in] eid - endpoint ID of the remote MCTP endpoint 1479fffea2cSManojkiran Eda * @param[in] currrentSendbuffSize - the current send buffer size 14874f27c73STom Joseph * @param[in] event - reference to PLDM daemon's main event loop 14974f27c73STom Joseph * @param[in] requestMsg - PLDM request message 15074f27c73STom Joseph * @param[in] numRetries - number of request retries 15174f27c73STom Joseph * @param[in] timeout - time to wait between each retry in milliseconds 152e5268cdaSTom Joseph * @param[in] verbose - verbose tracing flag 15374f27c73STom Joseph */ Request(PldmTransport * pldmTransport,mctp_eid_t eid,sdeventplus::Event & event,pldm::Request && requestMsg,uint8_t numRetries,std::chrono::milliseconds timeout,bool verbose)1541ed5f7a6SRashmica Gupta explicit Request(PldmTransport* pldmTransport, mctp_eid_t eid, 1551ed5f7a6SRashmica Gupta sdeventplus::Event& event, pldm::Request&& requestMsg, 1561ed5f7a6SRashmica Gupta uint8_t numRetries, std::chrono::milliseconds timeout, 1579fffea2cSManojkiran Eda bool verbose) : 15874f27c73STom Joseph RequestRetryTimer(event, numRetries, timeout), 1591ed5f7a6SRashmica Gupta pldmTransport(pldmTransport), eid(eid), 1601ed5f7a6SRashmica Gupta requestMsg(std::move(requestMsg)), verbose(verbose) 16174f27c73STom Joseph {} 16274f27c73STom Joseph 16374f27c73STom Joseph private: 1641ed5f7a6SRashmica Gupta PldmTransport* pldmTransport; //!< PLDM transport 16574f27c73STom Joseph mctp_eid_t eid; //!< endpoint ID of the remote MCTP endpoint 16642336b5cSSampa Misra pldm::Request requestMsg; //!< PLDM request message 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 */ send() const17374f27c73STom Joseph int send() const 17474f27c73STom Joseph { 175e5268cdaSTom Joseph if (verbose) 176e5268cdaSTom Joseph { 177e5268cdaSTom Joseph pldm::utils::printBuffer(pldm::utils::Tx, requestMsg); 178e5268cdaSTom Joseph } 179ef773059SManojkiran Eda pldm::flightrecorder::FlightRecorder::GetInstance().saveRecord( 180ef773059SManojkiran Eda requestMsg, true); 1811ed5f7a6SRashmica Gupta const struct pldm_msg_hdr* hdr = 1821ed5f7a6SRashmica Gupta (struct pldm_msg_hdr*)(requestMsg.data()); 1831ed5f7a6SRashmica Gupta if (!hdr->request) 1841ed5f7a6SRashmica Gupta { 1851ed5f7a6SRashmica Gupta return PLDM_REQUESTER_NOT_REQ_MSG; 1861ed5f7a6SRashmica Gupta } 1871ed5f7a6SRashmica Gupta 1881ed5f7a6SRashmica Gupta if (pldmTransport == nullptr) 1891ed5f7a6SRashmica Gupta { 1901ed5f7a6SRashmica Gupta error("Invalid transport: Unable to send PLDM request"); 1911ed5f7a6SRashmica Gupta return PLDM_ERROR; 1921ed5f7a6SRashmica Gupta } 1931ed5f7a6SRashmica Gupta 1941ed5f7a6SRashmica Gupta auto rc = pldmTransport->sendMsg(static_cast<pldm_tid_t>(eid), 1951ed5f7a6SRashmica Gupta requestMsg.data(), requestMsg.size()); 19674f27c73STom Joseph if (rc < 0) 19774f27c73STom Joseph { 198087a751fSRiya Dixit error( 199087a751fSRiya Dixit "Failed to send pldmTransport message, response code '{RC}' and error - {ERROR}", 200*1e5c81e0SRiya Dixit "RC", rc, "ERROR", errno); 20174f27c73STom Joseph return PLDM_ERROR; 20274f27c73STom Joseph } 20374f27c73STom Joseph return PLDM_SUCCESS; 20474f27c73STom Joseph } 20574f27c73STom Joseph }; 20674f27c73STom Joseph 20774f27c73STom Joseph } // namespace requester 20874f27c73STom Joseph 20974f27c73STom Joseph } // namespace pldm 210