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