requester: PLDM handler for async request/response

PLDM request handler provides APIs to register PLDM request message,
handle retries and instance ID expiration. Sending the PLDM request
and handling response is handled in an async manner. On receiving
the response the corresponding response handler registered for the
request is invoked.

Tested: Ran unit tests

Signed-off-by: Tom Joseph <rushtotom@gmail.com>
Change-Id: I9f0a9dfcf0fbc9a84eefad375b92d40dd8b48d3d
diff --git a/pldmd/pldmd.cpp b/pldmd/pldmd.cpp
index 9684f0b..4e3bea3 100644
--- a/pldmd/pldmd.cpp
+++ b/pldmd/pldmd.cpp
@@ -6,6 +6,8 @@
 #include "common/utils.hpp"
 #include "dbus_impl_requester.hpp"
 #include "invoker.hpp"
+#include "requester/handler.hpp"
+#include "requester/request.hpp"
 
 #include <err.h>
 #include <getopt.h>
@@ -26,6 +28,7 @@
 #include <iostream>
 #include <iterator>
 #include <memory>
+#include <optional>
 #include <sstream>
 #include <stdexcept>
 #include <string>
@@ -57,11 +60,10 @@
 using namespace pldm::responder;
 using namespace pldm::utils;
 
-static Response processRxMsg(const std::vector<uint8_t>& requestMsg,
-                             Invoker& invoker, dbus_api::Requester& requester)
+static std::optional<Response>
+    processRxMsg(const std::vector<uint8_t>& requestMsg, Invoker& invoker,
+                 requester::Handler<requester::Request>& handler)
 {
-
-    Response response;
     uint8_t eid = requestMsg[0];
     uint8_t type = requestMsg[1];
     pldm_header_info hdrFields{};
@@ -70,11 +72,12 @@
     if (PLDM_SUCCESS != unpack_pldm_header(hdr, &hdrFields))
     {
         std::cerr << "Empty PLDM request header \n";
-        return response;
+        return std::nullopt;
     }
 
     if (PLDM_RESPONSE != hdrFields.msg_type)
     {
+        Response response;
         auto request = reinterpret_cast<const pldm_msg*>(hdr);
         size_t requestLen = requestMsg.size() - sizeof(struct pldm_msg_hdr) -
                             sizeof(eid) - sizeof(type);
@@ -96,15 +99,21 @@
             if (PLDM_SUCCESS != pack_pldm_header(&header, responseHdr))
             {
                 std::cerr << "Failed adding response header \n";
+                return std::nullopt;
             }
             response.insert(response.end(), completion_code);
         }
+        return response;
     }
-    else
+    else if (PLDM_RESPONSE == hdrFields.msg_type)
     {
-        requester.markFree(eid, hdr->instance_id);
+        auto response = reinterpret_cast<const pldm_msg*>(hdr);
+        size_t responseLen = requestMsg.size() - sizeof(struct pldm_msg_hdr) -
+                             sizeof(eid) - sizeof(type);
+        handler.handleResponse(eid, hdrFields.instance, hdrFields.pldm_type,
+                               hdrFields.command, response, responseLen);
     }
-    return response;
+    return std::nullopt;
 }
 
 void optionUsage(void)
@@ -159,6 +168,8 @@
     auto& bus = pldm::utils::DBusHandler::getBus();
     dbus_api::Requester dbusImplReq(bus, "/xyz/openbmc_project/pldm");
     Invoker invoker{};
+    requester::Handler<requester::Request> reqHandler(sockfd, event,
+                                                      dbusImplReq);
 
 #ifdef LIBPLDMRESPONDER
     using namespace pldm::state_sensor;
@@ -182,7 +193,8 @@
     {
         hostPDRHandler = std::make_unique<HostPDRHandler>(
             sockfd, hostEID, event, pdrRepo.get(), EVENTS_JSONS_DIR,
-            entityTree.get(), bmcEntityTree.get(), dbusImplReq, verbose);
+            entityTree.get(), bmcEntityTree.get(), dbusImplReq, reqHandler,
+            verbose);
         hostEffecterParser =
             std::make_unique<pldm::host_effecters::HostEffecterParser>(
                 &dbusImplReq, sockfd, pdrRepo.get(), dbusHandler.get(),
@@ -256,8 +268,8 @@
         exit(EXIT_FAILURE);
     }
 
-    auto callback = [verbose, &invoker, &dbusImplReq](IO& io, int fd,
-                                                      uint32_t revents) {
+    auto callback = [verbose, &invoker, &reqHandler](IO& io, int fd,
+                                                     uint32_t revents) {
         if (!(revents & EPOLLIN))
         {
             return;
@@ -309,20 +321,20 @@
                 {
                     // process message and send response
                     auto response =
-                        processRxMsg(requestMsg, invoker, dbusImplReq);
-                    if (!response.empty())
+                        processRxMsg(requestMsg, invoker, reqHandler);
+                    if (response.has_value())
                     {
                         if (verbose)
                         {
                             std::cout << "Sending Msg" << std::endl;
-                            printBuffer(response, verbose);
+                            printBuffer(*response, verbose);
                         }
 
                         iov[0].iov_base = &requestMsg[0];
                         iov[0].iov_len =
                             sizeof(requestMsg[0]) + sizeof(requestMsg[1]);
-                        iov[1].iov_base = response.data();
-                        iov[1].iov_len = response.size();
+                        iov[1].iov_base = (*response).data();
+                        iov[1].iov_len = (*response).size();
 
                         msg.msg_iov = iov;
                         msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);