Coverage Report

Created: 2026-09-28 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/header/Packet.h
Line
Count
Source
1
#pragma once
2
3
#include "RawPacket.h"
4
#include "Layer.h"
5
#include "Serializers.h"
6
#include <vector>
7
8
/// @file
9
10
/// @namespace pcpp
11
/// @brief The main namespace for the PcapPlusPlus lib
12
namespace pcpp
13
{
14
  /// @brief Options struct for configuring packet parsing behavior.
15
  ///
16
  /// The parsing options are combined. If multiple stop conditions are specified, parsing stops
17
  /// as soon as any condition is met.
18
  struct PacketParseOptions
19
  {
20
    /// @brief Defines the protocol type up to and including which the packet should be parsed (inclusive).
21
    ///
22
    /// For large packets where only the lower layers are of interest, this option can be used to limit the parsing
23
    /// procedure to the desired protocol. The packet is parsed until the specified protocol is reached and
24
    /// consumed. Layers beyond this protocol are not parsed, which can improve performance and reduce
25
    /// memory usage.
26
    ///
27
    /// @remarks If multiple consecutive layers of the same protocol type exist, parsing stops after exhausting the
28
    /// first contiguous sequence of that protocol type. This matters for protocols that may appear multiple times
29
    /// in succession within a packet (e.g. BgpLayer).
30
    ProtocolTypeFamily parseUntilProtocol = UnknownProtocol;
31
32
    /// @brief Defines an OSI model layer up to and including which the packet should be parsed (inclusive).
33
    ///
34
    /// For large packets where only the lower layers are of interest, this option can be used to limit the parsing
35
    /// procedure to the desired OSI layer. The packet is parsed until all layers belonging to the specified OSI
36
    /// layer are consumed. Layers beyond that are ignored, which can improve performance and reduce memory usage.
37
    OsiModelLayer parseUntilLayer = OsiModelLayerUnknown;
38
  };
39
40
  /// @class Packet
41
  /// This class represents a parsed packet. It contains the raw data (RawPacket instance), and a linked list of
42
  /// layers, each layer is a parsed protocol that this packet contains. The layers linked list is ordered where the
43
  /// first layer is the lowest in the packet (currently it's always Ethernet protocol as PcapPlusPlus supports only
44
  /// Ethernet packets), the next layer will be L2.5 or L3 (e.g VLAN, IPv4, IPv6, etc.), and so on. etc.), etc. The
45
  /// last layer in the linked list will be the highest in the packet. For example: for a standard HTTP request packet
46
  /// the layer will look like this: EthLayer -> IPv4Layer -> TcpLayer -> HttpRequestLayer <BR> Packet instance isn't
47
  /// read only. The user can add or remove layers, update current layer, etc.
48
  class Packet
49
  {
50
    friend class Layer;
51
52
  private:
53
    RawPacket* m_RawPacket;
54
    Layer* m_FirstLayer;
55
    Layer* m_LastLayer;
56
    size_t m_MaxPacketLen;
57
    bool m_FreeRawPacket;
58
    bool m_CanReallocateData;
59
60
  public:
61
    /// A constructor for creating a new packet (with no layers).
62
    /// When using this constructor an empty raw buffer is allocated (with the size of maxPacketLen) and a new
63
    /// RawPacket is created
64
    /// @param[in] maxPacketLen The expected packet length in bytes
65
    /// @param[in] linkType The link type to use for this packet (the default is Ethernet)
66
    explicit Packet(size_t maxPacketLen = 1, LinkLayerType linkType = LINKTYPE_ETHERNET);
67
68
    /// A constructor for creating a new packet with a buffer that is pre-allocated by the user.
69
    /// The packet is created empty (with no layers), which means the constructor doesn't parse the data in the
70
    /// buffer. Instead, all of the raw data of this packet it written to this buffer: whenever a layer is added,
71
    /// it's data is written to this buffer. The buffer isn't freed and it's content isn't erased when the packet
72
    /// object is deleted. This constructor is useful when you already have a memory buffer and you want to create
73
    /// packet data in it.
74
    /// @param[in] buffer A pointer to a pre-allocated memory buffer
75
    /// @param[in] bufferSize The size of the buffer
76
    /// @param[in] linkType The link type to use for this packet (the default is Ethernet)
77
    Packet(uint8_t* buffer, size_t bufferSize, LinkLayerType linkType = LINKTYPE_ETHERNET);
78
79
    /// A constructor for creating a packet out of already allocated RawPacket. Very useful when parsing packets
80
    /// that came from the network. When using this constructor a pointer to the RawPacket is saved (data isn't
81
    /// copied) and the RawPacket is parsed, meaning all layers are created and linked to each other in the right
82
    /// order. In this overload of the constructor the user can specify whether to free the instance of raw packet
83
    /// when the Packet is free or not
84
    /// @param[in] rawPacket A pointer to the raw packet
85
    /// @param[in] freeRawPacket Optional parameter. A flag indicating if the destructor should also call the raw
86
    /// packet destructor or not. Default value is false
87
    /// @param[in] parseUntil Optional parameter. Parse the packet until you reach a certain protocol (inclusive).
88
    /// Can be useful for cases when you need to parse only up to a certain layer and want to avoid the performance
89
    /// impact and memory consumption of parsing the whole packet. Default value is ::UnknownProtocol which means
90
    /// don't take this parameter into account
91
    /// @param[in] parseUntilLayer Optional parameter. Parse the packet until you reach a certain layer in the OSI
92
    /// model (inclusive). Can be useful for cases when you need to parse only up to a certain OSI layer (for
93
    /// example transport layer) and want to avoid the performance impact and memory consumption of parsing the
94
    /// whole packet. Default value is ::OsiModelLayerUnknown which means don't take this parameter into account
95
    explicit Packet(RawPacket* rawPacket, bool freeRawPacket = false, ProtocolType parseUntil = UnknownProtocol,
96
                    OsiModelLayer parseUntilLayer = OsiModelLayerUnknown);
97
98
    /// @copydoc Packet(RawPacket*, bool, ProtocolType, OsiModelLayer)
99
    explicit Packet(RawPacket* rawPacket, bool freeRawPacket, ProtocolTypeFamily parseUntil,
100
                    OsiModelLayer parseUntilLayer = OsiModelLayerUnknown);
101
102
    /// A constructor for creating a packet out of already allocated RawPacket. Very useful when parsing packets
103
    /// that came from the network. When using this constructor a pointer to the RawPacket is saved (data isn't
104
    /// copied) and the RawPacket is parsed, meaning all layers are created and linked to each other in the right
105
    /// order. In this overload of the constructor the user can specify whether to free the instance of raw packet
106
    /// when the Packet is free or not. This constructor should be used to parse the packet up to a certain layer
107
    /// @param[in] rawPacket A pointer to the raw packet
108
    /// @param[in] parseUntil Parse the packet until you reach a certain protocol (inclusive). Can be useful for
109
    /// cases when you need to parse only up to a certain layer and want to avoid the performance impact and memory
110
    /// consumption of parsing the whole packet
111
    explicit Packet(RawPacket* rawPacket, ProtocolType parseUntil);
112
113
    /// A constructor for creating a packet out of already allocated RawPacket. Very useful when parsing packets
114
    /// that came from the network. When using this constructor a pointer to the RawPacket is saved (data isn't
115
    /// copied) and the RawPacket is parsed, meaning all layers are created and linked to each other in the right
116
    /// order. In this overload of the constructor the user can specify whether to free the instance of raw packet
117
    /// when the Packet is free or not. This constructor should be used to parse the packet up to a certain layer
118
    /// @param[in] rawPacket A pointer to the raw packet
119
    /// @param[in] parseUntilFamily Parse the packet until you reach a certain protocol family (inclusive). Can be
120
    /// useful for cases when you need to parse only up to a certain layer and want to avoid the performance impact
121
    /// and memory consumption of parsing the whole packet
122
    explicit Packet(RawPacket* rawPacket, ProtocolTypeFamily parseUntilFamily);
123
124
    /// A constructor for creating a packet out of already allocated RawPacket. Very useful when parsing packets
125
    /// that came from the network. When using this constructor a pointer to the RawPacket is saved (data isn't
126
    /// copied) and the RawPacket is parsed, meaning all layers are created and linked to each other in the right
127
    /// order. In this overload of the constructor the user can specify whether to free the instance of raw packet
128
    /// when the Packet is free or not. This constructor should be used to parse the packet up to a certain layer in
129
    /// the OSI model
130
    /// @param[in] rawPacket A pointer to the raw packet
131
    /// @param[in] parseUntilLayer Optional parameter. Parse the packet until you reach a certain layer in the OSI
132
    /// model (inclusive). Can be useful for cases when you need to parse only up to a certain OSI layer (for
133
    /// example transport layer) and want to avoid the performance impact and memory consumption of parsing the
134
    /// whole packet
135
    explicit Packet(RawPacket* rawPacket, OsiModelLayer parseUntilLayer);
136
137
    /// A destructor for this class. Frees all layers allocated by this instance (Notice: it doesn't free layers
138
    /// that weren't allocated by this class, for example layers that were added by addLayer() or insertLayer() ).
139
    /// In addition it frees the raw packet if it was allocated by this instance (meaning if it was allocated by
140
    /// this instance constructor)
141
    virtual ~Packet()
142
0
    {
143
0
      destructPacketData();
144
0
    }
145
146
    /// A copy constructor for this class. This copy constructor copies all the raw data and re-create all layers.
147
    /// So when the original Packet is being freed, no data will be lost in the copied instance
148
    /// @param[in] other The instance to copy from
149
    Packet(const Packet& other)
150
0
    {
151
0
      copyDataFrom(other);
152
0
    }
153
154
    /// Assignment operator overloading. It first frees all layers allocated by this instance (Notice: it doesn't
155
    /// free layers that weren't allocated by this class, for example layers that were added by addLayer() or
156
    /// insertLayer() ). In addition it frees the raw packet if it was allocated by this instance (meaning if it was
157
    /// allocated by this instance constructor). Afterwards it copies the data from the other packet in the same way
158
    /// used in the copy constructor.
159
    /// @param[in] other The instance to copy from
160
    Packet& operator=(const Packet& other);
161
162
    /// Get a pointer to the Packet's RawPacket
163
    /// @return A pointer to the Packet's RawPacket
164
    RawPacket* getRawPacket() const
165
0
    {
166
0
      return m_RawPacket;
167
0
    }
168
169
    /// Set a RawPacket and re-construct all packet layers
170
    /// @param[in] rawPacket Raw packet to set
171
    /// @param[in] freeRawPacket A flag indicating if the destructor should also call the raw packet destructor or
172
    /// not
173
    /// @param[in] parseUntil Parse the packet until it reaches this protocol. Can be useful for cases when you need
174
    /// to parse only up to a certain layer and want to avoid the performance impact and memory consumption of
175
    /// parsing the whole packet. Default value is ::UnknownProtocol which means don't take this parameter into
176
    /// account
177
    /// @param[in] parseUntilLayer Parse the packet until certain layer in OSI model. Can be useful for cases when
178
    /// you need to parse only up to a certain layer and want to avoid the performance impact and memory consumption
179
    /// of parsing the whole packet. Default value is ::OsiModelLayerUnknown which means don't take this parameter
180
    /// into account
181
    void setRawPacket(RawPacket* rawPacket, bool freeRawPacket, ProtocolTypeFamily parseUntil = UnknownProtocol,
182
                      OsiModelLayer parseUntilLayer = OsiModelLayerUnknown);
183
184
    /// @brief Parse the packet according to the provided options.
185
    ///
186
    /// The packet is parsed according to the specified options, constructing the layer hierarchy if it does not
187
    /// exist. If the packet has already been parsed, it will be re-parsed based on the new options.
188
    ///
189
    /// If @p incrementalParsing is true, the procedure will reuse existing layers where possible, only creating new
190
    /// layers for previously unparsed data. Otherwise, all existing layers are discarded and the packet is parsed
191
    /// from scratch.
192
    ///
193
    /// @param[in] options Parsing options to configure the parsing behavior.
194
    /// @param[in] incrementalParsing If 'true', incremental parsing is performed, reusing existing layers where
195
    /// possible.
196
    /// @throws std::runtime_error if there is no RawPacket associated with this Packet instance.
197
    void parsePacket(PacketParseOptions options, bool incrementalParsing = true);
198
199
    /// Get a pointer to the Packet's RawPacket in a read-only manner
200
    /// @return A pointer to the Packet's RawPacket
201
    const RawPacket* getRawPacketReadOnly() const
202
0
    {
203
0
      return m_RawPacket;
204
0
    }
205
206
    /// Get a pointer to the first (lowest) layer in the packet
207
    /// @return A pointer to the first (lowest) layer in the packet
208
    Layer* getFirstLayer() const
209
0
    {
210
0
      return m_FirstLayer;
211
0
    }
212
213
    /// Get a pointer to the last (highest) layer in the packet
214
    /// @return A pointer to the last (highest) layer in the packet
215
    Layer* getLastLayer() const
216
0
    {
217
0
      return m_LastLayer;
218
0
    }
219
220
    /// Add a new layer as the last layer in the packet. This method gets a pointer to the new layer as a parameter
221
    /// and attaches it to the packet. Notice after calling this method the input layer is attached to the packet so
222
    /// every change you make in it affect the packet; Also it cannot be attached to other packets
223
    /// @param[in] newLayer A pointer to the new layer to be added to the packet
224
    /// @param[in] ownInPacket If true, Packet fully owns newLayer, including memory deletion upon destruct. Default
225
    /// is false.
226
    /// @return True if everything went well or false otherwise (an appropriate error log message will be printed in
227
    /// such cases)
228
    bool addLayer(Layer* newLayer, bool ownInPacket = false)
229
0
    {
230
0
      return insertLayer(m_LastLayer, newLayer, ownInPacket);
231
0
    }
232
233
    /// Insert a new layer after an existing layer in the packet. This method gets a pointer to the new layer as a
234
    /// parameter and attaches it to the packet. Notice after calling this method the input layer is attached to the
235
    /// packet so every change you make in it affect the packet; Also it cannot be attached to other packets
236
    /// @param[in] prevLayer A pointer to an existing layer in the packet which the new layer should followed by. If
237
    /// this layer isn't attached to a packet and error will be printed to log and false will be returned
238
    /// @param[in] newLayer A pointer to the new layer to be added to the packet
239
    /// @param[in] ownInPacket If true, Packet fully owns newLayer, including memory deletion upon destruct. Default
240
    /// is false.
241
    /// @return True if everything went well or false otherwise (an appropriate error log message will be printed in
242
    /// such cases)
243
    bool insertLayer(Layer* prevLayer, Layer* newLayer, bool ownInPacket = false);
244
245
    /// Remove an existing layer from the packet. The layer to removed is identified by its type (protocol). If the
246
    /// packet has multiple layers of the same type in the packet the user may specify the index of the layer to
247
    /// remove (the default index is 0 - remove the first layer of this type). If the layer was allocated during
248
    /// packet creation it will be deleted and any pointer to it will get invalid. However if the layer was
249
    /// allocated by the user and manually added to the packet it will simply get detached from the packet, meaning
250
    /// the pointer to it will stay valid and its data (that was removed from the packet) will be copied back to the
251
    /// layer. In that case it's the user's responsibility to delete the layer instance
252
    /// @param[in] layerType The layer type (protocol) to remove
253
    /// @param[in] index If there are multiple layers of the same type, indicate which instance to remove. The
254
    /// default value is 0, meaning remove the first layer of this type
255
    /// @return True if everything went well or false otherwise (an appropriate error log message will be printed in
256
    /// such cases)
257
    bool removeLayer(ProtocolType layerType, int index = 0);
258
259
    /// Remove the first layer in the packet. The layer will be deleted if it was allocated during packet creation,
260
    /// or detached if was allocated outside of the packet. Please refer to removeLayer() to get more info
261
    /// @return True if layer removed successfully, or false if removing the layer failed or if there are no layers
262
    /// in the packet. In any case of failure an appropriate error log message will be printed
263
    bool removeFirstLayer();
264
265
    /// Remove the last layer in the packet. The layer will be deleted if it was allocated during packet creation,
266
    /// or detached if was allocated outside of the packet. Please refer to removeLayer() to get more info
267
    /// @return True if layer removed successfully, or false if removing the layer failed or if there are no layers
268
    /// in the packet. In any case of failure an appropriate error log message will be printed
269
    bool removeLastLayer();
270
271
    /// Remove all layers that come after a certain layer. All layers removed will be deleted if they were allocated
272
    /// during packet creation or detached if were allocated outside of the packet, please refer to removeLayer() to
273
    /// get more info
274
    /// @param[in] layer A pointer to the layer to begin removing from. Please note this layer will not be removed,
275
    /// only the layers that come after it will be removed. Also, if removal of one layer failed, the method will
276
    /// return immediately and the following layers won't be deleted
277
    /// @return True if all layers were removed successfully, or false if failed to remove at least one layer. In
278
    /// any case of failure an appropriate error log message will be printed
279
    bool removeAllLayersAfter(Layer* layer);
280
281
    /// Detach a layer from the packet. Detaching means the layer instance will not be deleted, but rather separated
282
    /// from the packet - e.g it will be removed from the layer chain of the packet and its data will be copied from
283
    /// the packet buffer into an internal layer buffer. After a layer is detached, it can be added into another
284
    /// packet (but it's impossible to attach a layer to multiple packets in the same time). After layer is
285
    /// detached, it's the user's responsibility to delete it when it's not needed anymore
286
    /// @param[in] layerType The layer type (protocol) to detach from the packet
287
    /// @param[in] index If there are multiple layers of the same type, indicate which instance to detach. The
288
    /// default value is 0, meaning detach the first layer of this type
289
    /// @return A pointer to the detached layer or nullptr if detaching process failed. In any case of failure an
290
    /// appropriate error log message will be printed
291
    Layer* detachLayer(ProtocolType layerType, int index = 0);
292
293
    /// Detach a layer from the packet. Detaching means the layer instance will not be deleted, but rather separated
294
    /// from the packet - e.g it will be removed from the layer chain of the packet and its data will be copied from
295
    /// the packet buffer into an internal layer buffer. After a layer is detached, it can be added into another
296
    /// packet (but it's impossible to attach a layer to multiple packets at the same time). After layer is
297
    /// detached, it's the user's responsibility to delete it when it's not needed anymore
298
    /// @param[in] layer A pointer to the layer to detach
299
    /// @return True if the layer was detached successfully, or false if something went wrong. In any case of
300
    /// failure an appropriate error log message will be printed
301
    bool detachLayer(Layer* layer)
302
0
    {
303
0
      return removeLayer(layer, false);
304
0
    }
305
306
    /// Get a pointer to the layer of a certain type (protocol). This method goes through the layers and returns a
307
    /// layer that matches the give protocol type
308
    /// @param[in] layerType The layer type (protocol) to fetch
309
    /// @param[in] index If there are multiple layers of the same type, indicate which instance to fetch. The
310
    /// default value is 0, meaning fetch the first layer of this type
311
    /// @return A pointer to the layer or nullptr if no such layer was found
312
    Layer* getLayerOfType(ProtocolType layerType, int index = 0) const;
313
314
    /// A templated method to get a layer of a certain type (protocol). If no layer of such type is found, nullptr
315
    /// is returned
316
    /// @param[in] reverseOrder The optional parameter that indicates that the lookup should run in reverse order,
317
    /// the default value is false
318
    /// @return A pointer to the layer of the requested type, nullptr if not found
319
    template <class TLayer> TLayer* getLayerOfType(bool reverseOrder = false) const;
320
321
    /// A templated method to get the first layer of a certain type (protocol), start searching from a certain
322
    /// layer. For example: if a packet looks like: EthLayer -> VlanLayer(1) -> VlanLayer(2) -> VlanLayer(3) ->
323
    /// IPv4Layer and the user put VlanLayer(2) as a parameter and wishes to search for a VlanLayer, VlanLayer(3)
324
    /// will be returned If no layer of such type is found, nullptr is returned
325
    /// @param[in] startLayer A pointer to the layer to start search from
326
    /// @return A pointer to the layer of the requested type, nullptr if not found
327
    template <class TLayer> TLayer* getNextLayerOfType(Layer* startLayer) const;
328
329
    /// A templated method to get the first layer of a certain type (protocol), start searching from a certain
330
    /// layer. For example: if a packet looks like: EthLayer -> VlanLayer(1) -> VlanLayer(2) -> VlanLayer(3) ->
331
    /// IPv4Layer and the user put VlanLayer(2) as a parameter and wishes to search for a VlanLayer, VlanLayer(1)
332
    /// will be returned If no layer of such type is found, nullptr is returned
333
    /// @param[in] startLayer A pointer to the layer to start search from
334
    /// @return A pointer to the layer of the requested type, nullptr if not found
335
    template <class TLayer> TLayer* getPrevLayerOfType(Layer* startLayer) const;
336
337
    /// Check whether the packet contains a layer of a certain protocol
338
    /// @param[in] protocolType The protocol type to search
339
    /// @return True if the packet contains a layer of a certain protocol, false otherwise
340
    bool isPacketOfType(ProtocolType protocolType) const;
341
342
    /// Check whether the packet contains a layer of a certain protocol family
343
    /// @param[in] protocolTypeFamily The protocol type family to search
344
    /// @return True if the packet contains a layer of a certain protocol family, false otherwise
345
    bool isPacketOfType(ProtocolTypeFamily protocolTypeFamily) const;
346
347
    /// Each layer can have fields that can be calculate automatically from other fields using
348
    /// Layer#computeCalculateFields(). This method forces all layers to calculate these fields values
349
    void computeCalculateFields();
350
351
    /// Each layer can print a string representation of the layer most important data using Layer#toString(). This
352
    /// method aggregates this string from all layers and print it to a complete string containing all packet's
353
    /// relevant data
354
    /// @param[in] timeAsLocalTime Print time as local time or GMT. Default (true value) is local time, for GMT set
355
    /// to false
356
    /// @return A string containing most relevant data from all layers (looks like the packet description in
357
    /// Wireshark)
358
    std::string toString(bool timeAsLocalTime = true) const;
359
360
    /// Similar to toString(), but instead of one string it outputs a list of strings, one string for every layer
361
    /// @param[out] result A string vector that will contain all strings
362
    /// @param[in] timeAsLocalTime Print time as local time or GMT. Default (true value) is local time, for GMT set
363
    /// to false
364
    void toStringList(std::vector<std::string>& result, bool timeAsLocalTime = true) const;
365
366
    /// @struct SerializedFields
367
    /// Field descriptors for the fields serialized by Packet::serialize().
368
    struct SerializedFields
369
    {
370
      /// @struct TimestampObject
371
      /// Field descriptors for the packet timestamp.
372
      struct TimestampObject : ObjectFieldDescriptor<TimestampObject>
373
      {
374
        using ObjectFieldDescriptor::ObjectFieldDescriptor;
375
376
        /// @return A vector containing all timestamp field descriptors.
377
        static std::vector<FieldDescriptor> all()
378
0
        {
379
0
          return { Sec, NSec };
380
0
        }
381
382
        /// Field descriptor for the timestamp seconds.
383
        static const FieldDescriptor Sec;
384
385
        /// Field descriptor for the timestamp nanoseconds.
386
        static const FieldDescriptor NSec;
387
      };
388
389
      /// @return A vector containing all packet field descriptors.
390
      static std::vector<FieldDescriptor> all()
391
0
      {
392
0
        return { Timestamp, FrameLength, LinkLayer, LinkLayerName, Layers };
393
0
      }
394
395
      /// Field descriptor for the packet timestamp.
396
      static const TimestampObject Timestamp;
397
398
      /// Field descriptor for the packet frame length.
399
      static const FieldDescriptor FrameLength;
400
401
      /// Field descriptor for the packet link layer type.
402
      static const FieldDescriptor LinkLayer;
403
404
      /// Field descriptor for the packet link layer name.
405
      static const FieldDescriptor LinkLayerName;
406
407
      /// Field descriptor for the packet layers.
408
      static const FieldDescriptor Layers;
409
    };
410
411
    /// Serialize the packet using the provided serializer.
412
    /// @param[in] serializer The serializer to use.
413
    void serialize(ISerializer& serializer) const;
414
415
  private:
416
    void copyDataFrom(const Packet& other);
417
418
    void destructPacketData();
419
    void destroyAllLayers();
420
421
    bool extendLayer(Layer* layer, int offsetInLayer, size_t numOfBytesToExtend);
422
    bool shortenLayer(Layer* layer, int offsetInLayer, size_t numOfBytesToShorten);
423
424
    void reallocateRawData(size_t newSize);
425
426
    bool removeLayer(Layer* layer, bool tryToDelete);
427
428
    std::string printPacketInfo(bool timeAsLocalTime) const;
429
430
    Layer* createFirstLayer(LinkLayerType linkType);
431
432
    template <typename TLayer, typename NextLayerFn>
433
    static TLayer* searchLayerStackForType(Layer* startLayer, NextLayerFn nextLayerFn, bool skipFirst);
434
  };  // class Packet
435
436
  // implementation of inline methods
437
438
  template <class TLayer> TLayer* Packet::getLayerOfType(bool reverse) const
439
  {
440
    if (!reverse)
441
    {
442
      return searchLayerStackForType<TLayer>(
443
          m_FirstLayer, [](Layer* layer) { return layer->getNextLayer(); }, false);
444
    }
445
446
    // lookup in reverse order
447
    return searchLayerStackForType<TLayer>(m_LastLayer, [](Layer* layer) { return layer->getPrevLayer(); }, false);
448
  }
449
450
  template <class TLayer> TLayer* Packet::getNextLayerOfType(Layer* curLayer) const
451
  {
452
    return searchLayerStackForType<TLayer>(curLayer, [](Layer* layer) { return layer->getNextLayer(); }, true);
453
  }
454
455
  template <class TLayer> TLayer* Packet::getPrevLayerOfType(Layer* curLayer) const
456
  {
457
    return searchLayerStackForType<TLayer>(curLayer, [](Layer* layer) { return layer->getPrevLayer(); }, true);
458
  }
459
460
  template <typename TLayer, typename NextLayerFn>
461
  TLayer* Packet::searchLayerStackForType(Layer* curLayer, NextLayerFn nextLayerFn, bool skipFirst)
462
  {
463
    if (curLayer == nullptr)
464
      return nullptr;
465
466
    if (skipFirst)
467
    {
468
      curLayer = nextLayerFn(curLayer);
469
    }
470
471
    while (curLayer != nullptr)
472
    {
473
      auto* curLayerCasted = dynamic_cast<TLayer*>(curLayer);
474
      if (curLayerCasted != nullptr)
475
        return curLayerCasted;
476
477
      curLayer = nextLayerFn(curLayer);
478
    }
479
480
    return nullptr;
481
  }
482
483
  inline std::ostream& operator<<(std::ostream& os, const pcpp::Packet& packet)
484
0
  {
485
0
    os << packet.toString();
486
0
    return os;
487
0
  }
488
}  // namespace pcpp