lib/quic/src/packet/model.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2
3 pub const connection_id_bytes_max: u5 = 20;
4 const ConnectionIdBytes = [connection_id_bytes_max]u8;
5
6 /// A 20-byte array with the count of bytes in use holds the identifier a packet header carries, the
7 /// connection ID. A caller reads one out of a decoded header, or builds one to encode, and passes
8 /// it by value. RFC 9000 section 17.2 bounds a version 1 connection ID at 20 bytes, so the array
9 /// holds every legal value and the value copies without touching an allocator. Building one from a
10 /// longer slice gives `ConnectionIdTooLong`. The bytes past the length are zero, and `slice`
11 /// returns the bytes in use.
12 pub const ConnectionId = struct {
13 bytes: ConnectionIdBytes,
14 length: u5,
15
16 pub fn init(input: []const u8) error{ConnectionIdTooLong}!ConnectionId {
17 if (input.len > connection_id_bytes_max) return error.ConnectionIdTooLong;
18 var result = ConnectionId{
19 .bytes = @splat(0),
20 .length = @intCast(input.len),
21 };
22 @memcpy(result.bytes[0..input.len], input);
23 return result;
24 }
25
26 pub fn slice(self: *const ConnectionId) []const u8 {
27 std.debug.assert(self.length <= connection_id_bytes_max);
28 return self.bytes[0..self.length];
29 }
30 };
31
32 pub const Common = struct {
33 first: u8,
34 version: u32,
35 destination: ConnectionId,
36 source: ConnectionId,
37 };
38
39 pub const Initial = struct {
40 common: Common,
41 token: []const u8,
42 length: u62,
43 packet_number_offset: usize,
44 };
45
46 pub const Protected = struct {
47 common: Common,
48 length: u62,
49 packet_number_offset: usize,
50 };
51
52 pub const Retry = struct {
53 common: Common,
54 token: []const u8,
55 integrity_tag: [16]u8,
56 };
57
58 pub const VersionNegotiation = struct {
59 common: Common,
60 versions: []const u8,
61
62 pub fn iterator(self: VersionNegotiation) VersionIterator {
63 return .{ .bytes = self.versions, .index = 0 };
64 }
65 };
66
67 pub const VersionIterator = struct {
68 bytes: []const u8,
69 index: usize,
70
71 pub fn next(self: *VersionIterator) ?u32 {
72 std.debug.assert(self.index <= self.bytes.len);
73 if (self.index == self.bytes.len) return null;
74 std.debug.assert(self.bytes.len - self.index >= 4);
75 const value = std.mem.readInt(u32, self.bytes[self.index..][0..4], .big);
76 self.index += 4;
77 return value;
78 }
79 };
80
81 pub const Long = union(enum) {
82 initial: Initial,
83 zero_rtt: Protected,
84 handshake: Protected,
85 retry: Retry,
86 version_negotiation: VersionNegotiation,
87
88 pub fn packetNumberOffset(self: Long) ?usize {
89 return switch (self) {
90 .initial => |value| value.packet_number_offset,
91 .zero_rtt, .handshake => |value| value.packet_number_offset,
92 .retry, .version_negotiation => null,
93 };
94 }
95 };
96
97 pub const Short = struct {
98 first: u8,
99 destination: ConnectionId,
100 packet_number_offset: usize,
101 };