Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
kcenon::network::protocols::quic::packet_parser Class Reference

Parser for QUIC packet headers (RFC 9000 Section 17) More...

#include <packet.h>

Collaboration diagram for kcenon::network::protocols::quic::packet_parser:
Collaboration graph

Static Public Member Functions

static constexpr auto is_long_header (uint8_t first_byte) noexcept -> bool
 Check if a packet has a long header.
 
static constexpr auto has_valid_fixed_bit (uint8_t first_byte) noexcept -> bool
 Check if the fixed bit is set correctly.
 
static auto parse_header (std::span< const uint8_t > data) -> Result< std::pair< packet_header, size_t > >
 Parse a packet header (without header protection removal)
 
static auto parse_long_header (std::span< const uint8_t > data) -> Result< std::pair< long_header, size_t > >
 Parse a long header packet.
 
static auto parse_short_header (std::span< const uint8_t > data, size_t conn_id_length) -> Result< std::pair< short_header, size_t > >
 Parse a short header packet.
 
static constexpr auto get_long_packet_type (uint8_t first_byte) noexcept -> packet_type
 Get the packet type from long header's first byte.
 
static auto is_version_negotiation (std::span< const uint8_t > data) noexcept -> bool
 Check if this is a version negotiation packet.
 

Detailed Description

Parser for QUIC packet headers (RFC 9000 Section 17)

Parses raw bytes into QUIC packet header structures. Note that this parser handles the unprotected header format; header protection must be removed before parsing packet numbers.

Definition at line 217 of file packet.h.

Member Function Documentation

◆ get_long_packet_type()

static constexpr auto kcenon::network::protocols::quic::packet_parser::get_long_packet_type ( uint8_t first_byte) -> packet_type
inlinestaticnodiscardconstexprnoexcept

Get the packet type from long header's first byte.

Parameters
first_byteFirst byte of a long header packet
Returns
Packet type

Definition at line 273 of file packet.h.

275 {
276 return static_cast<packet_type>((first_byte >> 4) & 0x03);
277 }
packet_type
QUIC packet types (RFC 9000 Section 17)
Definition packet.h:55

◆ has_valid_fixed_bit()

static constexpr auto kcenon::network::protocols::quic::packet_parser::has_valid_fixed_bit ( uint8_t first_byte) -> bool
inlinestaticnodiscardconstexprnoexcept

Check if the fixed bit is set correctly.

Parameters
first_byteFirst byte of the packet
Returns
true if the fixed bit is 1 (as required by RFC 9000)

Definition at line 235 of file packet.h.

236 {
237 return (first_byte & 0x40) != 0;
238 }

◆ is_long_header()

static constexpr auto kcenon::network::protocols::quic::packet_parser::is_long_header ( uint8_t first_byte) -> bool
inlinestaticnodiscardconstexprnoexcept

Check if a packet has a long header.

Parameters
first_byteFirst byte of the packet
Returns
true if the packet has a long header

Definition at line 225 of file packet.h.

226 {
227 return (first_byte & 0x80) != 0;
228 }

Referenced by kcenon::network::protocols::quic::connection::receive_packet().

Here is the caller graph for this function:

◆ is_version_negotiation()

auto kcenon::network::protocols::quic::packet_parser::is_version_negotiation ( std::span< const uint8_t > data) -> bool
staticnodiscardnoexcept

Check if this is a version negotiation packet.

Parameters
dataInput buffer (at least 5 bytes)
Returns
true if this is a version negotiation packet

Definition at line 150 of file packet.cpp.

151{
152 if (data.size() < 5)
153 {
154 return false;
155 }
156 // Long header with version 0
157 if ((data[0] & header_form_long) == 0)
158 {
159 return false;
160 }
161 uint32_t version = (static_cast<uint32_t>(data[1]) << 24) |
162 (static_cast<uint32_t>(data[2]) << 16) |
163 (static_cast<uint32_t>(data[3]) << 8) |
164 static_cast<uint32_t>(data[4]);
165 return version == 0;
166}
constexpr const char * version() noexcept
Get the network system version string.
Definition network.cppm:111

References kcenon::network::version().

Here is the call graph for this function:

◆ parse_header()

auto kcenon::network::protocols::quic::packet_parser::parse_header ( std::span< const uint8_t > data) -> Result<std::pair<packet_header, size_t>>
staticnodiscard

Parse a packet header (without header protection removal)

Parameters
dataInput buffer containing the packet
Returns
Result containing (header, header_length) or error
Note
For short headers, the caller must provide the expected connection ID length via parse_short_header instead

Definition at line 168 of file packet.cpp.

170{
171 if (data.empty())
172 {
173 return make_error<std::pair<packet_header, size_t>>(
175 "Empty packet data");
176 }
177
178 if (is_long_header(data[0]))
179 {
180 auto result = parse_long_header(data);
181 if (result.is_err())
182 {
183 return make_error<std::pair<packet_header, size_t>>(
184 result.error().code, result.error().message);
185 }
186 auto& [header, len] = result.value();
187 return ok(std::make_pair(packet_header{std::move(header)}, len));
188 }
189 else
190 {
191 // For short headers, we need to know the connection ID length
192 // Return an error directing caller to use parse_short_header
193 return make_error<std::pair<packet_header, size_t>>(
195 "Short header requires known connection ID length. Use parse_short_header().");
196 }
197}
static constexpr auto is_long_header(uint8_t first_byte) noexcept -> bool
Check if a packet has a long header.
Definition packet.h:225
static auto parse_long_header(std::span< const uint8_t > data) -> Result< std::pair< long_header, size_t > >
Parse a long header packet.
Definition packet.cpp:199
constexpr uint8_t len
Length field present.
Definition frame_types.h:64
std::variant< long_header, short_header > packet_header
Variant type for packet headers.
Definition packet.h:160
VoidResult ok()

References kcenon::network::error_codes::common_errors::invalid_argument, and kcenon::network::ok().

Referenced by kcenon::network::core::messaging_quic_server::handle_packet(), and kcenon::network::internal::quic_socket::handle_packet().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ parse_long_header()

auto kcenon::network::protocols::quic::packet_parser::parse_long_header ( std::span< const uint8_t > data) -> Result<std::pair<long_header, size_t>>
staticnodiscard

Parse a long header packet.

Parameters
dataInput buffer
Returns
Result containing (header, header_length) or error

Definition at line 199 of file packet.cpp.

201{
202 // Minimum long header: 1 + 4 + 1 + 1 = 7 bytes (with empty CIDs)
203 if (data.size() < 7)
204 {
205 return make_error<std::pair<long_header, size_t>>(
207 "Insufficient data for long header");
208 }
209
210 long_header header;
211 size_t offset = 0;
212
213 // First byte
214 header.first_byte = data[offset++];
215
216 // Validate header form
217 if (!is_long_header(header.first_byte))
218 {
219 return make_error<std::pair<long_header, size_t>>(
221 "Not a long header packet");
222 }
223
224 // Validate fixed bit
225 if (!has_valid_fixed_bit(header.first_byte))
226 {
227 return make_error<std::pair<long_header, size_t>>(
229 "Invalid fixed bit in long header");
230 }
231
232 // Version (4 bytes, big-endian)
233 if (data.size() < offset + 4)
234 {
235 return make_error<std::pair<long_header, size_t>>(
237 "Insufficient data for version");
238 }
239 header.version = (static_cast<uint32_t>(data[offset]) << 24) |
240 (static_cast<uint32_t>(data[offset + 1]) << 16) |
241 (static_cast<uint32_t>(data[offset + 2]) << 8) |
242 static_cast<uint32_t>(data[offset + 3]);
243 offset += 4;
244
245 // Destination Connection ID Length (1 byte)
246 if (data.size() < offset + 1)
247 {
248 return make_error<std::pair<long_header, size_t>>(
250 "Insufficient data for DCID length");
251 }
252 uint8_t dcid_len = data[offset++];
253 if (dcid_len > connection_id::max_length)
254 {
255 return make_error<std::pair<long_header, size_t>>(
257 "DCID length exceeds maximum");
258 }
259
260 // Destination Connection ID
261 if (data.size() < offset + dcid_len)
262 {
263 return make_error<std::pair<long_header, size_t>>(
265 "Insufficient data for DCID");
266 }
267 header.dest_conn_id = connection_id(data.subspan(offset, dcid_len));
268 offset += dcid_len;
269
270 // Source Connection ID Length (1 byte)
271 if (data.size() < offset + 1)
272 {
273 return make_error<std::pair<long_header, size_t>>(
275 "Insufficient data for SCID length");
276 }
277 uint8_t scid_len = data[offset++];
278 if (scid_len > connection_id::max_length)
279 {
280 return make_error<std::pair<long_header, size_t>>(
282 "SCID length exceeds maximum");
283 }
284
285 // Source Connection ID
286 if (data.size() < offset + scid_len)
287 {
288 return make_error<std::pair<long_header, size_t>>(
290 "Insufficient data for SCID");
291 }
292 header.src_conn_id = connection_id(data.subspan(offset, scid_len));
293 offset += scid_len;
294
295 // Type-specific fields
296 auto ptype = header.type();
297
298 if (ptype == packet_type::initial)
299 {
300 // Token Length (varint)
301 auto token_len_result = varint::decode(data.subspan(offset));
302 if (token_len_result.is_err())
303 {
304 return make_error<std::pair<long_header, size_t>>(
306 "Failed to decode token length");
307 }
308 auto [token_len, token_len_bytes] = token_len_result.value();
309 offset += token_len_bytes;
310
311 // Token
312 if (data.size() < offset + token_len)
313 {
314 return make_error<std::pair<long_header, size_t>>(
316 "Insufficient data for token");
317 }
318 header.token.assign(data.begin() + static_cast<ptrdiff_t>(offset),
319 data.begin() + static_cast<ptrdiff_t>(offset + token_len));
320 offset += token_len;
321
322 // Packet Length (varint)
323 auto pkt_len_result = varint::decode(data.subspan(offset));
324 if (pkt_len_result.is_err())
325 {
326 return make_error<std::pair<long_header, size_t>>(
328 "Failed to decode packet length");
329 }
330 offset += pkt_len_result.value().second;
331
332 // Packet number length from reserved bits
333 header.packet_number_length = (header.first_byte & pn_length_mask) + 1;
334 }
335 else if (ptype == packet_type::handshake || ptype == packet_type::zero_rtt)
336 {
337 // Packet Length (varint)
338 auto pkt_len_result = varint::decode(data.subspan(offset));
339 if (pkt_len_result.is_err())
340 {
341 return make_error<std::pair<long_header, size_t>>(
343 "Failed to decode packet length");
344 }
345 offset += pkt_len_result.value().second;
346
347 // Packet number length from reserved bits
348 header.packet_number_length = (header.first_byte & pn_length_mask) + 1;
349 }
350 else if (ptype == packet_type::retry)
351 {
352 // Retry packets have token (remaining bytes except last 16) and integrity tag
353 // We don't parse the actual payload here, just note that it's a retry
354 // The token is everything between the header and the integrity tag
355 }
356
357 return ok(std::make_pair(std::move(header), offset));
358}
static constexpr size_t max_length
Maximum length of a connection ID (RFC 9000)
static constexpr auto has_valid_fixed_bit(uint8_t first_byte) noexcept -> bool
Check if the fixed bit is set correctly.
Definition packet.h:235
static auto decode(std::span< const uint8_t > data) -> Result< std::pair< uint64_t, size_t > >
Decode variable-length integer from buffer.
Definition varint.cpp:146

References kcenon::network::protocols::quic::varint::decode(), kcenon::network::protocols::quic::long_header::dest_conn_id, kcenon::network::protocols::quic::long_header::first_byte, kcenon::network::protocols::quic::handshake, kcenon::network::protocols::quic::initial, kcenon::network::error_codes::common_errors::invalid_argument, kcenon::network::protocols::quic::connection_id::max_length, kcenon::network::ok(), kcenon::network::protocols::quic::long_header::packet_number_length, kcenon::network::protocols::quic::retry, kcenon::network::protocols::quic::long_header::src_conn_id, kcenon::network::protocols::quic::long_header::token, kcenon::network::protocols::quic::long_header::type(), kcenon::network::protocols::quic::long_header::version, and kcenon::network::protocols::quic::zero_rtt.

Referenced by kcenon::network::protocols::quic::connection::receive_packet().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ parse_short_header()

auto kcenon::network::protocols::quic::packet_parser::parse_short_header ( std::span< const uint8_t > data,
size_t conn_id_length ) -> Result<std::pair<short_header, size_t>>
staticnodiscard

Parse a short header packet.

Parameters
dataInput buffer
conn_id_lengthExpected destination connection ID length
Returns
Result containing (header, header_length) or error

Definition at line 360 of file packet.cpp.

363{
364 // Minimum: 1 byte first + conn_id + 1 byte packet number
365 if (data.size() < 1 + conn_id_length + 1)
366 {
367 return make_error<std::pair<short_header, size_t>>(
369 "Insufficient data for short header");
370 }
371
372 short_header header;
373 size_t offset = 0;
374
375 // First byte
376 header.first_byte = data[offset++];
377
378 // Validate header form (should be 0 for short header)
379 if (is_long_header(header.first_byte))
380 {
381 return make_error<std::pair<short_header, size_t>>(
383 "Not a short header packet");
384 }
385
386 // Validate fixed bit
387 if (!has_valid_fixed_bit(header.first_byte))
388 {
389 return make_error<std::pair<short_header, size_t>>(
391 "Invalid fixed bit in short header");
392 }
393
394 // Destination Connection ID
395 if (conn_id_length > 0)
396 {
397 if (data.size() < offset + conn_id_length)
398 {
399 return make_error<std::pair<short_header, size_t>>(
401 "Insufficient data for DCID");
402 }
403 header.dest_conn_id = connection_id(data.subspan(offset, conn_id_length));
404 offset += conn_id_length;
405 }
406
407 // Packet number length from reserved bits
408 header.packet_number_length = (header.first_byte & pn_length_mask) + 1;
409
410 return ok(std::make_pair(std::move(header), offset));
411}

References kcenon::network::protocols::quic::short_header::dest_conn_id, kcenon::network::protocols::quic::short_header::first_byte, kcenon::network::error_codes::common_errors::invalid_argument, kcenon::network::ok(), and kcenon::network::protocols::quic::short_header::packet_number_length.

Referenced by kcenon::network::protocols::quic::connection::receive_packet().

Here is the call graph for this function:
Here is the caller graph for this function:

The documentation for this class was generated from the following files: