Coverage Report

Created: 2026-09-28 06:37

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