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