From c0f499b594b158bdb6c61764c27729fef6837cd3 Mon Sep 17 00:00:00 2001 From: Patrick Venture Date: Fri, 14 Sep 2018 17:57:42 -0700 Subject: add example handler This adds an example handler to demonstrate how one can add a specific type of BLOB handler. Change-Id: Ib5421f1b945b45998b40d3939a4dab9cdf39aaa9 Signed-off-by: Patrick Venture --- Makefile.am | 9 ++- configure.ac | 6 ++ example/example.cpp | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++ example/example.hpp | 71 ++++++++++++++++++++++ main.cpp | 8 +++ 5 files changed, 260 insertions(+), 1 deletion(-) create mode 100644 example/example.cpp create mode 100644 example/example.hpp diff --git a/Makefile.am b/Makefile.am index 624bbf2..51f7bdd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,12 +1,19 @@ AM_DEFAULT_SOURCE_EXT = .cpp +HANDLERS = + +if ENABLE_EXAMPLE +HANDLERS += example/example.cpp +endif + libblobcmdsdir = ${libdir}/ipmid-providers libblobcmds_LTLIBRARIES = libblobcmds.la libblobcmds_la_SOURCES = main.cpp \ ipmi.cpp \ manager.cpp \ process.cpp \ - crc.cpp + crc.cpp \ + $(HANDLERS) libblobcmds_la_LDFLAGS = $(SYSTEMD_LIBS) \ -version-info 0:0:0 -shared diff --git a/configure.ac b/configure.ac index 186c711..7ef48a4 100644 --- a/configure.ac +++ b/configure.ac @@ -53,6 +53,12 @@ AS_IF([test "x$enable_oe_sdk" == "xyes"], AC_SUBST([OESDK_TESTCASE_FLAGS], [$testcase_flags]) ) +# Do you want to include the example blob handler? +AC_ARG_ENABLE([example], + AS_HELP_STRING([--enable-example], [Enable example blob handler]) +) +AM_CONDITIONAL(ENABLE_EXAMPLE, [test "x$enable_example" = "xyes"]) + # Create configured output AC_CONFIG_FILES([Makefile test/Makefile]) AC_OUTPUT diff --git a/example/example.cpp b/example/example.cpp new file mode 100644 index 0000000..de05f00 --- /dev/null +++ b/example/example.cpp @@ -0,0 +1,167 @@ +#include "example/example.hpp" + +#include +#include +#include + +namespace blobs +{ + +constexpr char ExampleBlobHandler::supportedPath[]; + +ExampleBlob* ExampleBlobHandler::getSession(uint16_t id) +{ + auto search = sessions.find(id); + if (search == sessions.end()) + { + return nullptr; + } + /* Not thread-safe, however, the blob handler deliberately assumes serial + * execution. */ + return &search->second; +} + +bool ExampleBlobHandler::canHandleBlob(const std::string& path) +{ + return (path == supportedPath); +} + +std::vector ExampleBlobHandler::getBlobIds() +{ + return {supportedPath}; +} + +bool ExampleBlobHandler::deleteBlob(const std::string& path) +{ + return false; +} + +bool ExampleBlobHandler::stat(const std::string& path, struct BlobMeta* meta) +{ + return false; +} + +bool ExampleBlobHandler::open(uint16_t session, uint16_t flags, + const std::string& path) +{ + if (!canHandleBlob(path)) + { + return false; + } + + auto findSess = sessions.find(session); + if (findSess != sessions.end()) + { + /* This session is already active. */ + return false; + } + sessions[session] = ExampleBlob(session, flags); + return true; +} + +std::vector ExampleBlobHandler::read(uint16_t session, uint32_t offset, + uint32_t requestedSize) +{ + ExampleBlob* sess = getSession(session); + if (!sess) + { + return std::vector(); + } + + /* Is the offset beyond the array? */ + if (offset >= sizeof(sess->buffer)) + { + return std::vector(); + } + + /* Determine how many bytes we can read from the offset. + * In this case, if they read beyond "size" we allow it. + */ + uint32_t remain = sizeof(sess->buffer) - offset; + uint32_t numBytes = std::min(remain, requestedSize); + /* Copy the bytes! */ + std::vector result(numBytes); + std::memcpy(result.data(), &sess->buffer[offset], numBytes); + return result; +} + +bool ExampleBlobHandler::write(uint16_t session, uint32_t offset, + const std::vector& data) +{ + ExampleBlob* sess = getSession(session); + if (!sess) + { + return false; + } + /* Is the offset beyond the array? */ + if (offset >= sizeof(sess->buffer)) + { + return false; + } + /* Determine whether all their bytes will fit. */ + uint32_t remain = sizeof(sess->buffer) - offset; + if (data.size() > remain) + { + return false; + } + sess->length = + std::max(offset + data.size(), + static_cast::size_type>(sess->length)); + std::memcpy(&sess->buffer[offset], data.data(), data.size()); + return true; +} + +bool ExampleBlobHandler::commit(uint16_t session, + const std::vector& data) +{ + ExampleBlob* sess = getSession(session); + if (!sess) + { + return false; + } + + /* Do something with the staged data!. */ + + return false; +} + +bool ExampleBlobHandler::close(uint16_t session) +{ + ExampleBlob* sess = getSession(session); + if (!sess) + { + return false; + } + + sessions.erase(session); + return true; +} + +bool ExampleBlobHandler::stat(uint16_t session, struct BlobMeta* meta) +{ + ExampleBlob* sess = getSession(session); + if (!sess) + { + return false; + } + if (!meta) + { + return false; + } + meta->size = sess->length; + meta->blobState = sess->state; + return true; +} + +bool ExampleBlobHandler::expire(uint16_t session) +{ + ExampleBlob* sess = getSession(session); + if (!sess) + { + return false; + } + /* TODO: implement session expiration behavior. */ + return false; +} + +} // namespace blobs diff --git a/example/example.hpp b/example/example.hpp new file mode 100644 index 0000000..0ea9572 --- /dev/null +++ b/example/example.hpp @@ -0,0 +1,71 @@ +#pragma once + +#include "blobs.hpp" + +#include +#include +#include + +namespace blobs +{ + +constexpr int kBufferSize = 1024; + +struct ExampleBlob +{ + ExampleBlob() = default; + ExampleBlob(uint16_t id, uint16_t flags) : + sessionId(id), flags(flags), length(0) + { + } + + /* The blob handler session id. */ + uint16_t sessionId; + + /* The flags passed into open. */ + uint16_t flags; + + /* The buffer is a fixed size, but length represents the number of bytes + * expected to be used contiguously from offset 0. + */ + uint32_t length; + + /* The staging buffer. */ + uint8_t buffer[kBufferSize]; +}; + +class ExampleBlobHandler : public GenericBlobInterface +{ + public: + /* We want everything explicitly default. */ + ExampleBlobHandler() = default; + ~ExampleBlobHandler() = default; + ExampleBlobHandler(const ExampleBlobHandler&) = default; + ExampleBlobHandler& operator=(const ExampleBlobHandler&) = default; + ExampleBlobHandler(ExampleBlobHandler&&) = default; + ExampleBlobHandler& operator=(ExampleBlobHandler&&) = default; + + bool canHandleBlob(const std::string& path) override; + std::vector getBlobIds() override; + bool deleteBlob(const std::string& path) override; + bool stat(const std::string& path, struct BlobMeta* meta) override; + bool open(uint16_t session, uint16_t flags, + const std::string& path) override; + std::vector read(uint16_t session, uint32_t offset, + uint32_t requestedSize) override; + bool write(uint16_t session, uint32_t offset, + const std::vector& data) override; + bool commit(uint16_t session, const std::vector& data) override; + bool close(uint16_t session) override; + bool stat(uint16_t session, struct BlobMeta* meta) override; + bool expire(uint16_t session) override; + + constexpr static char supportedPath[] = "/dev/fake/command"; + + private: + ExampleBlob* getSession(uint16_t id); + + std::unordered_map sessions; +}; + +} // namespace blobs diff --git a/main.cpp b/main.cpp index e7c1247..a28a232 100644 --- a/main.cpp +++ b/main.cpp @@ -26,6 +26,10 @@ #include #include +#if ENABLE_EXAMPLE +#include "example/example.hpp" +#endif + /* TODO: Swap out once https://gerrit.openbmc-project.xyz/12743 is merged */ namespace oem { @@ -73,5 +77,9 @@ void setupBlobGlobalHandler() handleBlobCommand); manager = std::make_unique(); + +#if ENABLE_EXAMPLE + manager->registerHandler(std::move(std::make_unique())); +#endif } } // namespace blobs -- cgit v1.2.3