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 152 of file packet.cpp.

153{
154 if (data.size() < 5)
155 {
156 return false;
157 }
158 // Long header with version 0
159 if ((data[0] & header_form_long) == 0)
160 {
161 return false;
162 }
163 uint32_t version = (static_cast<uint32_t>(data[1]) << 24) |
164 (static_cast<uint32_t>(data[2]) << 16) |
165 (static_cast<uint32_t>(data[3]) << 8) |
166 static_cast<uint32_t>(data[4]);
167 return version == 0;
168}
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 170 of file packet.cpp.

172{
173 if (data.empty())
174 {
175 return make_error<std::pair<packet_header, size_t>>(
177 "Empty packet data");
178 }
179
180 if (is_long_header(data[0]))
181 {
182 auto result = parse_long_header(data);
183 if (result.is_err())
184 {
185 return make_error<std::pair<packet_header, size_t>>(
186 result.error().code, result.error().message);
187 }
188 auto& [header, len] = result.value();
189 return ok(std::make_pair(packet_header{std::move(header)}, len));
190 }
191 else
192 {
193 // For short headers, we need to know the connection ID length
194 // Return an error directing caller to use parse_short_header
195 return make_error<std::pair<packet_header, size_t>>(
197 "Short header requires known connection ID length. Use parse_short_header().");
198 }
199}
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:201
uint32_t code
Definition hpack.cpp:668
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 code, 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 201 of file packet.cpp.

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

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

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: