/src/PcapPlusPlus/Packet++/header/Layer.h
Line | Count | Source |
1 | | #pragma once |
2 | | |
3 | | #include <stdint.h> |
4 | | #include <stdio.h> |
5 | | #include "ProtocolType.h" |
6 | | #include <ostream> |
7 | | #include <string> |
8 | | #include <stdexcept> |
9 | | #include <utility> |
10 | | |
11 | | /// @file |
12 | | |
13 | | /// @namespace pcpp |
14 | | /// @brief The main namespace for the PcapPlusPlus lib |
15 | | namespace pcpp |
16 | | { |
17 | | |
18 | | /// @class IDataContainer |
19 | | /// An interface (virtual abstract class) that indicates an object that holds a pointer to a buffer data. The Layer |
20 | | /// class is an example of such object, hence it inherits this interface |
21 | | class IDataContainer |
22 | | { |
23 | | public: |
24 | | /// Get a pointer to the data |
25 | | /// @param[in] offset Get a pointer in a certain offset. Default is 0 - get a pointer to start of data |
26 | | /// @return A pointer to the data |
27 | | virtual uint8_t* getDataPtr(size_t offset = 0) const = 0; |
28 | | |
29 | | virtual ~IDataContainer() = default; |
30 | | }; |
31 | | |
32 | | class Packet; |
33 | | |
34 | | namespace internal |
35 | | { |
36 | | /// @brief Holds information about a Layer's data and object ownership. |
37 | | struct LayerAllocationInfo |
38 | | { |
39 | | /// @brief Pointer to the Packet this layer is attached to (if any). |
40 | | /// |
41 | | /// If the layer is attached to a Packet, the layer's memory span (data) is considered managed by the |
42 | | /// Packet. The Packet is responsible for keeping the layer's memory span valid and updating it should it |
43 | | /// become necessary as long as the layer is attached to it. |
44 | | /// |
45 | | /// In an event the Packet is destroyed, all of its attached layers's memory views are considered invalid. |
46 | | /// Accessing layer data after the Packet is destroyed results in undefined behavior. |
47 | | /// |
48 | | /// If nullptr, the layer is not attached to any Packet and is considered unmanaged. |
49 | | /// It also means the layer's memory span is considered owned by the layer itself and will be freed when |
50 | | /// the layer is destroyed. |
51 | | Packet* attachedPacket = nullptr; |
52 | | |
53 | | /// @brief Controls if the layer object is considered owned by the attached Packet |
54 | | /// |
55 | | /// If 'true', the Layer object is considered owned by the attached Packet and will be freed by it on Packet |
56 | | /// destruction. |
57 | | /// |
58 | | /// If 'false', the Layer object is considered unmanaged and the user is responsible for freeing it. |
59 | | /// This is commonly the case for layers created on the stack and attached to a Packet. |
60 | | bool ownedByPacket = false; |
61 | | |
62 | | /// @brief Sets the state of attachment to a specified Packet |
63 | | /// @param packet Pointer to the Packet this layer is attached to (or nullptr if not attached to any Packet) |
64 | | /// @param managed True if the layer object's lifetime is to be managed by the Packet, false otherwise |
65 | | /// @param force If true, bypasses the check for existing attachment. Default is false. |
66 | | /// @throws std::runtime_error if the layer is already attached to a Packet and 'force' is false |
67 | | void attachPacket(Packet* packet, bool managed, bool force = false) |
68 | 0 | { |
69 | 0 | if (!force && attachedPacket != nullptr) |
70 | 0 | { |
71 | 0 | throw std::runtime_error("Layer is already attached to a Packet"); |
72 | 0 | } |
73 | 0 |
|
74 | 0 | attachedPacket = packet; |
75 | 0 | ownedByPacket = managed; |
76 | 0 | } |
77 | | |
78 | | /// @brief Clears the attachment to any Packet, resetting to unmanaged state. |
79 | | void detach() |
80 | 0 | { |
81 | 0 | attachedPacket = nullptr; |
82 | 0 | ownedByPacket = false; |
83 | 0 | } |
84 | | }; |
85 | | } // namespace internal |
86 | | |
87 | | /// @class Layer |
88 | | /// Layer is the base class for all protocol layers. Each protocol supported in PcapPlusPlus has a class that |
89 | | /// inherits Layer. |
90 | | /// The protocol layer class expose all properties and methods relevant for viewing and editing protocol fields. |
91 | | /// For example: a pointer to a structured header (e.g tcphdr, iphdr, etc.), protocol header size, payload size, |
92 | | /// compute fields that can be automatically computed, print protocol data to string, etc. |
93 | | /// Each protocol instance is obviously part of a protocol stack (which construct a packet). This protocol stack is |
94 | | /// represented in PcapPlusPlus in a linked list, and each layer is an element in this list. That's why each layer |
95 | | /// has properties to the next and previous layer in the protocol stack. The Layer class, as a base class, is |
96 | | /// abstract and the user can't create an instance of it (it has a private constructor). Each layer holds a pointer |
97 | | /// to the relevant place in the packet. The layer sees all the data from this pointer forward until the end of the |
98 | | /// packet. Here is an example packet showing this concept: |
99 | | /// |
100 | | /// @code{.unparsed} |
101 | | /// ==================================================== |
102 | | /// |Eth |IPv4 |TCP |Packet | |
103 | | /// |Header |Header |Header |Payload | |
104 | | /// ==================================================== |
105 | | /// |
106 | | /// |--------------------------------------------------| |
107 | | /// EthLayer data |
108 | | /// |---------------------------------------| |
109 | | /// IPv4Layer data |
110 | | /// |---------------------------| |
111 | | /// TcpLayer data |
112 | | /// |----------------| |
113 | | /// PayloadLayer data |
114 | | /// @endcode |
115 | | class Layer : public IDataContainer |
116 | | { |
117 | | friend class Packet; |
118 | | |
119 | | public: |
120 | | /// A destructor for this class. Frees the data if it was allocated by the layer constructor (see |
121 | | /// isAllocatedToPacket() for more info) |
122 | | ~Layer() override; |
123 | | |
124 | | /// @return A pointer to the next layer in the protocol stack or nullptr if the layer is the last one |
125 | | Layer* getNextLayer() const |
126 | 0 | { |
127 | 0 | return m_NextLayer; |
128 | 0 | } |
129 | | |
130 | | /// @return A pointer to the previous layer in the protocol stack or nullptr if the layer is the first one |
131 | | Layer* getPrevLayer() const |
132 | 0 | { |
133 | 0 | return m_PrevLayer; |
134 | 0 | } |
135 | | |
136 | | /// @return The protocol enum |
137 | | ProtocolType getProtocol() const |
138 | 0 | { |
139 | 0 | return m_Protocol; |
140 | 0 | } |
141 | | |
142 | | /// Check if the layer's protocol matches a protocol family |
143 | | /// @param protocolTypeFamily The protocol family to check |
144 | | /// @return True if the layer's protocol matches the protocol family, false otherwise |
145 | | bool isMemberOfProtocolFamily(ProtocolTypeFamily protocolTypeFamily) const; |
146 | | |
147 | | /// @return A pointer to the layer raw data. In most cases it'll be a pointer to the first byte of the header |
148 | | uint8_t* getData() const |
149 | 0 | { |
150 | 0 | return m_Data; |
151 | 0 | } |
152 | | |
153 | | /// @return The length in bytes of the data from the first byte of the header until the end of the packet |
154 | | size_t getDataLen() const |
155 | 0 | { |
156 | 0 | return m_DataLen; |
157 | 0 | } |
158 | | |
159 | | /// @return A pointer for the layer payload, meaning the first byte after the header |
160 | | uint8_t* getLayerPayload() const |
161 | 0 | { |
162 | 0 | return m_Data + getHeaderLen(); |
163 | 0 | } |
164 | | |
165 | | /// @return The size in bytes of the payload |
166 | | size_t getLayerPayloadSize() const |
167 | 0 | { |
168 | 0 | return m_DataLen - getHeaderLen(); |
169 | 0 | } |
170 | | |
171 | | /// Raw data in layers can come from one of sources: |
172 | | /// 1. from an existing packet - this is the case when parsing packets received from files or the network. In |
173 | | /// this case the data was already allocated by someone else, and layer only holds the pointer to the relevant |
174 | | /// place inside this data |
175 | | /// 2. when creating packets, data is allocated when layer is created. In this case the layer is responsible for |
176 | | /// freeing it as well |
177 | | /// |
178 | | /// @return Returns true if the data was allocated by an external source (a packet) or false if it was allocated |
179 | | /// by the layer itself |
180 | | bool isAllocatedToPacket() const |
181 | 0 | { |
182 | 0 | return m_AllocationInfo.attachedPacket != nullptr; |
183 | 0 | } |
184 | | |
185 | | /// Copy the raw data of this layer to another array |
186 | | /// @param[out] toArr The destination byte array |
187 | | void copyData(uint8_t* toArr) const; |
188 | | |
189 | | // implement abstract methods |
190 | | |
191 | | uint8_t* getDataPtr(size_t offset = 0) const override |
192 | 0 | { |
193 | 0 | return static_cast<uint8_t*>(m_Data + offset); |
194 | 0 | } |
195 | | |
196 | | // abstract methods |
197 | | |
198 | | /// Each layer is responsible for parsing the next layer |
199 | | virtual void parseNextLayer() = 0; |
200 | | |
201 | | /// @return The header length in bytes |
202 | | virtual size_t getHeaderLen() const = 0; |
203 | | |
204 | | /// Each layer can compute field values automatically using this method. This is an abstract method |
205 | | virtual void computeCalculateFields() = 0; |
206 | | |
207 | | /// @return A string representation of the layer most important data (should look like the layer description in |
208 | | /// Wireshark) |
209 | | virtual std::string toString() const = 0; |
210 | | |
211 | | /// @return The OSI Model layer this protocol belongs to |
212 | | virtual OsiModelLayer getOsiModelLayer() const = 0; |
213 | | |
214 | | protected: |
215 | | uint8_t* m_Data; |
216 | | size_t m_DataLen; |
217 | | ProtocolType m_Protocol; |
218 | | Layer* m_NextLayer; |
219 | | Layer* m_PrevLayer; |
220 | | |
221 | | private: |
222 | | internal::LayerAllocationInfo m_AllocationInfo; |
223 | | |
224 | | protected: |
225 | | Layer() : m_Data(nullptr), m_DataLen(0), m_Protocol(UnknownProtocol), m_NextLayer(nullptr), m_PrevLayer(nullptr) |
226 | 0 | {} |
227 | | |
228 | | Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ProtocolType protocol = UnknownProtocol) |
229 | | : m_Data(data), m_DataLen(dataLen), m_Protocol(protocol), m_NextLayer(nullptr), m_PrevLayer(prevLayer), |
230 | | m_AllocationInfo{ packet, false } |
231 | 0 | {} |
232 | | |
233 | | // Copy c'tor |
234 | | Layer(const Layer& other); |
235 | | Layer& operator=(const Layer& other); |
236 | | |
237 | | /// @brief Get a pointer to the Packet this layer is attached to (if any). |
238 | | /// @return A pointer to the Packet this layer is attached to, or nullptr if the layer is not attached. |
239 | | Packet* getAttachedPacket() |
240 | 0 | { |
241 | 0 | return m_AllocationInfo.attachedPacket; |
242 | 0 | } |
243 | | |
244 | | /// @brief Get a pointer to the Packet this layer is attached to (if any). |
245 | | /// @return A const pointer to the Packet this layer is attached to, or nullptr if the layer is not attached. |
246 | | Packet const* getAttachedPacket() const |
247 | 0 | { |
248 | 0 | return m_AllocationInfo.attachedPacket; |
249 | 0 | } |
250 | | |
251 | | void setNextLayer(Layer* nextLayer) |
252 | 0 | { |
253 | 0 | m_NextLayer = nextLayer; |
254 | 0 | } |
255 | | void setPrevLayer(Layer* prevLayer) |
256 | 0 | { |
257 | 0 | m_PrevLayer = prevLayer; |
258 | 0 | } |
259 | | |
260 | | virtual bool extendLayer(int offsetInLayer, size_t numOfBytesToExtend); |
261 | | virtual bool shortenLayer(int offsetInLayer, size_t numOfBytesToShorten); |
262 | | |
263 | | bool hasNextLayer() const |
264 | 0 | { |
265 | 0 | return m_NextLayer != nullptr; |
266 | 0 | } |
267 | | |
268 | | /// @brief Construct the next layer in the protocol stack. No validation is performed on the data. |
269 | | /// |
270 | | /// This overload infers the Packet from the current layer. |
271 | | /// |
272 | | /// @tparam T The type of the layer to construct |
273 | | /// @tparam Args The types of the arguments to pass to the layer constructor |
274 | | /// @param data The data to construct the layer from |
275 | | /// @param dataLen The length of the data |
276 | | /// @param extraArgs Extra arguments to be forwarded to the layer constructor |
277 | | /// @return The constructed layer |
278 | | template <typename T, typename... Args> |
279 | | Layer* constructNextLayer(uint8_t* data, size_t dataLen, Args&&... extraArgs) |
280 | | { |
281 | | return constructNextLayer<T>(data, dataLen, getAttachedPacket(), std::forward<Args>(extraArgs)...); |
282 | | } |
283 | | |
284 | | /// Construct the next layer in the protocol stack. No validation is performed on the data. |
285 | | /// @tparam T The type of the layer to construct |
286 | | /// @tparam Args The types of the arguments to pass to the layer constructor |
287 | | /// @param[in] data The data to construct the layer from |
288 | | /// @param[in] dataLen The length of the data |
289 | | /// @param[in] packet The packet the layer belongs to |
290 | | /// @param[in] extraArgs Extra arguments to be forwarded to the layer constructor |
291 | | /// @return The constructed layer |
292 | | template <typename T, typename... Args> |
293 | | Layer* constructNextLayer(uint8_t* data, size_t dataLen, Packet* packet, Args&&... extraArgs) |
294 | | { |
295 | | if (hasNextLayer()) |
296 | | { |
297 | | throw std::runtime_error("Next layer already exists"); |
298 | | } |
299 | | |
300 | | Layer* newLayer = new T(data, dataLen, this, packet, std::forward<Args>(extraArgs)...); |
301 | | setNextLayer(newLayer); |
302 | | return newLayer; |
303 | | } |
304 | | |
305 | | /// @brief Construct the next layer in the protocol stack using a factory functor. |
306 | | /// |
307 | | /// No validation is performed on the data, outside of what the factory functor may perform. |
308 | | /// If the factory returns a nullptr, no next layer is set. |
309 | | /// |
310 | | /// The factory functor is expected to have the following signature: |
311 | | /// Layer* factoryFn(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ...); |
312 | | /// |
313 | | /// This overload infers the Packet from the current layer. |
314 | | /// |
315 | | /// @tparam TFactory The factory functor type. |
316 | | /// @tparam ...Args Parameter pack for extra arguments to pass to the factory functor. |
317 | | /// @param[in] factoryFn The factory functor to create the layer. |
318 | | /// @param[in] data The data to construct the layer from |
319 | | /// @param[in] dataLen The length of the data |
320 | | /// @param[in] extraArgs Extra arguments to be forwarded to the factory. |
321 | | /// @return The return value of the factory functor. |
322 | | template <typename TFactory, typename... Args> |
323 | | Layer* constructNextLayerFromFactory(TFactory factoryFn, uint8_t* data, size_t dataLen, Args&&... extraArgs) |
324 | | { |
325 | | return constructNextLayerFromFactory<TFactory>(factoryFn, data, dataLen, getAttachedPacket(), |
326 | | std::forward<Args>(extraArgs)...); |
327 | | } |
328 | | |
329 | | /// @brief Construct the next layer in the protocol stack using a factory functor. |
330 | | /// |
331 | | /// No validation is performed on the data, outside of what the factory functor may perform. |
332 | | /// If the factory returns a nullptr, no next layer is set. |
333 | | /// |
334 | | /// The factory functor is expected to have the following signature: |
335 | | /// Layer* factoryFn(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ...); |
336 | | /// |
337 | | /// @tparam TFactory The factory functor type. |
338 | | /// @tparam ...Args Parameter pack for extra arguments to pass to the factory functor. |
339 | | /// @param[in] factoryFn The factory functor to create the layer. |
340 | | /// @param[in] data The data to construct the layer from |
341 | | /// @param[in] dataLen The length of the data |
342 | | /// @param[in] packet The packet the layer belongs to |
343 | | /// @param[in] extraArgs Extra arguments to be forwarded to the factory. |
344 | | /// @return The return value of the factory functor. |
345 | | template <typename TFactory, typename... Args> |
346 | | Layer* constructNextLayerFromFactory(TFactory factoryFn, uint8_t* data, size_t dataLen, Packet* packet, |
347 | | Args&&... extraArgs) |
348 | | { |
349 | | if (hasNextLayer()) |
350 | | { |
351 | | throw std::runtime_error("Next layer already exists"); |
352 | | } |
353 | | |
354 | | // cppcheck-suppress redundantInitialization |
355 | | Layer* newLayer = factoryFn(data, dataLen, this, packet, std::forward<Args>(extraArgs)...); |
356 | | setNextLayer(newLayer); |
357 | | return newLayer; |
358 | | } |
359 | | |
360 | | /// Try to construct the next layer in the protocol stack. |
361 | | /// |
362 | | /// This overload infers the Packet from the current layer. |
363 | | /// |
364 | | /// The method checks if the data is valid for the layer type T before constructing it by calling |
365 | | /// T::isDataValid(data, dataLen). If the data is invalid, no layer is constructed and a nullptr is returned. |
366 | | /// |
367 | | /// @tparam T The type of the layer to construct |
368 | | /// @tparam Args The types of the extra arguments to pass to the layer constructor |
369 | | /// @param[in] data The data to construct the layer from |
370 | | /// @param[in] dataLen The length of the data |
371 | | /// @param[in] extraArgs Extra arguments to be forwarded to the layer constructor |
372 | | /// @return The constructed layer or nullptr if the data is invalid |
373 | | template <typename T, typename... Args> |
374 | | Layer* tryConstructNextLayer(uint8_t* data, size_t dataLen, Args&&... extraArgs) |
375 | | { |
376 | | return tryConstructNextLayer<T>(data, dataLen, getAttachedPacket(), std::forward<Args>(extraArgs)...); |
377 | | } |
378 | | |
379 | | /// Try to construct the next layer in the protocol stack. |
380 | | /// |
381 | | /// The method checks if the data is valid for the layer type T before constructing it by calling |
382 | | /// T::isDataValid(data, dataLen). If the data is invalid, no layer is constructed and a nullptr is returned. |
383 | | /// |
384 | | /// @tparam T The type of the layer to construct |
385 | | /// @tparam Args The types of the extra arguments to pass to the layer constructor |
386 | | /// @param[in] data The data to construct the layer from |
387 | | /// @param[in] dataLen The length of the data |
388 | | /// @param[in] packet The packet the layer belongs to |
389 | | /// @param[in] extraArgs Extra arguments to be forwarded to the layer constructor |
390 | | /// @return The constructed layer or nullptr if the data is invalid |
391 | | template <typename T, typename... Args> |
392 | | Layer* tryConstructNextLayer(uint8_t* data, size_t dataLen, Packet* packet, Args&&... extraArgs) |
393 | | { |
394 | | if (T::isDataValid(data, dataLen)) |
395 | | { |
396 | | return constructNextLayer<T>(data, dataLen, packet, std::forward<Args>(extraArgs)...); |
397 | | } |
398 | | return nullptr; |
399 | | } |
400 | | |
401 | | /// @brief Try to construct the next layer in the protocol stack with a fallback option. |
402 | | /// |
403 | | /// This overload infers the Packet from the current layer. |
404 | | /// |
405 | | /// The method checks if the data is valid for the layer type T before constructing it by calling |
406 | | /// T::isDataValid(data, dataLen). If the data is invalid, it constructs the layer of type TFallback. |
407 | | /// |
408 | | /// @tparam T The type of the layer to construct |
409 | | /// @tparam TFallback The fallback layer type to construct if T fails |
410 | | /// @tparam Args The types of the extra arguments to pass to the layer constructor of T |
411 | | /// @param[in] data The data to construct the layer from |
412 | | /// @param[in] dataLen The length of the data |
413 | | /// @param[in] extraArgs Extra arguments to be forwarded to the layer constructor of T |
414 | | /// @return The constructed layer of type T or TFallback |
415 | | /// @remarks The parameters extraArgs are forwarded to the factory function, but not to the TFallback |
416 | | /// constructor. |
417 | | template <typename T, typename TFallback, typename... Args> |
418 | | Layer* tryConstructNextLayerWithFallback(uint8_t* data, size_t dataLen, Args&&... extraArgs) |
419 | | { |
420 | | return tryConstructNextLayerWithFallback<T, TFallback>(data, dataLen, getAttachedPacket(), |
421 | | std::forward<Args>(extraArgs)...); |
422 | | } |
423 | | |
424 | | /// Try to construct the next layer in the protocol stack with a fallback option. |
425 | | /// |
426 | | /// The method checks if the data is valid for the layer type T before constructing it by calling |
427 | | /// T::isDataValid(data, dataLen). If the data is invalid, it constructs the layer of type TFallback. |
428 | | /// |
429 | | /// @tparam T The type of the layer to construct |
430 | | /// @tparam TFallback The fallback layer type to construct if T fails |
431 | | /// @tparam Args The types of the extra arguments to pass to the layer constructor of T |
432 | | /// @param[in] data The data to construct the layer from |
433 | | /// @param[in] dataLen The length of the data |
434 | | /// @param[in] packet The packet the layer belongs to |
435 | | /// @param[in] extraArgs Extra arguments to be forwarded to the layer constructor of T |
436 | | /// @return The constructed layer of type T or TFallback |
437 | | /// @remarks The parameters extraArgs are forwarded to the factory function, but not to the TFallback |
438 | | /// constructor. |
439 | | template <typename T, typename TFallback, typename... Args> |
440 | | Layer* tryConstructNextLayerWithFallback(uint8_t* data, size_t dataLen, Packet* packet, Args&&... extraArgs) |
441 | | { |
442 | | if (tryConstructNextLayer<T>(data, dataLen, packet, std::forward<Args>(extraArgs)...)) |
443 | | { |
444 | | return m_NextLayer; |
445 | | } |
446 | | |
447 | | return constructNextLayer<TFallback>(data, dataLen, packet); |
448 | | } |
449 | | |
450 | | /// @brief Try to construct the next layer in the protocol stack using a factory functor with a fallback option. |
451 | | /// |
452 | | /// The method will attempt to construct the next layer using the provided factory function. |
453 | | /// If the factory function returns nullptr, indicating failure to create the layer, the method will then |
454 | | /// construct a layer of type TFallback. |
455 | | /// |
456 | | /// The factory functor is expected to have the following signature: |
457 | | /// Layer* factoryFn(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ...); |
458 | | /// |
459 | | /// This overload infers the Packet from the current layer. |
460 | | /// |
461 | | /// @tparam TFallback The fallback layer type to construct if the factory fails. |
462 | | /// @tparam TFactory The factory functor type. |
463 | | /// @tparam ...Args Parameter pack for extra arguments to pass to the factory functor. |
464 | | /// @param[in] factoryFn The factory functor to create the layer. |
465 | | /// @param[in] data The data to construct the layer from |
466 | | /// @param[in] dataLen The length of the data |
467 | | /// @param[in] extraArgs Extra arguments to be forwarded to the factory. |
468 | | /// @return The return value of the factory functor. |
469 | | /// @remarks The parameters extraArgs are forwarded to the factory function, but not to the TFallback |
470 | | /// constructor. |
471 | | template <typename TFallback, typename TFactory, typename... Args> |
472 | | Layer* tryConstructNextLayerFromFactoryWithFallback(TFactory factoryFn, uint8_t* data, size_t dataLen, |
473 | | Args&&... extraArgs) |
474 | | { |
475 | | // Note that the fallback is first to allow template argument deduction of the factory type. |
476 | | return tryConstructNextLayerFromFactoryWithFallback<TFallback, TFactory>( |
477 | | factoryFn, data, dataLen, getAttachedPacket(), std::forward<Args>(extraArgs)...); |
478 | | } |
479 | | |
480 | | /// @brief Try to construct the next layer in the protocol stack using a factory functor with a fallback option. |
481 | | /// |
482 | | /// The method will attempt to construct the next layer using the provided factory function. |
483 | | /// If the factory function returns nullptr, indicating failure to create the layer, the method will then |
484 | | /// construct a layer of type TFallback. |
485 | | /// |
486 | | /// The factory functor is expected to have the following signature: |
487 | | /// Layer* factoryFn(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ...); |
488 | | /// |
489 | | /// @tparam TFallback The fallback layer type to construct if the factory fails. |
490 | | /// @tparam TFactory The factory functor type. |
491 | | /// @tparam ...Args Parameter pack for extra arguments to pass to the factory functor. |
492 | | /// @param[in] factoryFn The factory functor to create the layer. |
493 | | /// @param[in] data The data to construct the layer from |
494 | | /// @param[in] dataLen The length of the data |
495 | | /// @param[in] packet The packet the layer belongs to |
496 | | /// @param[in] extraArgs Extra arguments to be forwarded to the factory. |
497 | | /// @return The return value of the factory functor. |
498 | | /// @remarks The parameters extraArgs are forwarded to the factory function, but not to the TFallback |
499 | | /// constructor. |
500 | | template <typename TFallback, typename TFactory, typename... Args> |
501 | | Layer* tryConstructNextLayerFromFactoryWithFallback(TFactory factoryFn, uint8_t* data, size_t dataLen, |
502 | | Packet* packet, Args&&... extraArgs) |
503 | | { |
504 | | auto nextLayer = constructNextLayerFromFactory<TFactory>(factoryFn, data, dataLen, packet, |
505 | | std::forward<Args>(extraArgs)...); |
506 | | if (nextLayer != nullptr) |
507 | | { |
508 | | return nextLayer; |
509 | | } |
510 | | |
511 | | // factory failed, construct fallback layer |
512 | | return constructNextLayer<TFallback>(data, dataLen, packet); |
513 | | } |
514 | | |
515 | | /// @brief Check if the data is large enough to reinterpret as a type |
516 | | /// |
517 | | /// The data must be non-null and at least as large as the type |
518 | | /// |
519 | | /// @tparam T The type to reinterpret as |
520 | | /// @param data The data to check |
521 | | /// @param dataLen The length of the data |
522 | | /// @return True if the data is large enough to reinterpret as T, false otherwise |
523 | | template <typename T> static bool canReinterpretAs(const uint8_t* data, size_t dataLen) |
524 | 0 | { |
525 | 0 | return data != nullptr && dataLen >= sizeof(T); |
526 | 0 | } Unexecuted instantiation: bool pcpp::Layer::canReinterpretAs<pcpp::arphdr>(unsigned char const*, unsigned long) Unexecuted instantiation: bool pcpp::Layer::canReinterpretAs<pcpp::iphdr>(unsigned char const*, unsigned long) |
527 | | }; |
528 | | |
529 | | inline std::ostream& operator<<(std::ostream& os, const pcpp::Layer& layer) |
530 | 0 | { |
531 | 0 | os << layer.toString(); |
532 | 0 | return os; |
533 | 0 | } |
534 | | } // namespace pcpp |