diff options
author | Patrick Venture <venture@google.com> | 2018-09-12 08:53:29 -0700 |
---|---|---|
committer | Patrick Venture <venture@google.com> | 2018-09-15 13:11:30 -0700 |
commit | ef3aeadc9be37c47d0627e576e81a74a5bb9e94f (patch) | |
tree | 95c183977468b107bdd3faaaa988b5d853be2f00 /manager.cpp | |
parent | baa73da1abaaf05ea1133319405fb2b891825618 (diff) | |
download | phosphor-ipmi-blobs-ef3aeadc9be37c47d0627e576e81a74a5bb9e94f.tar.gz phosphor-ipmi-blobs-ef3aeadc9be37c47d0627e576e81a74a5bb9e94f.zip |
initial drop of phosphor-ipmi-blobs
This implements a majority of the OEM IPMI BLOBS protocol. The only
piece missing from this is the timed expiration of sessions.
Change-Id: I82c9d17b625c94fc3340edcfabbbf1ffeb5ad7ac
Signed-off-by: Patrick Venture <venture@google.com>
Diffstat (limited to 'manager.cpp')
-rw-r--r-- | manager.cpp | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/manager.cpp b/manager.cpp new file mode 100644 index 0000000..b6311b4 --- /dev/null +++ b/manager.cpp @@ -0,0 +1,347 @@ +/* + * Copyright 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "manager.hpp" + +#include <string> +#include <vector> + +namespace blobs +{ + +void BlobManager::incrementOpen(const std::string& path) +{ + if (path.empty()) + { + return; + } + + openFiles[path] += 1; +} + +void BlobManager::decrementOpen(const std::string& path) +{ + if (path.empty()) + { + return; + } + + /* TODO(venture): Check into the iterator from find, does it makes sense + * to just update it directly? */ + auto entry = openFiles.find(path); + if (entry != openFiles.end()) + { + /* found it, decrement it and remove it if 0. */ + openFiles[path] -= 1; + if (openFiles[path] == 0) + { + openFiles.erase(path); + } + } +} + +int BlobManager::getOpen(const std::string& path) const +{ + /* No need to input check on the read-only call. */ + auto entry = openFiles.find(path); + if (entry != openFiles.end()) + { + return entry->second; + } + + return 0; +} + +bool BlobManager::registerHandler(std::unique_ptr<GenericBlobInterface> handler) +{ + if (!handler) + { + return false; + } + + handlers.push_back(std::move(handler)); + return true; +} + +uint32_t BlobManager::buildBlobList() +{ + /* Clear out the current list (IPMI handler is presently single-threaded). + */ + ids.clear(); + + /* Grab the list of blobs and extend the local list */ + for (auto& h : handlers) + { + std::vector<std::string> blobs = h->getBlobIds(); + ids.insert(ids.end(), blobs.begin(), blobs.end()); + } + + return ids.size(); +} + +std::string BlobManager::getBlobId(uint32_t index) +{ + /* Range check. */ + if (index >= ids.size()) + { + return ""; + } + + return ids[index]; +} + +bool BlobManager::open(uint16_t flags, const std::string& path, + uint16_t* session) +{ + GenericBlobInterface* handler = getHandler(path); + + /* No handler found. */ + if (!handler) + { + return false; + } + + /* No sessions availabe... */ + if (!getSession(session)) + { + return false; + } + + /* Verify flags - must be at least read or write */ + if (!(flags & (OpenFlags::read | OpenFlags::write))) + { + /* Neither read not write set, which means calls to Read/Write will + * reject. */ + return false; + } + + if (!handler->open(*session, flags, path)) + { + return false; + } + + /* Associate session with handler */ + sessions[*session] = SessionInfo(path, handler, flags); + incrementOpen(path); + return true; +} + +GenericBlobInterface* BlobManager::getHandler(const std::string& path) +{ + /* Find a handler. */ + GenericBlobInterface* handler = nullptr; + + for (auto& h : handlers) + { + if (h->canHandleBlob(path)) + { + handler = h.get(); + break; + } + } + + return handler; +} + +GenericBlobInterface* BlobManager::getHandler(uint16_t session) +{ + auto item = sessions.find(session); + if (item == sessions.end()) + { + return nullptr; + } + + return item->second.handler; +} + +SessionInfo* BlobManager::getSessionInfo(uint16_t session) +{ + auto item = sessions.find(session); + if (item == sessions.end()) + { + return nullptr; + } + + /* If we go to multi-threaded, this pointer can be invalidated and this + * method will need to change. + */ + return &item->second; +} + +std::string BlobManager::getPath(uint16_t session) const +{ + auto item = sessions.find(session); + if (item == sessions.end()) + { + return ""; + } + + return item->second.blobId; +} + +bool BlobManager::stat(const std::string& path, struct BlobMeta* meta) +{ + /* meta should never be NULL. */ + GenericBlobInterface* handler = getHandler(path); + + /* No handler found. */ + if (!handler) + { + return false; + } + + return handler->stat(path, meta); +} + +bool BlobManager::stat(uint16_t session, struct BlobMeta* meta) +{ + /* meta should never be NULL. */ + GenericBlobInterface* handler = getHandler(session); + + /* No handler found. */ + if (!handler) + { + return false; + } + + return handler->stat(session, meta); +} + +bool BlobManager::commit(uint16_t session, const std::vector<uint8_t>& data) +{ + GenericBlobInterface* handler = getHandler(session); + + /* No handler found. */ + if (!handler) + { + return false; + } + + return handler->commit(session, data); +} + +bool BlobManager::close(uint16_t session) +{ + GenericBlobInterface* handler = getHandler(session); + + /* No handler found. */ + if (!handler) + { + return false; + } + + /* Handler returns failure */ + if (!handler->close(session)) + { + return false; + } + + sessions.erase(session); + decrementOpen(getPath(session)); + return true; +} + +std::vector<uint8_t> BlobManager::read(uint16_t session, uint32_t offset, + uint32_t requestedSize) +{ + SessionInfo* info = getSessionInfo(session); + + /* No session found. */ + if (!info) + { + return std::vector<uint8_t>(); + } + + /* Check flags. */ + if (!(info->flags & OpenFlags::read)) + { + return std::vector<uint8_t>(); + } + + /* Try reading from it. */ + return info->handler->read(session, offset, requestedSize); +} + +bool BlobManager::write(uint16_t session, uint32_t offset, + const std::vector<uint8_t>& data) +{ + SessionInfo* info = getSessionInfo(session); + + /* No session found. */ + if (!info) + { + return false; + } + + /* Check flags. */ + if (!(info->flags & OpenFlags::write)) + { + return false; + } + + /* Try writing to it. */ + return info->handler->write(session, offset, data); +} + +bool BlobManager::deleteBlob(const std::string& path) +{ + GenericBlobInterface* handler = getHandler(path); + + /* No handler found. */ + if (!handler) + { + return false; + } + + /* Check if the file has any open handles. */ + if (getOpen(path) > 0) + { + return false; + } + + /* Try deleting it. */ + return handler->deleteBlob(path); +} + +bool BlobManager::getSession(uint16_t* sess) +{ + uint16_t tries = 0; + uint16_t lsess; + + if (!sess) + { + return false; + } + + /* This is not meant to fail as you have 64KiB values available. */ + + /* TODO(venture): We could just count the keys in the session map to know + * if it's full. + */ + do + { + lsess = next++; + if (!sessions.count(lsess)) + { + /* value not in use, return it. */ + (*sess) = lsess; + return true; + } + } while (++tries < 0xffff); + + return false; +} +} // namespace blobs |