diff options
-rw-r--r-- | Makefile.am | 9 | ||||
-rw-r--r-- | configure.ac | 6 | ||||
-rw-r--r-- | example/example.cpp | 167 | ||||
-rw-r--r-- | example/example.hpp | 71 | ||||
-rw-r--r-- | main.cpp | 8 |
5 files changed, 260 insertions, 1 deletions
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 <algorithm> +#include <string> +#include <vector> + +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<std::string> 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<uint8_t> ExampleBlobHandler::read(uint16_t session, uint32_t offset, + uint32_t requestedSize) +{ + ExampleBlob* sess = getSession(session); + if (!sess) + { + return std::vector<uint8_t>(); + } + + /* Is the offset beyond the array? */ + if (offset >= sizeof(sess->buffer)) + { + return std::vector<uint8_t>(); + } + + /* 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<uint8_t> result(numBytes); + std::memcpy(result.data(), &sess->buffer[offset], numBytes); + return result; +} + +bool ExampleBlobHandler::write(uint16_t session, uint32_t offset, + const std::vector<uint8_t>& 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<std::vector<uint8_t>::size_type>(sess->length)); + std::memcpy(&sess->buffer[offset], data.data(), data.size()); + return true; +} + +bool ExampleBlobHandler::commit(uint16_t session, + const std::vector<uint8_t>& 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 <string> +#include <unordered_map> +#include <vector> + +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<std::string> 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<uint8_t> read(uint16_t session, uint32_t offset, + uint32_t requestedSize) override; + bool write(uint16_t session, uint32_t offset, + const std::vector<uint8_t>& data) override; + bool commit(uint16_t session, const std::vector<uint8_t>& 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<uint16_t, ExampleBlob> sessions; +}; + +} // namespace blobs @@ -26,6 +26,10 @@ #include <host-ipmid/oemrouter.hpp> #include <memory> +#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<BlobManager>(); + +#if ENABLE_EXAMPLE + manager->registerHandler(std::move(std::make_unique<ExampleBlobHandler>())); +#endif } } // namespace blobs |