set up data handler mechanism

Data that comes from outside of the IPMI packet will leverage a data
interface implementation.  Only the IPMI blocktransfer (or really KCS)
will not use this external interface.

Change-Id: I7806da04c070dc3d6a79070ea563aeec63221dca
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/Makefile.am b/Makefile.am
index f990788..60b8e42 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,7 +4,9 @@
 libfirmwareblob_LTLIBRARIES = libfirmwareblob.la
 libfirmwareblob_la_SOURCES = main.cpp \
 		      firmware_handler.cpp \
-		      static_handler.cpp
+		      static_handler.cpp \
+		      lpc_handler.cpp \
+		      pci_handler.cpp
 libfirmwareblob_la_LDFLAGS = $(PHOSPHOR_LOGGING_LIBS) \
                         -version-info 0:0:0 -shared
 libfirmwareblob_la_CXXFLAGS = $(PHOSPHOR_LOGGING_CFLAGS) \
diff --git a/data_handler.hpp b/data_handler.hpp
index 07101f7..79e228f 100644
--- a/data_handler.hpp
+++ b/data_handler.hpp
@@ -1,5 +1,8 @@
 #pragma once
 
+#include <cstdint>
+#include <vector>
+
 namespace blobs
 {
 
@@ -10,6 +13,20 @@
 {
   public:
     virtual ~DataInterface() = default;
+
+    /**
+     * Copy bytes from external interface (blocking call).
+     *
+     * @param[in] length - number of bytes to copy
+     * @return the bytes read
+     */
+    virtual std::vector<std::uint8_t> copyFrom(std::uint32_t length) = 0;
+};
+
+struct DataHandlerPack
+{
+    std::uint16_t bitmask;
+    DataInterface* handler;
 };
 
 } // namespace blobs
diff --git a/firmware_handler.cpp b/firmware_handler.cpp
index 21556e1..f6c5472 100644
--- a/firmware_handler.cpp
+++ b/firmware_handler.cpp
@@ -18,13 +18,18 @@
 
 std::unique_ptr<GenericBlobInterface>
     FirmwareBlobHandler::CreateFirmwareBlobHandler(
-        const std::vector<HandlerPack>& firmwares, std::uint16_t transports)
+        const std::vector<HandlerPack>& firmwares,
+        const std::vector<DataHandlerPack>& transports)
 {
     /* There must be at least one. */
     if (!firmwares.size())
     {
         return nullptr;
     }
+    if (!transports.size())
+    {
+        return nullptr;
+    }
 
     std::vector<std::string> blobs;
     for (const auto& item : firmwares)
@@ -33,7 +38,15 @@
     }
     blobs.push_back(hashBlobID);
 
-    return std::make_unique<FirmwareBlobHandler>(firmwares, blobs, transports);
+    std::uint16_t bitmask = 0;
+    for (const auto& item : transports)
+    {
+        /* TODO: can use std::accumulate() unless I'm mistaken. :D */
+        bitmask |= item.bitmask;
+    }
+
+    return std::make_unique<FirmwareBlobHandler>(firmwares, blobs, transports,
+                                                 bitmask);
 }
 
 bool FirmwareBlobHandler::canHandleBlob(const std::string& path)
@@ -92,7 +105,7 @@
     else
     {
         /* They are requesting information about the generic blob_id. */
-        meta->blobState = transports;
+        meta->blobState = bitmask;
         meta->size = 0;
 
         /* The generic blob_ids state is only the bits related to the transport
@@ -148,7 +161,7 @@
 
     /* Check the flags for the transport mechanism: if none match we don't
      * support what they request. */
-    if ((flags & transports) == 0)
+    if ((flags & bitmask) == 0)
     {
         return false;
     }
@@ -170,6 +183,16 @@
     }
     else
     {
+        /* How are they expecting to copy this data? */
+        auto d = std::find_if(
+            transports.begin(), transports.end(),
+            [&flags](const auto& iter) { return (iter.bitmask & flags); });
+        if (d != transports.end())
+        {
+            /* We found the transport handler they requested, no surprise since
+             * above we verify they selected at least one we wanted. */
+        }
+
         /* 2d) are they opening the /flash/tarball ? (to start the UBI process)
          */
         /* 2e) are they opening the /flash/image ? (to start the process) */
diff --git a/firmware_handler.hpp b/firmware_handler.hpp
index 8f54d7d..786b2d1 100644
--- a/firmware_handler.hpp
+++ b/firmware_handler.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "data_handler.hpp"
 #include "image_handler.hpp"
 
 #include <blobs-ipmid/blobs.hpp>
@@ -28,23 +29,26 @@
      * Create a FirmwareBlobHandler.
      *
      * @param[in] firmwares - list of firmware blob_ids to support.
-     * @param[in] transports - bitmask of transports to support.
+     * @param[in] transports - list of transports to support.
      */
-    static std::unique_ptr<GenericBlobInterface>
-        CreateFirmwareBlobHandler(const std::vector<HandlerPack>& firmwares,
-                                  std::uint16_t transports);
+    static std::unique_ptr<GenericBlobInterface> CreateFirmwareBlobHandler(
+        const std::vector<HandlerPack>& firmwares,
+        const std::vector<DataHandlerPack>& transports);
 
     /**
      * Create a FirmwareBlobHandler.
      *
-     * @param[in] blobs - list of blobs_ids to support and their image handlers.
-     * @param[in] transports - bitmask of transports to support.
+     * @param[in] firmwares - list of firmware types and their handlers
+     * @param[in] blobs - list of blobs_ids to support
+     * @param[in] transports - list of transport types and their handlers
+     * @param[in] bitmask - bitmask of transports to support
      */
     FirmwareBlobHandler(const std::vector<HandlerPack>& firmwares,
                         const std::vector<std::string>& blobs,
-                        std::uint16_t transports) :
+                        const std::vector<DataHandlerPack>& transports,
+                        std::uint16_t bitmask) :
         handlers(firmwares),
-        blobIDs(blobs), transports(transports)
+        blobIDs(blobs), transports(transports), bitmask(bitmask)
     {
     }
     ~FirmwareBlobHandler() = default;
@@ -81,8 +85,11 @@
     /** Active list of blobIDs. */
     std::vector<std::string> blobIDs;
 
+    /** List of handlers by transport type. */
+    std::vector<DataHandlerPack> transports;
+
     /** The bits set indicate what transport mechanisms are supported. */
-    std::uint16_t transports;
+    std::uint16_t bitmask;
 
     /** Temporary variable to track whether a blob is open. */
     bool fileOpen = false;
diff --git a/lpc_handler.cpp b/lpc_handler.cpp
new file mode 100644
index 0000000..acd58c8
--- /dev/null
+++ b/lpc_handler.cpp
@@ -0,0 +1,15 @@
+#include "lpc_handler.hpp"
+
+#include <cstdint>
+#include <vector>
+
+namespace blobs
+{
+
+std::vector<std::uint8_t> LpcDataHandler::copyFrom(std::uint32_t length)
+{
+    /* TODO: implement this. */
+    return {};
+}
+
+} // namespace blobs
diff --git a/lpc_handler.hpp b/lpc_handler.hpp
new file mode 100644
index 0000000..903cf26
--- /dev/null
+++ b/lpc_handler.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "data_handler.hpp"
+
+#include <cstdint>
+#include <vector>
+
+namespace blobs
+{
+
+class LpcDataHandler : public DataInterface
+{
+
+  public:
+    LpcDataHandler() = default;
+
+    std::vector<std::uint8_t> copyFrom(std::uint32_t length) override;
+};
+
+} // namespace blobs
diff --git a/main.cpp b/main.cpp
index 28bb943..93d3770 100644
--- a/main.cpp
+++ b/main.cpp
@@ -2,6 +2,8 @@
 
 #include "firmware_handler.hpp"
 #include "image_handler.hpp"
+#include "lpc_handler.hpp"
+#include "pci_handler.hpp"
 #include "static_handler.hpp"
 
 #include <blobs-ipmid/manager.hpp>
@@ -16,6 +18,8 @@
 namespace
 {
 StaticLayoutHandler staticLayoutHandler;
+LpcDataHandler lpcDataHandler;
+PciDataHandler pciDataHandler;
 
 std::vector<HandlerPack> supportedFirmware = {
 #ifdef ENABLE_STATIC_LAYOUT
@@ -23,21 +27,22 @@
 #endif
 };
 
-std::uint16_t supportedTransports =
-    FirmwareBlobHandler::FirmwareUpdateFlags::bt;
+std::vector<DataHandlerPack> supportedTransports = {
+    {FirmwareBlobHandler::FirmwareUpdateFlags::bt, nullptr},
+#ifdef ENABLE_PCI_BRIDGE
+    {FirmwareBlobHandler::FirmwareUpdateFlags::p2a, &pciDataHandler},
+#endif
+#ifdef ENABLE_LPC_BRIDGE
+    {FirmwareBlobHandler::FirmwareUpdateFlags::lpc, &lpcDataHandler},
+#endif
+};
+
 } // namespace
 
 void setupFirmwareHandler() __attribute__((constructor));
 
 void setupFirmwareHandler()
 {
-#ifdef ENABLE_PCI_BRIDGE
-    supportedTransports |= FirmwareBlobHandler::FirmwareUpdateFlags::p2a;
-#endif
-#ifdef ENABLE_LPC_BRIDGE
-    supportedTransports |= FirmwareBlobHandler::FirmwareUpdateFlags::lpc;
-#endif
-
     auto handler = FirmwareBlobHandler::CreateFirmwareBlobHandler(
         supportedFirmware, supportedTransports);
 
diff --git a/pci_handler.cpp b/pci_handler.cpp
new file mode 100644
index 0000000..91edf63
--- /dev/null
+++ b/pci_handler.cpp
@@ -0,0 +1,15 @@
+#include "pci_handler.hpp"
+
+#include <cstdint>
+#include <vector>
+
+namespace blobs
+{
+
+std::vector<std::uint8_t> PciDataHandler::copyFrom(std::uint32_t length)
+{
+    /* TODO: implement this. */
+    return {};
+}
+
+} // namespace blobs
diff --git a/pci_handler.hpp b/pci_handler.hpp
new file mode 100644
index 0000000..df936e4
--- /dev/null
+++ b/pci_handler.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "data_handler.hpp"
+
+#include <cstdint>
+#include <vector>
+
+namespace blobs
+{
+
+class PciDataHandler : public DataInterface
+{
+
+  public:
+    PciDataHandler() = default;
+
+    std::vector<std::uint8_t> copyFrom(std::uint32_t length) override;
+};
+
+} // namespace blobs
diff --git a/test/data_mock.hpp b/test/data_mock.hpp
new file mode 100644
index 0000000..1fd1fae
--- /dev/null
+++ b/test/data_mock.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "data_handler.hpp"
+
+#include <gmock/gmock.h>
+
+namespace blobs
+{
+
+class DataHandlerMock : public DataInterface
+{
+  public:
+    virtual ~DataHandlerMock() = default;
+
+    MOCK_METHOD1(copyFrom, std::vector<std::uint8_t>(std::uint32_t));
+};
+
+} // namespace blobs
diff --git a/test/firmware_canhandle_unittest.cpp b/test/firmware_canhandle_unittest.cpp
index 028d472..4f00d50 100644
--- a/test/firmware_canhandle_unittest.cpp
+++ b/test/firmware_canhandle_unittest.cpp
@@ -1,3 +1,4 @@
+#include "data_mock.hpp"
 #include "firmware_handler.hpp"
 #include "image_mock.hpp"
 
@@ -25,9 +26,11 @@
         {"asdf", &imageMock},
         {"bcdf", &imageMock},
     };
+    std::vector<DataHandlerPack> data = {
+        {FirmwareBlobHandler::FirmwareUpdateFlags::bt, nullptr},
+    };
 
-    auto handler = FirmwareBlobHandler::CreateFirmwareBlobHandler(
-        blobs, FirmwareBlobHandler::FirmwareUpdateFlags::bt);
+    auto handler = FirmwareBlobHandler::CreateFirmwareBlobHandler(blobs, data);
 
     for (const auto& item : items)
     {
diff --git a/test/firmware_handler_unittest.cpp b/test/firmware_handler_unittest.cpp
index 16395df..bae6cab 100644
--- a/test/firmware_handler_unittest.cpp
+++ b/test/firmware_handler_unittest.cpp
@@ -12,7 +12,22 @@
 
 TEST(FirmwareHandlerTest, CreateEmptyListVerifyFails)
 {
-    auto handler = FirmwareBlobHandler::CreateFirmwareBlobHandler({}, 0);
+    std::vector<DataHandlerPack> data = {
+        {FirmwareBlobHandler::FirmwareUpdateFlags::bt, nullptr},
+    };
+
+    auto handler = FirmwareBlobHandler::CreateFirmwareBlobHandler({}, data);
+    EXPECT_EQ(handler, nullptr);
+}
+TEST(FirmwareHandlerTest, CreateEmptyDataHandlerListFails)
+{
+    ImageHandlerMock imageMock;
+
+    std::vector<HandlerPack> blobs = {
+        {"asdf", &imageMock},
+    };
+
+    auto handler = FirmwareBlobHandler::CreateFirmwareBlobHandler(blobs, {});
     EXPECT_EQ(handler, nullptr);
 }
 TEST(FirmwareHandlerTest, CreateEmptyListVerifyHasHash)
@@ -22,8 +37,11 @@
     std::vector<HandlerPack> blobs = {
         {"asdf", &imageMock},
     };
+    std::vector<DataHandlerPack> data = {
+        {FirmwareBlobHandler::FirmwareUpdateFlags::bt, nullptr},
+    };
 
-    auto handler = FirmwareBlobHandler::CreateFirmwareBlobHandler(blobs, 0);
+    auto handler = FirmwareBlobHandler::CreateFirmwareBlobHandler(blobs, data);
     auto result = handler->getBlobIds();
     EXPECT_EQ(2, result.size());
     EXPECT_EQ(2, std::count(result.begin(), result.end(), "asdf") +
diff --git a/test/firmware_stat_unittest.cpp b/test/firmware_stat_unittest.cpp
index a00adf5..e52ce86 100644
--- a/test/firmware_stat_unittest.cpp
+++ b/test/firmware_stat_unittest.cpp
@@ -22,9 +22,11 @@
     std::vector<HandlerPack> blobs = {
         {"asdf", &imageMock},
     };
+    std::vector<DataHandlerPack> data = {
+        {FirmwareBlobHandler::FirmwareUpdateFlags::bt, nullptr},
+    };
 
-    auto handler = FirmwareBlobHandler::CreateFirmwareBlobHandler(
-        blobs, FirmwareBlobHandler::FirmwareUpdateFlags::bt);
+    auto handler = FirmwareBlobHandler::CreateFirmwareBlobHandler(blobs, data);
     struct BlobMeta meta;
     EXPECT_TRUE(handler->stat("asdf", &meta));
     EXPECT_EQ(FirmwareBlobHandler::FirmwareUpdateFlags::bt, meta.blobState);