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