1 #pragma once 2 3 #include <blobs-ipmid/blobs.hpp> 4 #include <chrono> 5 #include <ctime> 6 #include <ipmid/oemrouter.hpp> 7 #include <memory> 8 #include <set> 9 #include <string> 10 #include <unordered_map> 11 #include <vector> 12 13 namespace blobs 14 { 15 16 using namespace std::chrono_literals; 17 18 /* The maximum read size. 19 * NOTE: Once this can be dynamically determined, we'll switch to that method. 20 * Having this in a header allows it to used cleanly for now. 21 */ 22 const int crcSize = sizeof(uint16_t); 23 const int btReplyHdrLen = 5; 24 const int btTransportLength = 64; 25 const uint32_t maximumReadSize = 26 btTransportLength - (btReplyHdrLen + oem::groupMagicSize + crcSize); 27 constexpr auto defaultSessionTimeout = 10min; 28 29 struct SessionInfo 30 { 31 SessionInfo() = default; 32 SessionInfo(const std::string& path, GenericBlobInterface* handler, 33 uint16_t flags) : 34 blobId(path), 35 handler(handler), flags(flags) 36 { 37 } 38 ~SessionInfo() = default; 39 40 std::string blobId; 41 GenericBlobInterface* handler; 42 uint16_t flags; 43 44 /* Initially set during open(). read/write/writeMeta/commit/stat operations 45 * would update it. 46 */ 47 std::chrono::time_point<std::chrono::steady_clock> lastActionTime = 48 std::chrono::steady_clock::now(); 49 }; 50 51 class ManagerInterface 52 { 53 public: 54 virtual ~ManagerInterface() = default; 55 56 virtual bool 57 registerHandler(std::unique_ptr<GenericBlobInterface> handler) = 0; 58 59 virtual uint32_t buildBlobList() = 0; 60 61 virtual std::string getBlobId(uint32_t index) = 0; 62 63 virtual bool open(uint16_t flags, const std::string& path, 64 uint16_t* session) = 0; 65 66 virtual bool stat(const std::string& path, BlobMeta* meta) = 0; 67 68 virtual bool stat(uint16_t session, BlobMeta* meta) = 0; 69 70 virtual bool commit(uint16_t session, const std::vector<uint8_t>& data) = 0; 71 72 virtual bool close(uint16_t session) = 0; 73 74 virtual std::vector<uint8_t> read(uint16_t session, uint32_t offset, 75 uint32_t requestedSize) = 0; 76 77 virtual bool write(uint16_t session, uint32_t offset, 78 const std::vector<uint8_t>& data) = 0; 79 80 virtual bool deleteBlob(const std::string& path) = 0; 81 82 virtual bool writeMeta(uint16_t session, uint32_t offset, 83 const std::vector<uint8_t>& data) = 0; 84 }; 85 86 /** 87 * Blob Manager used to store handlers and sessions. 88 */ 89 class BlobManager : public ManagerInterface 90 { 91 public: 92 BlobManager(std::chrono::seconds sessionTimeout = defaultSessionTimeout) : 93 sessionTimeout(sessionTimeout) 94 { 95 next = static_cast<uint16_t>(std::time(nullptr)); 96 }; 97 98 ~BlobManager() = default; 99 /* delete copy constructor & assignment operator, only support move 100 * operations. 101 */ 102 BlobManager(const BlobManager&) = delete; 103 BlobManager& operator=(const BlobManager&) = delete; 104 BlobManager(BlobManager&&) = default; 105 BlobManager& operator=(BlobManager&&) = default; 106 107 /** 108 * Register a handler. We own the pointer. 109 * 110 * @param[in] handler - a pointer to a blob handler. 111 * @return bool - true if registered. 112 */ 113 bool 114 registerHandler(std::unique_ptr<GenericBlobInterface> handler) override; 115 116 /** 117 * Builds the blobId list for enumeration. 118 * 119 * @return lowest value returned is 0, otherwise the number of 120 * blobIds. 121 */ 122 uint32_t buildBlobList() override; 123 124 /** 125 * Grabs the blobId for the indexed blobId. 126 * 127 * @param[in] index - the index into the blobId cache. 128 * @return string - the blobId or empty string on failure. 129 */ 130 std::string getBlobId(uint32_t index) override; 131 132 /** 133 * Attempts to open the file specified and associates with a session. 134 * 135 * @param[in] flags - the flags to pass to open. 136 * @param[in] path - the file path to open. 137 * @param[in,out] session - pointer to store the session on success. 138 * @return bool - true if able to open. 139 */ 140 bool open(uint16_t flags, const std::string& path, 141 uint16_t* session) override; 142 143 /** 144 * Attempts to retrieve a BlobMeta for the specified path. 145 * 146 * @param[in] path - the file path for stat(). 147 * @param[in,out] meta - a pointer to store the metadata. 148 * @return bool - true if able to retrieve the information. 149 */ 150 bool stat(const std::string& path, BlobMeta* meta) override; 151 152 /** 153 * Attempts to retrieve a BlobMeta for a given session. 154 * 155 * @param[in] session - the session for this command. 156 * @param[in,out] meta - a pointer to store the metadata. 157 * @return bool - true if able to retrieve the information. 158 */ 159 bool stat(uint16_t session, BlobMeta* meta) override; 160 161 /** 162 * Attempt to commit a blob for a given session. 163 * 164 * @param[in] session - the session for this command. 165 * @param[in] data - an optional commit blob. 166 * @return bool - true if the commit succeeds. 167 */ 168 bool commit(uint16_t session, const std::vector<uint8_t>& data) override; 169 170 /** 171 * Attempt to close a session. If the handler returns a failure 172 * in closing, the session is kept open. 173 * 174 * @param[in] session - the session for this command. 175 * @return bool - true if the session was closed. 176 */ 177 bool close(uint16_t session) override; 178 179 /** 180 * Attempt to read bytes from the blob. If there's a failure, such as 181 * an invalid offset it'll just return 0 bytes. 182 * 183 * @param[in] session - the session for this command. 184 * @param[in] offset - the offset from which to read. 185 * @param[in] requestedSize - the number of bytes to try and read. 186 * @return the bytes read. 187 */ 188 std::vector<uint8_t> read(uint16_t session, uint32_t offset, 189 uint32_t requestedSize) override; 190 191 /** 192 * Attempt to write to a blob. The manager does not track whether 193 * the session opened the file for writing. 194 * 195 * @param[in] session - the session for this command. 196 * @param[in] offset - the offset into the blob to write. 197 * @param[in] data - the bytes to write to the blob. 198 * @return bool - true if the write succeeded. 199 */ 200 bool write(uint16_t session, uint32_t offset, 201 const std::vector<uint8_t>& data) override; 202 203 /** 204 * Attempt to delete a blobId. This method will just call the 205 * handler, which will return failure if the blob doesn't support 206 * deletion. This command will also fail if there are any open 207 * sessions against the specific blob. 208 * 209 * In the case where they specify a folder, such as /blob/skm where 210 * the "real" blobIds are /blob/skm/1, or /blob/skm/2, the manager 211 * may see there are on open sessions to that specific path and will 212 * call the handler. In this case, the handler is responsible for 213 * handling any checks or logic. 214 * 215 * @param[in] path - the blobId path. 216 * @return bool - true if delete was successful. 217 */ 218 bool deleteBlob(const std::string& path) override; 219 220 /** 221 * Attempt to write Metadata to a blob. 222 * 223 * @param[in] session - the session for this command. 224 * @param[in] offset - the offset into the blob to write. 225 * @param[in] data - the bytes to write to the blob. 226 * @return bool - true if the write succeeded. 227 */ 228 bool writeMeta(uint16_t session, uint32_t offset, 229 const std::vector<uint8_t>& data) override; 230 231 /** 232 * Attempts to return a valid unique session id. 233 * 234 * @param[in,out] - pointer to the session. 235 * @return bool - true if able to allocate. 236 */ 237 bool getSession(uint16_t* session); 238 239 private: 240 /** 241 * Given a file path will return first handler to answer that it owns 242 * it. 243 * 244 * @param[in] path - the file path. 245 * @return pointer to the handler or nullptr if not found. 246 */ 247 GenericBlobInterface* getHandler(const std::string& path); 248 249 /** 250 * Given a session id, update session time and return a handler to take 251 * action 252 * 253 * @param[in] session - session ID 254 * @param[in] requiredFlags - only return handler if the flags for this 255 * session contain these flags; defaults to any flag 256 * @return session handler, nullptr if cannot get handler 257 */ 258 GenericBlobInterface* getActionHandler( 259 uint16_t session, 260 uint16_t requiredFlags = std::numeric_limits<uint16_t>::max()); 261 262 /** 263 * Helper method to erase a session from all maps 264 * 265 * @param[in] handler - handler pointer for lookup 266 * @param[in] session - session ID for lookup 267 * @return None 268 */ 269 void eraseSession(GenericBlobInterface* const handler, uint16_t session); 270 271 /** 272 * For each session owned by this handler, call expire if it is stale 273 * 274 * @param[in] handler - handler pointer for lookup 275 * @return None 276 */ 277 void cleanUpStaleSessions(GenericBlobInterface* const handler); 278 279 /* How long a session has to be inactive to be considered stale */ 280 std::chrono::seconds sessionTimeout; 281 /* The next session ID to use */ 282 uint16_t next; 283 /* Temporary list of blobIds used for enumeration. */ 284 std::vector<std::string> ids; 285 /* List of Blob handler. */ 286 std::vector<std::unique_ptr<GenericBlobInterface>> handlers; 287 /* Mapping of session ids to blob handlers and the path used with open. 288 */ 289 std::unordered_map<uint16_t, SessionInfo> sessions; 290 /* Mapping of open blobIds */ 291 std::unordered_map<std::string, int> openFiles; 292 /* Map of handlers to their open sessions */ 293 std::unordered_map<GenericBlobInterface*, std::set<uint16_t>> openSessions; 294 }; 295 296 /** 297 * @brief Gets a handle to the BlobManager. 298 * 299 * @return a pointer to the BlobManager instance. 300 */ 301 ManagerInterface* getBlobManager(); 302 303 } // namespace blobs 304