/src/PcapPlusPlus/Packet++/header/IgmpLayer.h
Line | Count | Source (jump to first uncovered line) |
1 | | #pragma once |
2 | | |
3 | | #include "Layer.h" |
4 | | #include "IpAddress.h" |
5 | | #include <vector> |
6 | | |
7 | | /// @file |
8 | | |
9 | | /** |
10 | | * \namespace pcpp |
11 | | * \brief The main namespace for the PcapPlusPlus lib |
12 | | */ |
13 | | namespace pcpp |
14 | | { |
15 | | |
16 | | /** |
17 | | * @struct igmp_header |
18 | | * IGMPv1 and IGMPv2 basic protocol header |
19 | | */ |
20 | | struct igmp_header |
21 | | { |
22 | | /** Indicates the message type. The enum for message type is pcpp::IgmpType */ |
23 | | uint8_t type; |
24 | | /** Specifies the time limit for the corresponding report. The field has a resolution of 100 milliseconds */ |
25 | | uint8_t maxResponseTime; |
26 | | /** This is the 16-bit one's complement of the one's complement sum of the entire IGMP message */ |
27 | | uint16_t checksum; |
28 | | /** This is the multicast address being queried when sending a Group-Specific or Group-and-Source-Specific Query */ |
29 | | uint32_t groupAddress; |
30 | | }; |
31 | | |
32 | | |
33 | | /** |
34 | | * @struct igmpv3_query_header |
35 | | * IGMPv3 membership query basic header |
36 | | */ |
37 | | struct igmpv3_query_header |
38 | | { |
39 | | /** IGMP message type. Should always have value of membership query (::IgmpType_MembershipQuery) */ |
40 | | uint8_t type; |
41 | | /** This field specifies the maximum time (in 1/10 second) allowed before sending a responding report */ |
42 | | uint8_t maxResponseTime; |
43 | | /** This is the 16-bit one's complement of the one's complement sum of the entire IGMP message */ |
44 | | uint16_t checksum; |
45 | | /** This is the multicast address being queried when sending a Group-Specific or Group-and-Source-Specific Query */ |
46 | | uint32_t groupAddress; |
47 | | /** Suppress Router-side Processing Flag + Querier's Robustness Variable */ |
48 | | uint8_t s_qrv; |
49 | | /** Querier's Query Interval Code */ |
50 | | uint8_t qqic; |
51 | | /** This field specifies the number of source addresses present in the Query */ |
52 | | uint16_t numOfSources; |
53 | | }; |
54 | | |
55 | | |
56 | | /** |
57 | | * @struct igmpv3_report_header |
58 | | * IGMPv3 membership report basic header |
59 | | */ |
60 | | struct igmpv3_report_header |
61 | | { |
62 | | /** IGMP message type. Should always have value of IGMPv3 membership report (::IgmpType_MembershipReportV3) */ |
63 | | uint8_t type; |
64 | | /** Unused byte */ |
65 | | uint8_t reserved1; |
66 | | /** This is the 16-bit one's complement of the one's complement sum of the entire IGMP message */ |
67 | | uint16_t checksum; |
68 | | /** Unused bytes */ |
69 | | uint16_t reserved2; |
70 | | /** This field specifies the number of group records present in the Report */ |
71 | | uint16_t numOfGroupRecords; |
72 | | }; |
73 | | |
74 | | |
75 | | /** |
76 | | * @struct igmpv3_group_record |
77 | | * A block of fields containing information pertaining to the sender's membership in a single multicast group on the interface |
78 | | * from which the Report is sent. Relevant only for IGMPv3 membership report messages |
79 | | */ |
80 | | struct igmpv3_group_record |
81 | | { |
82 | | /** Group record type */ |
83 | | uint8_t recordType; |
84 | | /** Contains the length of the Auxiliary Data field in this Group Record. A value other than 0 isn't supported */ |
85 | | uint8_t auxDataLen; |
86 | | /** Specifies how many source addresses are present in this Group Record */ |
87 | | uint16_t numOfSources; |
88 | | /** Contains the IP multicast address to which this Group Record pertains */ |
89 | | uint32_t multicastAddress; |
90 | | /** A vector of n IP unicast addresses, where n is the value in this record's Number of Sources field */ |
91 | | uint8_t sourceAddresses[]; |
92 | | |
93 | | /** |
94 | | * @return The multicast address in igmpv3_group_record#multicastAddress as IPv4Address instance |
95 | | */ |
96 | 0 | IPv4Address getMulticastAddress() const { return multicastAddress; } |
97 | | |
98 | | /** |
99 | | * @return The number of source addresses in this group record |
100 | | */ |
101 | | uint16_t getSourceAddressCount() const; |
102 | | |
103 | | /** |
104 | | * Get the source address at a certain index |
105 | | * @param[in] index The index of the source address in the group record |
106 | | * @return The source address in the requested index. If index is negative or higher than the number of source addresses in this |
107 | | * group record the value if IPv4Address#Zero is returned |
108 | | */ |
109 | | IPv4Address getSourceAddressAtIndex(int index) const; |
110 | | |
111 | | /** |
112 | | * @return The total size in bytes of the group record |
113 | | */ |
114 | | size_t getRecordLen() const; |
115 | | }; |
116 | | |
117 | | |
118 | | /** |
119 | | * IGMP message types |
120 | | */ |
121 | | enum IgmpType |
122 | | { |
123 | | /** Unknown message type */ |
124 | | IgmpType_Unknown = 0, |
125 | | /** IGMP Membership Query */ |
126 | | IgmpType_MembershipQuery = 0x11, |
127 | | /** IGMPv1 Membership Report */ |
128 | | IgmpType_MembershipReportV1 = 0x12, |
129 | | /** DVMRP */ |
130 | | IgmpType_DVMRP = 0x13, |
131 | | /** PIM version 1 */ |
132 | | IgmpType_P1Mv1 = 0x14, |
133 | | /** Cisco Trace Messages */ |
134 | | IgmpType_CiscoTrace = 0x15, |
135 | | /** IGMPv2 Membership Report */ |
136 | | IgmpType_MembershipReportV2 = 0x16, |
137 | | /** IGMPv2 Leave Group */ |
138 | | IgmpType_LeaveGroup = 0x17, |
139 | | /** Multicast Traceroute Response */ |
140 | | IgmpType_MulticastTracerouteResponse = 0x1e, |
141 | | /** Multicast Traceroute */ |
142 | | IgmpType_MulticastTraceroute = 0x1f, |
143 | | /** IGMPv3 Membership Report */ |
144 | | IgmpType_MembershipReportV3 = 0x22, |
145 | | /** MRD, Multicast Router Advertisement */ |
146 | | IgmpType_MulticastRouterAdvertisement = 0x30, |
147 | | /** MRD, Multicast Router Solicitation */ |
148 | | IgmpType_MulticastRouterSolicitation = 0x31, |
149 | | /** MRD, Multicast Router Termination */ |
150 | | IgmpType_MulticastRouterTermination = 0x32, |
151 | | }; |
152 | | |
153 | | |
154 | | /** |
155 | | * @class IgmpLayer |
156 | | * A base class for all IGMP (Internet Group Management Protocol) protocol classes. This is an abstract class and cannot be instantiated, |
157 | | * only its child classes can be instantiated. The inherited classes represent the different versions of the protocol: |
158 | | * IGMPv1, IGMPv2 and IGMPv3 |
159 | | */ |
160 | | class IgmpLayer : public Layer |
161 | | { |
162 | | protected: |
163 | | |
164 | 23.8k | IgmpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ProtocolType igmpVer) : Layer(data, dataLen, prevLayer, packet) { m_Protocol = igmpVer; } |
165 | | |
166 | | IgmpLayer(IgmpType type, const IPv4Address& groupAddr, uint8_t maxResponseTime, ProtocolType igmpVer); |
167 | | |
168 | | uint16_t calculateChecksum(); |
169 | | |
170 | | size_t getHeaderSizeByVerAndType(ProtocolType igmpVer, IgmpType igmpType) const; |
171 | | public: |
172 | | |
173 | 0 | virtual ~IgmpLayer() {} |
174 | | |
175 | | /** |
176 | | * Get a pointer to the raw IGMPv1/IGMPv2 header. Notice this points directly to the data, so every change will change the actual packet data |
177 | | * @return A pointer to the @ref igmp_header |
178 | | */ |
179 | 19.1k | igmp_header* getIgmpHeader() const { return (igmp_header*)m_Data; } |
180 | | |
181 | | /** |
182 | | * @return The IPv4 multicast address stored igmp_header#groupAddress |
183 | | */ |
184 | 0 | IPv4Address getGroupAddress() const { return getIgmpHeader()->groupAddress; } |
185 | | |
186 | | /** |
187 | | * Set the IPv4 multicast address |
188 | | * @param[in] groupAddr The IPv4 address to set |
189 | | */ |
190 | | void setGroupAddress(const IPv4Address& groupAddr); |
191 | | |
192 | | /** |
193 | | * @return IGMP type set in igmp_header#type as ::IgmpType enum. Notice that if igmp_header#type contains a value |
194 | | * that doesn't appear in the ::IgmpType enum, ::IgmpType_Unknown will be returned |
195 | | */ |
196 | | IgmpType getType() const; |
197 | | |
198 | | /** |
199 | | * Set IGMP type (will be written to igmp_header#type field) |
200 | | * @param[in] type The type to set |
201 | | */ |
202 | | void setType(IgmpType type); |
203 | | |
204 | | /** |
205 | | * A static method that gets raw IGMP data (byte stream) and returns the IGMP version of this IGMP message |
206 | | * @param[in] data The IGMP raw data (byte stream) |
207 | | * @param[in] dataLen Raw data length |
208 | | * @param[out] isQuery Return true if IGMP message type is ::IgmpType_MembershipQuery and false otherwise |
209 | | * @return One of the values ::IGMPv1, ::IGMPv2, ::IGMPv3 according to detected IGMP version or ::UnknownProtocol if couldn't detect |
210 | | * IGMP version |
211 | | */ |
212 | | static ProtocolType getIGMPVerFromData(uint8_t* data, size_t dataLen, bool& isQuery); |
213 | | |
214 | | |
215 | | // implement abstract methods |
216 | | |
217 | | /** |
218 | | * Does nothing for this layer (IGMP layer is always last) |
219 | | */ |
220 | 23.8k | void parseNextLayer() {} |
221 | | |
222 | | /** |
223 | | * @return Size of IGMP header = 8B |
224 | | */ |
225 | 5.37k | size_t getHeaderLen() const { return sizeof(igmp_header); } |
226 | | |
227 | | std::string toString() const; |
228 | | |
229 | 5.47k | OsiModelLayer getOsiModelLayer() const { return OsiModelNetworkLayer; } |
230 | | }; |
231 | | |
232 | | |
233 | | /** |
234 | | * @class IgmpV1Layer |
235 | | * Represents IGMPv1 (Internet Group Management Protocol ver 1) layer. This class represents all the different messages of IGMPv1 |
236 | | */ |
237 | | class IgmpV1Layer : public IgmpLayer |
238 | | { |
239 | | public: |
240 | | /** A constructor that creates the layer from an existing packet raw data |
241 | | * @param[in] data A pointer to the raw data |
242 | | * @param[in] dataLen Size of the data in bytes |
243 | | * @param[in] prevLayer A pointer to the previous layer |
244 | | * @param[in] packet A pointer to the Packet instance where layer will be stored in |
245 | | */ |
246 | | IgmpV1Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) |
247 | 6.76k | : IgmpLayer(data, dataLen, prevLayer, packet, IGMPv1) {} |
248 | | |
249 | | /** |
250 | | * A constructor that allocates a new IGMPv1 header |
251 | | * @param[in] type The message type to set |
252 | | * @param[in] groupAddr The multicast address to set. This is an optional parameter and has a default value of IPv4Address#Zero |
253 | | * if not provided |
254 | | */ |
255 | | explicit IgmpV1Layer(IgmpType type, const IPv4Address& groupAddr = IPv4Address()) |
256 | 0 | : IgmpLayer(type, groupAddr, 0, IGMPv1) {} |
257 | | |
258 | | /** |
259 | | * A destructor for this layer (does nothing) |
260 | | */ |
261 | 0 | ~IgmpV1Layer() {} |
262 | | |
263 | | |
264 | | // implement abstract methods |
265 | | |
266 | | /** |
267 | | * Calculate the IGMP checksum and set igmp_header#maxResponseTime to 0 (this field is unused in IGMPv1) |
268 | | */ |
269 | | void computeCalculateFields(); |
270 | | |
271 | | }; |
272 | | |
273 | | |
274 | | /** |
275 | | * @class IgmpV2Layer |
276 | | * Represents IGMPv2 (Internet Group Management Protocol ver 2) layer. This class represents all the different messages of IGMPv2 |
277 | | */ |
278 | | class IgmpV2Layer : public IgmpLayer |
279 | | { |
280 | | public: |
281 | | /** A constructor that creates the layer from an existing packet raw data |
282 | | * @param[in] data A pointer to the raw data |
283 | | * @param[in] dataLen Size of the data in bytes |
284 | | * @param[in] prevLayer A pointer to the previous layer |
285 | | * @param[in] packet A pointer to the Packet instance where layer will be stored in |
286 | | */ |
287 | | IgmpV2Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) |
288 | 5.99k | : IgmpLayer(data, dataLen, prevLayer, packet, IGMPv2) {} |
289 | | |
290 | | /** |
291 | | * A constructor that allocates a new IGMPv2 header |
292 | | * @param[in] type The message type to set |
293 | | * @param[in] groupAddr The multicast address to set. This is an optional parameter and has a default value of unspecified/zero IPv4 address |
294 | | * @param[in] maxResponseTime The max response time to set. This is an optional parameter and has a default value of 0 if not provided |
295 | | */ |
296 | | explicit IgmpV2Layer(IgmpType type, const IPv4Address& groupAddr = IPv4Address(), uint8_t maxResponseTime = 0) |
297 | 0 | : IgmpLayer(type, groupAddr, maxResponseTime, IGMPv2) {} |
298 | | |
299 | | /** |
300 | | * A destructor for this layer (does nothing) |
301 | | */ |
302 | 0 | ~IgmpV2Layer() {} |
303 | | |
304 | | |
305 | | // implement abstract methods |
306 | | |
307 | | /** |
308 | | * Calculate the IGMP checksum |
309 | | */ |
310 | | void computeCalculateFields(); |
311 | | }; |
312 | | |
313 | | |
314 | | /** |
315 | | * @class IgmpV3QueryLayer |
316 | | * Represents an IGMPv3 (Internet Group Management Protocol ver 3) membership query message |
317 | | */ |
318 | | class IgmpV3QueryLayer : public IgmpLayer |
319 | | { |
320 | | public: |
321 | | |
322 | | /** A constructor that creates the layer from an existing packet raw data |
323 | | * @param[in] data A pointer to the raw data |
324 | | * @param[in] dataLen Size of the data in bytes |
325 | | * @param[in] prevLayer A pointer to the previous layer |
326 | | * @param[in] packet A pointer to the Packet instance where layer will be stored in |
327 | | */ |
328 | | IgmpV3QueryLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); |
329 | | |
330 | | /** |
331 | | * A constructor that allocates a new IGMPv3 membership query |
332 | | * @param[in] multicastAddr The multicast address to set. This is an optional parameter and has a default value of unspecified/zero IPv4 address |
333 | | * if not provided |
334 | | * @param[in] maxResponseTime The max response time to set. This is an optional parameter and has a default value of 0 if not provided |
335 | | * @param[in] s_qrv A 1-byte value representing the value in Suppress Router-side Processing Flag + Querier's Robustness Variable |
336 | | * (igmpv3_query_header#s_qrv field). This is an optional parameter and has a default value of 0 if not provided |
337 | | */ |
338 | | explicit IgmpV3QueryLayer(const IPv4Address& multicastAddr = IPv4Address(), uint8_t maxResponseTime = 0, uint8_t s_qrv = 0); |
339 | | |
340 | | /** |
341 | | * Get a pointer to the raw IGMPv3 membership query header. Notice this points directly to the data, so every change will change the |
342 | | * actual packet data |
343 | | * @return A pointer to the @ref igmpv3_query_header |
344 | | */ |
345 | 2.25k | igmpv3_query_header* getIgmpV3QueryHeader() const { return (igmpv3_query_header*)m_Data; } |
346 | | |
347 | | /** |
348 | | * @return The number of source addresses in this message (as extracted from the igmpv3_query_header#numOfSources field) |
349 | | */ |
350 | | uint16_t getSourceAddressCount() const; |
351 | | |
352 | | /** |
353 | | * Get the IPV4 source address in a certain index |
354 | | * @param[in] index The requested index of the source address |
355 | | * @return The IPv4 source address, or IPv4Address#Zero if index is out of bounds (of the message or of the layer) |
356 | | */ |
357 | | IPv4Address getSourceAddressAtIndex(int index) const; |
358 | | |
359 | | /** |
360 | | * Add a new source address at the end of the source address list. The igmpv3_query_header#numOfSources field will be incremented accordingly |
361 | | * @param[in] addr The IPv4 source address to add |
362 | | * @return True if source address was added successfully or false otherwise. If false is returned an appropriate error message |
363 | | * will be printed to log |
364 | | */ |
365 | | bool addSourceAddress(const IPv4Address& addr); |
366 | | |
367 | | /** |
368 | | * Add a new source address at a certain index of the source address list. The igmpv3_query_header#numOfSources field will be incremented accordingly |
369 | | * @param[in] addr The IPv4 source address to add |
370 | | * @param[in] index The index to add the new source address at |
371 | | * @return True if source address was added successfully or false otherwise. If false is returned an appropriate error message |
372 | | * will be printed to log |
373 | | */ |
374 | | bool addSourceAddressAtIndex(const IPv4Address& addr, int index); |
375 | | |
376 | | /** |
377 | | * Remove a source address at a certain index. The igmpv3_query_header#numOfSources field will be decremented accordingly |
378 | | * @param[in] index The index of the source address to be removed |
379 | | * @return True if source address was removed successfully or false otherwise. If false is returned an appropriate error message |
380 | | * will be printed to log |
381 | | */ |
382 | | bool removeSourceAddressAtIndex(int index); |
383 | | |
384 | | /** |
385 | | * Remove all source addresses in the message. The igmpv3_query_header#numOfSources field will be set to 0 |
386 | | * @return True if all source addresses were cleared successfully or false otherwise. If false is returned an appropriate error message |
387 | | * will be printed to log |
388 | | */ |
389 | | bool removeAllSourceAddresses(); |
390 | | |
391 | | // implement abstract methods |
392 | | |
393 | | /** |
394 | | * Calculate the IGMP checksum |
395 | | */ |
396 | | void computeCalculateFields(); |
397 | | |
398 | | /** |
399 | | * @return The message size in bytes which include the size of the basic header + the size of the source address list |
400 | | */ |
401 | | size_t getHeaderLen() const; |
402 | | }; |
403 | | |
404 | | |
405 | | /** |
406 | | * @class IgmpV3ReportLayer |
407 | | * Represents an IGMPv3 (Internet Group Management Protocol ver 3) membership report message |
408 | | */ |
409 | | class IgmpV3ReportLayer : public IgmpLayer |
410 | | { |
411 | | private: |
412 | | igmpv3_group_record* addGroupRecordAt(uint8_t recordType, const IPv4Address& multicastAddress, const std::vector<IPv4Address>& sourceAddresses, int offset); |
413 | | |
414 | | public: |
415 | | |
416 | | /** A constructor that creates the layer from an existing packet raw data |
417 | | * @param[in] data A pointer to the raw data |
418 | | * @param[in] dataLen Size of the data in bytes |
419 | | * @param[in] prevLayer A pointer to the previous layer |
420 | | * @param[in] packet A pointer to the Packet instance where layer will be stored in |
421 | | */ |
422 | | IgmpV3ReportLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) |
423 | 8.37k | : IgmpLayer(data, dataLen, prevLayer, packet, IGMPv3) {} |
424 | | |
425 | | /** |
426 | | * A constructor that allocates a new IGMPv3 membership report with 0 group addresses |
427 | | */ |
428 | 0 | IgmpV3ReportLayer() : IgmpLayer(IgmpType_MembershipReportV3, IPv4Address(), 0, IGMPv3) {} |
429 | | |
430 | | /** |
431 | | * Get a pointer to the raw IGMPv3 membership report header. Notice this points directly to the data, so every change will change the |
432 | | * actual packet data |
433 | | * @return A pointer to the @ref igmpv3_report_header |
434 | | */ |
435 | 2.04k | igmpv3_report_header* getReportHeader() const { return (igmpv3_report_header*)m_Data; } |
436 | | |
437 | | /** |
438 | | * @return The number of group records in this message (as extracted from the igmpv3_report_header#numOfGroupRecords field) |
439 | | */ |
440 | | uint16_t getGroupRecordCount() const; |
441 | | |
442 | | /** |
443 | | * @return A pointer to the first group record or NULL if no group records exist. Notice the return value is a pointer to the real data, |
444 | | * so changes in the return value will affect the packet data |
445 | | */ |
446 | | igmpv3_group_record* getFirstGroupRecord() const; |
447 | | |
448 | | /** |
449 | | * Get the group record that comes next to a given group record. If "groupRecord" is NULL then NULL will be returned. |
450 | | * If "groupRecord" is the last group record or if it is out of layer bounds NULL will be returned also. Notice the return value is a |
451 | | * pointer to the real data casted to igmpv3_group_record type (as opposed to a copy of the option data). So changes in the return |
452 | | * value will affect the packet data |
453 | | * @param[in] groupRecord The group record to start searching from |
454 | | * @return The next group record or NULL if "groupRecord" is NULL, last or out of layer bounds |
455 | | */ |
456 | | igmpv3_group_record* getNextGroupRecord(igmpv3_group_record* groupRecord) const; |
457 | | |
458 | | /** |
459 | | * Add a new group record at a the end of the group record list. The igmpv3_report_header#numOfGroupRecords field will be |
460 | | * incremented accordingly |
461 | | * @param[in] recordType The type of the new group record |
462 | | * @param[in] multicastAddress The multicast address of the new group record |
463 | | * @param[in] sourceAddresses A vector containing all the source addresses of the new group record |
464 | | * @return The method constructs a new group record, adds it to the end of the group record list of IGMPv3 report message and |
465 | | * returns a pointer to the new message. If something went wrong in creating or adding the new group record a NULL value is returned |
466 | | * and an appropriate error message is printed to log |
467 | | */ |
468 | | igmpv3_group_record* addGroupRecord(uint8_t recordType, const IPv4Address& multicastAddress, const std::vector<IPv4Address>& sourceAddresses); |
469 | | |
470 | | /** |
471 | | * Add a new group record at a certain index of the group record list. The igmpv3_report_header#numOfGroupRecords field will be |
472 | | * incremented accordingly |
473 | | * @param[in] recordType The type of the new group record |
474 | | * @param[in] multicastAddress The multicast address of the new group record |
475 | | * @param[in] sourceAddresses A vector containing all the source addresses of the new group record |
476 | | * @param[in] index The index to add the new group address at |
477 | | * @return The method constructs a new group record, adds it to the IGMPv3 report message and returns a pointer to the new message. |
478 | | * If something went wrong in creating or adding the new group record a NULL value is returned and an appropriate error message is |
479 | | * printed to log |
480 | | */ |
481 | | igmpv3_group_record* addGroupRecordAtIndex(uint8_t recordType, const IPv4Address& multicastAddress, const std::vector<IPv4Address>& sourceAddresses, int index); |
482 | | |
483 | | /** |
484 | | * Remove a group record at a certain index. The igmpv3_report_header#numOfGroupRecords field will be decremented accordingly |
485 | | * @param[in] index The index of the group record to be removed |
486 | | * @return True if group record was removed successfully or false otherwise. If false is returned an appropriate error message |
487 | | * will be printed to log |
488 | | */ |
489 | | bool removeGroupRecordAtIndex(int index); |
490 | | |
491 | | /** |
492 | | * Remove all group records in the message. The igmpv3_report_header#numOfGroupRecords field will be set to 0 |
493 | | * @return True if all group records were cleared successfully or false otherwise. If false is returned an appropriate error message |
494 | | * will be printed to log |
495 | | */ |
496 | | bool removeAllGroupRecords(); |
497 | | |
498 | | // implement abstract methods |
499 | | |
500 | | /** |
501 | | * Calculate the IGMP checksum |
502 | | */ |
503 | | void computeCalculateFields(); |
504 | | |
505 | | /** |
506 | | * @return The message size in bytes which include the size of the basic header + the size of the group record list |
507 | | */ |
508 | 4.08k | size_t getHeaderLen() const { return m_DataLen; } |
509 | | }; |
510 | | |
511 | | } |