xref: /openbmc/phosphor-ipmi-blobs/manager.hpp (revision fea1d8115bace4bedae2523a9d9389a990adb09f)
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     /**
240      * Given a file path will return first handler to answer that it owns
241      * it.
242      *
243      * @param[in] path - the file path.
244      * @return pointer to the handler or nullptr if not found.
245      */
246     GenericBlobInterface* getHandler(const std::string& path);
247 
248     /**
249      * Given a session id, update session time and return a handle to take
250      * action
251      *
252      * @param[in] session - session ID
253      * @param[in] requiredFlags - only return handle if the flags for this
254      *            session contain these flags; defaults to any flag
255      * @return session handler, nullptr if cannot get handler
256      */
257     GenericBlobInterface* getActionHandle(
258         uint16_t session,
259         uint16_t requiredFlags = std::numeric_limits<uint16_t>::max());
260 
261     /**
262      * Given a session id will return associated path.
263      *
264      * @param[in] session - the session.
265      * @return the path or "" on failure.
266      */
267     std::string getPath(uint16_t session) const;
268 
269   private:
270     /* Helper method to erase a session from all maps */
271     void eraseSession(GenericBlobInterface* handler, uint16_t session);
272     /* For each session owned by this handler, call expire if it is stale */
273     void cleanUpStaleSessions(GenericBlobInterface* handler);
274 
275     /* How long a session has to be inactive to be considered stale */
276     std::chrono::seconds sessionTimeout;
277     /* The next session ID to use */
278     uint16_t next;
279     /* Temporary list of blobIds used for enumeration. */
280     std::vector<std::string> ids;
281     /* List of Blob handler. */
282     std::vector<std::unique_ptr<GenericBlobInterface>> handlers;
283     /* Mapping of session ids to blob handlers and the path used with open.
284      */
285     std::unordered_map<uint16_t, SessionInfo> sessions;
286     /* Mapping of open blobIds */
287     std::unordered_map<std::string, int> openFiles;
288     /* Map of handlers to their open sessions */
289     std::unordered_map<GenericBlobInterface*, std::set<uint16_t>> openSessions;
290 };
291 
292 /**
293  * @brief Gets a handle to the BlobManager.
294  *
295  * @return a pointer to the BlobManager instance.
296  */
297 ManagerInterface* getBlobManager();
298 
299 } // namespace blobs
300