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 };