lib/quic/src/connection/machine.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

   1 const std = @import("std");
   2 const quic = @import("../root.zig");
   3 
   4 /// Three-second span that a closing or draining connection stands before it reports itself closed,
   5 /// so a caller waiting on `nextTimeout` knows how long the connection stays before reporting
   6 /// closed. Both `close` and the path that fails a connection from inside set that deadline three
   7 /// seconds past the time the caller gave. The span is a constant, so it rests on no measurement of
   8 /// the path.
   9 pub const closing_period_ns: u64 = 3 * std.time.ns_per_s;
  10 
  11 /// Maximum byte length of a close reason, published so a caller can size its reason string against
  12 /// this bound because `close` answers `ReasonTooLong` for anything longer. The figure defines how
  13 /// far a close reason may run while its packets still fit a 1200-byte datagram with 20-byte
  14 /// connection IDs at both ends. The figure is the lesser of what one Initial close packet leaves
  15 /// free and what a Handshake and a 1-RTT close packet leave free between them, because a 1-RTT
  16 /// close raised before the handshake is confirmed travels behind a Handshake copy.
  17 pub const close_reason_bytes_max: usize = closeReasonCapacity();
  18 
  19 const PacketView = struct {
  20     kind: quic.connection.SpaceKind,
  21     length: usize,
  22     packet_number_offset: usize,
  23     destination: quic.packet.ConnectionId,
  24     source: ?quic.packet.ConnectionId,
  25 };
  26 
  27 const LongMetadata = struct {
  28     kind: quic.connection.SpaceKind,
  29     length: u62,
  30     offset: usize,
  31     destination: quic.packet.ConnectionId,
  32     source: quic.packet.ConnectionId,
  33 };
  34 
  35 const Payload = struct {
  36     bytes: []const u8,
  37     summary: quic.connection.FrameSummary,
  38     ack_eliciting: bool,
  39     sent_ack: bool,
  40     sent_ping: bool,
  41     sent_handshake_done: bool,
  42     sent_close: bool,
  43 };
  44 
  45 const PacketPlan = struct {
  46     number: quic.connection.NumberEncoding,
  47     payload_capacity: usize,
  48 };
  49 
  50 /// Armed probe timeout holding when it fires and which packet number space it is meant for, built
  51 /// by the timer path to store on the connection. The `armedProbe` function picks the soonest probe
  52 /// among the spaces holding packets the peer has yet to settle.
  53 const Probe = struct {
  54     deadline_ns: u64,
  55     kind: quic.connection.SpaceKind,
  56 };
  57 
  58 /// Pair of results from opening one packet, holding the packet itself and whether it was protected
  59 /// under a phase other than the one being read now. The receive path needs both results before it
  60 /// can record anything in the key state. A long header carries no phase bit, so a packet with one
  61 /// reports no difference.
  62 const OpenedPacket = struct {
  63     opened: quic.crypto.packet.Opened,
  64     phase_changed: bool,
  65 };
  66 
  67 const ViewError = error{ Malformed, Unsupported };
  68 const PayloadError = quic.frame.EncodeError || error{EmptyRanges};
  69 
  70 const StreamId = quic.connection.stream.StreamId;
  71 const SendState = quic.connection.stream.SendState;
  72 const ReceiveState = quic.connection.stream.ReceiveState;
  73 const ReadResult = quic.connection.stream.ReadResult;
  74 const frameDataCapacity = quic.connection.stream.frameDataCapacity;
  75 const frameHeaderBytes = quic.connection.stream.frameHeaderBytes;
  76 
  77 pub const OpenError = error{ NotClient, NotEstablished, StreamExists, StreamLimit };
  78 
  79 /// Acknowledgment sink taking each sent record that one ACK frame settled for the first time, so
  80 /// the connection releases what the packet carried. A settled CRYPTO frame takes its bytes out of
  81 /// the handshake stretch that space had waiting. In the application space, a settled STREAM frame
  82 /// and a settled RESET_STREAM go on to the sending half of stream 0. A record from either other
  83 /// space stops once the CRYPTO step is done.
  84 const AckSink = struct {
  85     connection: *Connection,
  86     kind: quic.connection.SpaceKind,
  87 
  88     pub fn onAcknowledged(self: AckSink, record: quic.connection.SentRecord) void {
  89         const frames = record.frames;
  90         if (frames.crypto) |range| {
  91             const lost = &self.connection.crypto_lost[spaceIndex(self.kind)];
  92             lost.acknowledge(range.offset, range.length);
  93         }
  94         if (self.kind != .application) return;
  95         const send_part = &self.connection.stream_send;
  96         if (frames.stream) |range| send_part.acknowledge(range.offset, range.length, range.fin);
  97         if (frames.reset_stream != null) send_part.acknowledgeReset();
  98     }
  99 };
 100 
 101 /// Loss sink taking and counting each record one detection pass gave up on, so the connection
 102 /// queues those frames again. A lost CRYPTO frame puts its bytes into the handshake stretch that
 103 /// space has waiting. In the application space, the remainder of the record goes to
 104 /// `loseApplicationFrames`. ACK, PING, and CONNECTION_CLOSE frames find no route back into a
 105 /// packet, since `loseApplicationFrames` holds no branch for them.
 106 const LossSink = struct {
 107     connection: *Connection,
 108     kind: quic.connection.SpaceKind,
 109 
 110     pub fn onLost(self: LossSink, record: quic.connection.SentRecord) void {
 111         std.debug.assert(record.lost);
 112         std.debug.assert(self.kind == self.connection.space(self.kind).kind);
 113         std.debug.assert(record.frames.max_streams == null);
 114         increment(&self.connection.stats_value.packets_lost);
 115         const frames = record.frames;
 116         if (frames.crypto) |range| {
 117             const lost = &self.connection.crypto_lost[spaceIndex(self.kind)];
 118             lost.add(range.offset, range.length);
 119         }
 120         if (self.kind == .application) self.connection.loseApplicationFrames(frames);
 121     }
 122 };
 123 
 124 pub const InitError = quic.connection.Storage.Capacity.DeriveError ||
 125     quic.connection.KeyState.InstallError || quic.tls.InitError ||
 126     quic.connection.parameters.Error ||
 127     error{ InvalidConfig, RandomFailed, StorageMismatch };
 128 
 129 /// Primary type for one QUIC endpoint, held by a caller to drive with `receive`, `send`, and
 130 /// `nextTimeout`, reading and writing byte slices its caller owns, and opening no socket of its
 131 /// own. The connection holds a pointer into its storage, so it and that storage both stay at fixed
 132 /// addresses for as long as it lives. The `init` constructor wants a configuration, the limits, and
 133 /// storage already set up for those same limits, and answers `StorageMismatch` for storage set up
 134 /// for others. Inside the connection are one record per packet number space, the key state, the TLS
 135 /// engine, both halves of stream 0, and the send credit and receive window that cover the whole
 136 /// connection. The `deinit` method gives back the TLS storage and the keys, and marks the storage
 137 /// ready for the caller to take back.
 138 pub const Connection = struct {
 139     config: quic.connection.Config,
 140     limits: quic.connection.Limits,
 141     storage: *quic.connection.Storage,
 142     local_cid: quic.packet.ConnectionId,
 143     peer_cid: ?quic.packet.ConnectionId,
 144     original_dcid: ?quic.packet.ConnectionId,
 145     peer_source_cid: ?quic.packet.ConnectionId,
 146     engine: ?quic.tls.Engine,
 147     keys: quic.connection.KeyState,
 148     spaces: [3]quic.connection.Space,
 149     crypto_streams: [3]quic.connection.Reassembler,
 150     crypto_send_offsets: [3]u62 = .{ 0, 0, 0 },
 151     /// Storage where each packet number space's lost handshake bytes wait for a packet, holding
 152     /// them until they go out again ahead of anything TLS has newly produced. The `emitCrypto`
 153     /// method clears them before it asks TLS for anything new. Dropping a space's keys empties its
 154     /// entry.
 155     crypto_lost: [3]quic.connection.recovery.LostRange = @splat(.{}),
 156     status_value: quic.connection.Status = .handshaking,
 157     close_reason_value: ?quic.connection.CloseReason = null,
 158     close_pending: bool = false,
 159     close_deadline_ns: ?u64 = null,
 160     close_packets_since_response: u16 = 0,
 161     close_response_packet_limit: u16 = 1,
 162     pending_ping: bool = false,
 163     pending_handshake_done: bool = false,
 164     handshake_done_received: bool = false,
 165     handshake_confirmed: bool = false,
 166     handshake_acknowledged: bool = false,
 167     rtt: quic.connection.recovery.Estimator = .{},
 168     pto_count: u32 = 0,
 169     pto_deadline_ns: ?u64 = null,
 170     pto_space: quic.connection.SpaceKind = .initial,
 171     /// Timestamp recording when a client first armed its anti-deadlock probe with nothing
 172     /// outstanding, holding that deadline still across the arming that `send` and `receive` do on
 173     /// every call. Both `send` and `receive` arm the timer afresh on every call, and this anchor
 174     /// keeps those calls from pushing the probe further off. The anchor empties once packets go
 175     /// out, once the peer has proof of this endpoint's address, and once a probe deadline passes.
 176     pto_anchor_ns: ?u64 = null,
 177     probe_packets: [3]u8 = @splat(0),
 178     peer_parameters_authenticated: bool = false,
 179     peer_parameters: ?quic.transport.Parameters = null,
 180     stream_send: quic.connection.stream.Send,
 181     stream_receive: quic.connection.stream.Receive,
 182     connection_credit: quic.connection.stream.Credit = .{ .limit = 0 },
 183     connection_window: quic.connection.stream.Window,
 184     stream_open: bool = false,
 185     stream_accepted: bool = false,
 186     peer_streams_bidi: u62 = 0,
 187     streams_blocked_pending: bool = false,
 188     streams_blocked_sent: bool = false,
 189     effective_idle_timeout_ms: u62,
 190     timer_started: bool = false,
 191     last_activity_ns: u64 = 0,
 192     client_address_validated: bool,
 193     received_before_validation: u64 = 0,
 194     sent_before_validation: u64 = 0,
 195     stats_value: quic.connection.Stats = .{},
 196     deinitialized: bool = false,
 197 
 198     pub fn init(
 199         config: quic.connection.Config,
 200         limits: quic.connection.Limits,
 201         storage: *quic.connection.Storage,
 202     ) InitError!Connection {
 203         const expected = try quic.connection.Storage.Capacity.derive(limits);
 204         if (storage.phase != .initialization) return error.StorageMismatch;
 205         if (storage.capacity.storage_bytes != expected.storage_bytes) {
 206             return error.StorageMismatch;
 207         }
 208         if (storage.capacity.stream_receive_offset != expected.stream_receive_offset) {
 209             return error.StorageMismatch;
 210         }
 211         if (config.local_cid.len == 0) return error.InvalidConfig;
 212         if (config.local_cid.len > quic.packet.connection_id_bytes_max) {
 213             return error.InvalidConfig;
 214         }
 215         if (config.ack_delay_exponent > 20) return error.InvalidConfig;
 216         const local_cid = quic.packet.ConnectionId.init(config.local_cid) catch
 217             return error.InvalidConfig;
 218         var self = Connection{
 219             .config = config,
 220             .limits = limits,
 221             .storage = storage,
 222             .local_cid = local_cid,
 223             .peer_cid = null,
 224             .original_dcid = null,
 225             .peer_source_cid = null,
 226             .engine = null,
 227             .keys = quic.connection.KeyState.init(storage),
 228             .spaces = initSpaces(storage),
 229             .crypto_streams = initCryptoStreams(storage),
 230             .stream_send = quic.connection.stream.Send.init(
 231                 storage.stream_send_bytes,
 232                 storage.stream_sent_ranges,
 233                 0,
 234             ),
 235             .stream_receive = quic.connection.stream.Receive.init(
 236                 storage.stream_receive_bytes,
 237                 storage.stream_receive_ranges,
 238                 quic.connection.parameters.streamReceiveWindow(config, limits),
 239             ),
 240             .connection_window = quic.connection.stream.Window.init(config.initial_max_data),
 241             .effective_idle_timeout_ms = config.max_idle_timeout,
 242             .client_address_validated = config.role == .client,
 243         };
 244         errdefer self.keys.deinit();
 245         if (config.role == .client) try self.initializeClient();
 246         storage.activate();
 247         std.debug.assert(self.storage == storage);
 248         std.debug.assert(self.local_cid.length >= 1);
 249         return self;
 250     }
 251 
 252     pub fn deinit(self: *Connection) void {
 253         std.debug.assert(!self.deinitialized);
 254         if (self.engine) |*engine| {
 255             engine.deinit();
 256         } else {
 257             self.storage.tls_storage.activate();
 258         }
 259         _ = self.storage.tls_storage.deinit();
 260         self.keys.deinit();
 261         self.storage.nested_released = true;
 262         self.deinitialized = true;
 263     }
 264 
 265     pub fn state(self: *const Connection) quic.connection.Status {
 266         std.debug.assert(!self.deinitialized);
 267         return self.status_value;
 268     }
 269 
 270     pub fn closeReason(self: *const Connection) ?quic.connection.CloseReason {
 271         std.debug.assert(!self.deinitialized);
 272         return self.close_reason_value;
 273     }
 274 
 275     pub fn stats(self: *const Connection) quic.connection.Stats {
 276         std.debug.assert(!self.deinitialized);
 277         return self.stats_value;
 278     }
 279 
 280     /// Hands back what the connection has measured of the path, so a caller sees what the
 281     /// connection's timers rest on.
 282     pub fn roundTrip(self: *const Connection) quic.connection.recovery.Estimator {
 283         std.debug.assert(!self.deinitialized);
 284         return self.rtt;
 285     }
 286 
 287     /// Adds up what all three packet number spaces have outstanding, so a caller watching
 288     /// congestion reads the total bytes in flight.
 289     pub fn bytesInFlight(self: *const Connection) u64 {
 290         std.debug.assert(!self.deinitialized);
 291         var total: u64 = 0;
 292         for (&self.spaces) |*space_value| total += space_value.bytesInFlight();
 293         return total;
 294     }
 295 
 296     pub fn peer(self: *const Connection) ?quic.tls.Peer {
 297         std.debug.assert(!self.deinitialized);
 298         const engine = if (self.engine) |*value| value else return null;
 299         return engine.peer();
 300     }
 301 
 302     pub fn initialKeysDiscarded(self: *const Connection) bool {
 303         return self.keys.initial_write == null and self.keys.initial_read == null;
 304     }
 305 
 306     pub fn handshakeKeysDiscarded(self: *const Connection) bool {
 307         return self.keys.handshake_write == null and self.keys.handshake_read == null;
 308     }
 309 
 310     pub fn requestKeyUpdate(self: *Connection) error{NotEstablished}!void {
 311         if (self.status_value != .established) return error.NotEstablished;
 312         self.keys.requestUpdate();
 313         self.pending_ping = true;
 314     }
 315 
 316     pub fn ping(self: *Connection) error{NotEstablished}!void {
 317         if (self.status_value != .established) return error.NotEstablished;
 318         self.pending_ping = true;
 319     }
 320 
 321     /// Opens stream 0 for a client once the connection is established, and gives back the
 322     /// identifier 0, so the client obtains stream 0 before it writes. A server gets `NotClient`, a
 323     /// call made ahead of that point gets `NotEstablished`, and a repeat gets `StreamExists`. A
 324     /// peer that allows no streams gets `StreamLimit`, and one STREAMS_BLOCKED frame goes in the
 325     /// queue.
 326     pub fn openStream(self: *Connection) OpenError!StreamId {
 327         std.debug.assert(!self.deinitialized);
 328         if (self.config.role != .client) return error.NotClient;
 329         if (self.status_value != .established) return error.NotEstablished;
 330         if (self.stream_open) return error.StreamExists;
 331         if (self.peer_streams_bidi == 0) {
 332             if (!self.streams_blocked_sent) self.streams_blocked_pending = true;
 333             return error.StreamLimit;
 334         }
 335         self.stream_open = true;
 336         return 0;
 337     }
 338 
 339     /// Gives a server the identifier 0 once, after the client's first frame for that stream has
 340     /// arrived, so the server learns that the client has opened stream 0. A client receives null,
 341     /// and a server asking ahead of that frame or asking a second time also receives null.
 342     pub fn acceptStream(self: *Connection) ?StreamId {
 343         std.debug.assert(!self.deinitialized);
 344         if (self.config.role != .server) return null;
 345         if (!self.stream_open) return null;
 346         if (self.stream_accepted) return null;
 347         self.stream_accepted = true;
 348         return 0;
 349     }
 350 
 351     /// Takes application bytes into the send buffer, as many as the free room allows, and reports
 352     /// how many it took, providing the entry point for an application to hand stream bytes to the
 353     /// connection. Bytes go in for identifier 0 on an open stream, while the connection is
 354     /// handshaking or established.
 355     pub fn write(self: *Connection, id: StreamId, bytes: []const u8) usize {
 356         if (!self.streamOpenForApplication(id)) return 0;
 357         return self.stream_send.write(bytes);
 358     }
 359 
 360     /// Settles the final size at whatever has been written so far, so an application ends its side
 361     /// of the stream. The call acts for identifier 0 on an open stream, while the connection is
 362     /// handshaking or established.
 363     pub fn finish(self: *Connection, id: StreamId) void {
 364         if (!self.streamOpenForApplication(id)) return;
 365         self.stream_send.finish();
 366     }
 367 
 368     /// Copies waiting bytes in offset order and says whether they carry the reader to the FIN,
 369     /// enabling an application to take received stream bytes and release receive window room back
 370     /// to the peer. The method copies for identifier 0 on an open stream.
 371     pub fn read(self: *Connection, id: StreamId, out: []u8) ReadResult {
 372         if (!self.streamKnown(id)) return .{ .bytes = 0, .fin = false };
 373         return self.stream_receive.read(&self.connection_window, out);
 374     }
 375 
 376     /// Gives up on sending and puts RESET_STREAM in the queue under the caller's code, so an
 377     /// application abandons its side of the stream. The call acts for identifier 0 on an open
 378     /// stream, while the connection is handshaking or established.
 379     pub fn resetStream(self: *Connection, id: StreamId, app_error_code: u62) void {
 380         if (!self.streamOpenForApplication(id)) return;
 381         _ = self.stream_send.reset(app_error_code);
 382     }
 383 
 384     /// Puts STOP_SENDING in the queue under the caller's code while data may still arrive, so an
 385     /// application tells the peer to stop sending. The call acts for identifier 0 on an open
 386     /// stream, while the connection is handshaking or established.
 387     pub fn stopSending(self: *Connection, id: StreamId, app_error_code: u62) void {
 388         if (!self.streamOpenForApplication(id)) return;
 389         _ = self.stream_receive.stop(app_error_code);
 390     }
 391 
 392     /// Hands back how far the sending half of an open stream has traveled, so an application sees
 393     /// whether its data was acknowledged or its reset took effect. The method answers for
 394     /// identifier 0 on an open stream, and offers null elsewhere.
 395     pub fn sendState(self: *const Connection, id: StreamId) ?SendState {
 396         if (!self.streamKnown(id)) return null;
 397         return self.stream_send.state;
 398     }
 399 
 400     /// Hands back how far the receiving half of an open stream has traveled, so an application
 401     /// sees whether the peer has finished or reset the stream. The method answers for identifier 0
 402     /// on an open stream, and offers null elsewhere.
 403     pub fn receiveState(self: *const Connection, id: StreamId) ?ReceiveState {
 404         if (!self.streamKnown(id)) return null;
 405         return self.stream_receive.state;
 406     }
 407 
 408     /// Hands back how far an open stream's data has traveled and which codes each side sent, so an
 409     /// application inspects stream progress and exchanged error codes. The method answers for
 410     /// identifier 0 on an open stream, and offers null elsewhere.
 411     pub fn streamStats(self: *const Connection, id: StreamId) ?quic.connection.StreamStats {
 412         if (!self.streamKnown(id)) return null;
 413         const send_part = &self.stream_send;
 414         const receive_part = &self.stream_receive;
 415         return .{
 416             .bytes_written = send_part.written,
 417             .bytes_sent = send_part.sent,
 418             .bytes_released = send_part.acknowledged,
 419             .bytes_received = receive_part.window.received,
 420             .bytes_read = receive_part.read_offset,
 421             .send_final_size = send_part.final_size,
 422             .receive_final_size = receive_part.final_size,
 423             .reset_sent_code = send_part.reset_code,
 424             .reset_received_code = receive_part.reset_code,
 425             .stop_sending_sent_code = receive_part.stop_code,
 426         };
 427     }
 428 
 429     /// Moves the connection into closing and starts the closing period from the time the caller
 430     /// gave, so a close unable to reach the wire still ends and the caller receives the deadline to
 431     /// stop driving the connection. A reason past `close_reason_bytes_max` answers `ReasonTooLong`
 432     /// and changes nothing. The reason text is copied into the connection's own storage. When
 433     /// called on a connection that has already left handshaking or established, the call returns
 434     /// with the status untouched.
 435     pub fn close(
 436         self: *Connection,
 437         error_code: u62,
 438         application: bool,
 439         reason: []const u8,
 440         now_ns: u64,
 441     ) error{ReasonTooLong}!void {
 442         std.debug.assert(!self.deinitialized);
 443         std.debug.assert(close_reason_bytes_max <= self.storage.reason.len);
 444         if (reason.len > close_reason_bytes_max) return error.ReasonTooLong;
 445         self.advanceTime(now_ns);
 446         if (!isOpen(self.status_value)) return;
 447         std.debug.assert(self.close_deadline_ns == null);
 448         self.storeReason(error_code, application, null, reason, false);
 449         self.status_value = .closing;
 450         self.close_pending = true;
 451         self.close_deadline_ns = closeDeadline(now_ns);
 452     }
 453 
 454     pub fn receive(self: *Connection, datagram: []const u8, now_ns: u64) void {
 455         std.debug.assert(self.storage.phase == .steady);
 456         std.debug.assert(!self.deinitialized);
 457         self.advanceTime(now_ns);
 458         if (self.status_value == .closed or self.status_value == .draining) return;
 459         increment(&self.stats_value.datagrams_received);
 460         if (self.config.role == .server and !self.client_address_validated) {
 461             self.received_before_validation +|= datagram.len;
 462         }
 463         defer self.armProbeTimeout(now_ns);
 464         if (datagram.len > self.limits.datagram_bytes) {
 465             increment(&self.stats_value.drops.oversized);
 466             return;
 467         }
 468         if (self.status_value == .closing) self.noteClosingDatagram();
 469         self.receivePackets(datagram, now_ns);
 470     }
 471 
 472     pub fn send(self: *Connection, out: []u8, now_ns: u64) usize {
 473         std.debug.assert(self.storage.phase == .steady);
 474         std.debug.assert(!self.deinitialized);
 475         self.advanceTime(now_ns);
 476         if (self.status_value == .closed or self.status_value == .draining) return 0;
 477         if (out.len == 0) return 0;
 478         if (self.status_value == .closing) return self.sendClosing(out, now_ns);
 479         if (self.status_value == .established) {
 480             self.keys.prepareSend(true, self.space(.application).next_packet_number);
 481         }
 482         var datagram_length: usize = 0;
 483         var carries_initial = false;
 484         const can_coalesce_handshake = self.keys.write(.handshake) != null;
 485         for ([_]quic.connection.SpaceKind{ .initial, .handshake, .application }) |kind| {
 486             const limit = self.sendLimit(out.len);
 487             if (datagram_length >= limit) break;
 488             const available = limit - datagram_length;
 489             const minimum = packetMinimum(kind, available, carries_initial, can_coalesce_handshake);
 490             const force_ping = (kind == .handshake and carries_initial) or
 491                 self.probe_packets[spaceIndex(kind)] != 0;
 492             const count = self.sendSpace(
 493                 kind,
 494                 out[datagram_length..limit],
 495                 available,
 496                 minimum,
 497                 force_ping,
 498                 now_ns,
 499             );
 500             if (kind == .initial and count != 0) carries_initial = true;
 501             datagram_length += count;
 502         }
 503         if (carries_initial) std.debug.assert(datagram_length >= 1200);
 504         if (datagram_length != 0) self.recordDatagramSent(datagram_length);
 505         self.armProbeTimeout(now_ns);
 506         return datagram_length;
 507     }
 508 
 509     pub fn nextTimeout(self: *const Connection, now_ns: u64) ?u64 {
 510         std.debug.assert(self.storage.phase == .steady);
 511         std.debug.assert(!self.deinitialized);
 512         const deadline = switch (self.status_value) {
 513             .handshaking, .established => self.activeDeadline() orelse return null,
 514             .closing, .draining => self.close_deadline_ns orelse return null,
 515             .closed => return null,
 516         };
 517         return @max(deadline, now_ns);
 518     }
 519 
 520     fn activeDeadline(self: *const Connection) ?u64 {
 521         std.debug.assert(isOpen(self.status_value));
 522         std.debug.assert(self.close_deadline_ns == null);
 523         var deadline: ?u64 = null;
 524         for (&self.spaces) |*space_value| {
 525             if (space_value.ack_due_at_ns) |due| deadline = earlier(deadline, due);
 526             if (space_value.loss_deadline_ns) |due| deadline = earlier(deadline, due);
 527         }
 528         if (self.pto_deadline_ns) |due| deadline = earlier(deadline, due);
 529         if (self.idleDeadline()) |idle| deadline = earlier(deadline, idle);
 530         return deadline;
 531     }
 532 
 533     fn initializeClient(self: *Connection) InitError!void {
 534         std.debug.assert(self.config.role == .client);
 535         std.debug.assert(self.engine == null);
 536         var random = self.config.random.values() catch return error.RandomFailed;
 537         defer std.crypto.secureZero(u8, std.mem.asBytes(&random));
 538         const destination = quic.packet.ConnectionId.init(random.hello[0..8]) catch
 539             return error.InvalidConfig;
 540         self.peer_cid = destination;
 541         self.original_dcid = destination;
 542         try self.keys.installInitial(.client, destination.slice());
 543         const encoded = try quic.connection.parameters.encode(
 544             self.config,
 545             self.limits,
 546             self.local_cid,
 547             null,
 548             self.storage.transport,
 549         );
 550         self.engine = try quic.tls.Engine.init(.{
 551             .role = .client,
 552             .identity = self.config.identity,
 553             .expected_peer = self.config.expected_peer,
 554             .alpn = self.config.alpn,
 555             .transport_parameters = encoded,
 556             .server_name = self.config.server_name,
 557             .random = self.config.random,
 558             .cipher_suite = preferredCipherSuite(self.config.preferred_suite),
 559         }, .{ .max_message = self.limits.tls_message_max }, &self.storage.tls_storage);
 560     }
 561 
 562     fn initializeServer(self: *Connection, view: PacketView, now_ns: u64) bool {
 563         std.debug.assert(self.config.role == .server);
 564         std.debug.assert(self.engine == null);
 565         std.debug.assert(view.kind == .initial);
 566         std.debug.assert(view.destination.length >= 8);
 567         const source = view.source orelse return false;
 568         self.original_dcid = view.destination;
 569         self.peer_source_cid = source;
 570         self.peer_cid = source;
 571         self.keys.installInitial(.server, view.destination.slice()) catch {
 572             self.fail(quic.connection.TransportError.internal_error, null, "initial keys", now_ns);
 573             return false;
 574         };
 575         const encoded = quic.connection.parameters.encode(
 576             self.config,
 577             self.limits,
 578             self.local_cid,
 579             view.destination,
 580             self.storage.transport,
 581         ) catch {
 582             self.fail(quic.connection.TransportError.internal_error, null, "parameters", now_ns);
 583             return false;
 584         };
 585         self.engine = quic.tls.Engine.init(.{
 586             .role = .server,
 587             .identity = self.config.identity,
 588             .expected_peer = self.config.expected_peer,
 589             .alpn = self.config.alpn,
 590             .transport_parameters = encoded,
 591             .server_name = self.config.server_name,
 592             .random = self.config.random,
 593             .cipher_suite = preferredCipherSuite(self.config.preferred_suite),
 594         }, .{ .max_message = self.limits.tls_message_max }, &self.storage.tls_storage) catch {
 595             self.fail(quic.connection.TransportError.internal_error, null, "TLS init", now_ns);
 596             return false;
 597         };
 598         return true;
 599     }
 600 
 601     fn receivePackets(self: *Connection, datagram: []const u8, now_ns: u64) void {
 602         std.debug.assert(datagram.len <= self.limits.datagram_bytes);
 603         std.debug.assert(self.status_value != .closed);
 604         var offset: usize = 0;
 605         var first_destination: ?quic.packet.ConnectionId = null;
 606         for (0..self.limits.datagram_bytes) |_| {
 607             if (offset >= datagram.len) break;
 608             const view = inspectPacket(datagram[offset..], self.local_cid.length) catch |failure| {
 609                 if (failure == error.Malformed) increment(&self.stats_value.drops.malformed);
 610                 if (failure == error.Unsupported) increment(&self.stats_value.drops.unsupported);
 611                 return;
 612             };
 613             if (first_destination == null) first_destination = view.destination;
 614             if (!sameCid(first_destination.?, view.destination)) {
 615                 increment(&self.stats_value.drops.wrong_connection);
 616                 offset += view.length;
 617                 continue;
 618             }
 619             self.receivePacket(datagram[offset..][0..view.length], datagram.len, view, now_ns);
 620             if (self.status_value == .draining or self.status_value == .closed) return;
 621             offset += view.length;
 622             if (view.kind == .application) break;
 623         }
 624     }
 625 
 626     /// Admits one packet by opening the packet, working through the payload, and writing the packet
 627     /// number into the space, serving as the single admission path that keeps the key state honest
 628     /// through the order of its steps. The key state is written last, after the payload has been
 629     /// worked through and the number written. That order holds because a packet can decrypt and
 630     /// still be dropped without ending the connection, and the key state is meant to describe the
 631     /// packets this endpoint took. A number the space holds already counts as a repeat, and the
 632     /// packet goes no further. A server taking in a Handshake packet has its proof of the client's
 633     /// address, and drops its Initial keys.
 634     fn receivePacket(
 635         self: *Connection,
 636         packet_bytes: []const u8,
 637         datagram_length: usize,
 638         view: PacketView,
 639         now_ns: u64,
 640     ) void {
 641         std.debug.assert(packet_bytes.len <= datagram_length);
 642         std.debug.assert(datagram_length <= self.limits.datagram_bytes);
 643         if (self.config.role == .server and self.engine == null and
 644             view.kind == .initial and view.destination.length < 8)
 645         {
 646             increment(&self.stats_value.drops.malformed);
 647             return;
 648         }
 649         if (self.config.role == .server and view.kind == .initial and datagram_length < 1200) {
 650             increment(&self.stats_value.drops.undersized_initial);
 651             return;
 652         }
 653         if (self.config.role == .server and self.engine == null) {
 654             if (view.kind != .initial) {
 655                 increment(&self.stats_value.drops.unavailable_keys);
 656                 return;
 657             }
 658             if (!self.initializeServer(view, now_ns)) return;
 659         }
 660         if (!self.validateConnectionIds(view)) {
 661             increment(&self.stats_value.drops.wrong_connection);
 662             return;
 663         }
 664         @memcpy(self.storage.packet[0..packet_bytes.len], packet_bytes);
 665         const mutable = self.storage.packet[0..packet_bytes.len];
 666         const result = self.openPacket(view, mutable, now_ns) orelse return;
 667         const opened = result.opened;
 668         const space_value = self.space(view.kind);
 669         if (space_value.received.contains(opened.packet_number)) {
 670             increment(&self.stats_value.drops.duplicate);
 671             return;
 672         }
 673         const ack_eliciting = self.processPayload(view.kind, opened.payload, now_ns) orelse return;
 674         const accepted = space_value.recordReceived(
 675             opened.packet_number,
 676             ack_eliciting,
 677             now_ns,
 678             maxAckDelayNs(self.config.max_ack_delay),
 679         );
 680         std.debug.assert(accepted);
 681         if (view.kind == .application and isOpen(self.status_value)) {
 682             const observed = self.observeApplicationRead(
 683                 opened.packet_number,
 684                 result.phase_changed,
 685                 now_ns,
 686             );
 687             if (!observed) return;
 688         }
 689         if (self.keys.write(view.kind) == null) space_value.clearAck();
 690         increment(&self.stats_value.packets_received);
 691         self.touchActivity(now_ns);
 692         if (self.config.role == .server and view.kind == .handshake) {
 693             self.client_address_validated = true;
 694             self.discardInitialKeys();
 695         }
 696     }
 697 
 698     fn openPacket(
 699         self: *Connection,
 700         view: PacketView,
 701         bytes: []u8,
 702         now_ns: u64,
 703     ) ?OpenedPacket {
 704         std.debug.assert(bytes.len <= self.limits.datagram_bytes);
 705         const space_value = self.space(view.kind);
 706         if (view.kind != .application) {
 707             const read_keys = self.keys.read(view.kind) orelse {
 708                 increment(&self.stats_value.drops.unavailable_keys);
 709                 return null;
 710             };
 711             const long = quic.crypto.packet.open(
 712                 read_keys,
 713                 bytes,
 714                 self.storage.scratch,
 715                 view.packet_number_offset,
 716                 space_value.largest_received,
 717             ) catch |failure| return self.openFailure(read_keys, failure, now_ns);
 718             return .{ .opened = long, .phase_changed = false };
 719         }
 720         const header_keys = self.keys.read(.application) orelse {
 721             increment(&self.stats_value.drops.unavailable_keys);
 722             return null;
 723         };
 724         const header = quic.crypto.packet.unprotect(
 725             header_keys,
 726             bytes,
 727             view.packet_number_offset,
 728             space_value.largest_received,
 729         ) catch {
 730             increment(&self.stats_value.drops.malformed);
 731             return null;
 732         };
 733         const phase_changed = header.key_phase.? != self.keys.receive_phase;
 734         const read_keys = self.keys.selectApplicationRead(header) orelse {
 735             increment(&self.stats_value.drops.unavailable_keys);
 736             return null;
 737         };
 738         const opened = quic.crypto.packet.openPayload(
 739             read_keys,
 740             bytes,
 741             header,
 742             self.storage.scratch,
 743         ) catch |failure| return self.openFailure(read_keys, failure, now_ns);
 744         return .{ .opened = opened, .phase_changed = phase_changed };
 745     }
 746 
 747     /// Writes one accepted 1-RTT packet into the key state, recognizing a key update and closing
 748     /// the connection on an illegal update. A packet of the phase now being read, arriving behind
 749     /// its neighbors, pulls the boundary down. A packet of the other phase sitting under that
 750     /// boundary is written against the older keys. A packet of the other phase in any other
 751     /// position moves the read keys on a generation. Either check failing ends the connection with
 752     /// KEY_UPDATE_ERROR and answers false. The caller has written the number down already, which
 753     /// holds the first packet of the phase now being read at or under the space's largest received
 754     /// number.
 755     fn observeApplicationRead(
 756         self: *Connection,
 757         packet_number: u62,
 758         phase_changed: bool,
 759         now_ns: u64,
 760     ) bool {
 761         std.debug.assert(self.keys.application_read_current != null);
 762         std.debug.assert(isOpen(self.status_value));
 763         std.debug.assert(self.space(.application).largest_received != null);
 764         std.debug.assert(self.space(.application).largest_received.? >= packet_number);
 765         const key_update_error = quic.connection.TransportError.key_update_error;
 766         if (!phase_changed) {
 767             self.keys.observeCurrentRead(packet_number) catch {
 768                 self.fail(key_update_error, null, "previous keys above current packet", now_ns);
 769                 return false;
 770             };
 771             return true;
 772         }
 773         const uses_previous = self.keys.previous_read_valid and
 774             packet_number < self.keys.first_current_read_packet;
 775         if (uses_previous) {
 776             self.keys.observePreviousRead(packet_number);
 777             return true;
 778         }
 779         const next_send = self.space(.application).next_packet_number;
 780         self.keys.promoteApplicationRead(packet_number, next_send) catch {
 781             self.fail(key_update_error, null, "consecutive key update", now_ns);
 782             return false;
 783         };
 784         return true;
 785     }
 786 
 787     fn openFailure(
 788         self: *Connection,
 789         read_keys: *quic.crypto.Keys,
 790         failure: quic.crypto.packet.OpenError,
 791         now_ns: u64,
 792     ) ?OpenedPacket {
 793         if (failure == error.AuthenticationFailed) {
 794             increment(&self.stats_value.drops.unauthenticated);
 795             increment(&self.stats_value.failed_authentications);
 796             if (self.stats_value.failed_authentications >= read_keys.integrityLimit()) {
 797                 self.fail(
 798                     quic.connection.TransportError.aead_limit_reached,
 799                     null,
 800                     "AEAD integrity limit",
 801                     now_ns,
 802                 );
 803             }
 804             return null;
 805         }
 806         if (failure == error.IntegrityLimitReached) {
 807             self.fail(
 808                 quic.connection.TransportError.aead_limit_reached,
 809                 null,
 810                 "AEAD integrity limit",
 811                 now_ns,
 812             );
 813             return null;
 814         }
 815         if (failure == error.ReservedBits) {
 816             self.fail(
 817                 quic.connection.TransportError.protocol_violation,
 818                 null,
 819                 "reserved packet bits",
 820                 now_ns,
 821             );
 822             return null;
 823         }
 824         increment(&self.stats_value.drops.malformed);
 825         return null;
 826     }
 827 
 828     fn processPayload(
 829         self: *Connection,
 830         kind: quic.connection.SpaceKind,
 831         payload: []u8,
 832         now_ns: u64,
 833     ) ?bool {
 834         std.debug.assert(payload.len <= self.limits.datagram_bytes);
 835         if (payload.len == 0) {
 836             self.fail(
 837                 quic.connection.TransportError.protocol_violation,
 838                 null,
 839                 "empty packet",
 840                 now_ns,
 841             );
 842             return null;
 843         }
 844         var input = quic.cursor.Read.init(payload);
 845         var ack_eliciting = false;
 846         for (0..self.limits.datagram_bytes) |_| {
 847             if (input.remaining() == 0) return ack_eliciting;
 848             const value = quic.frame.decode(&input) catch {
 849                 self.fail(
 850                     quic.connection.TransportError.frame_encoding_error,
 851                     null,
 852                     "frame encoding",
 853                     now_ns,
 854                 );
 855                 return null;
 856             };
 857             const eliciting = self.processFrame(kind, value, now_ns) orelse return null;
 858             if (eliciting) ack_eliciting = true;
 859             if (self.status_value == .draining) return ack_eliciting;
 860         }
 861         unreachable;
 862     }
 863 
 864     fn processFrame(
 865         self: *Connection,
 866         kind: quic.connection.SpaceKind,
 867         value: quic.frame.Frame,
 868         now_ns: u64,
 869     ) ?bool {
 870         std.debug.assert(self.status_value != .draining);
 871         std.debug.assert(self.status_value != .closed);
 872         if (self.status_value == .closing and value != .connection_close) return false;
 873         return switch (value) {
 874             .padding => false,
 875             .ping => true,
 876             .ack => |ack| self.processAck(kind, ack, now_ns),
 877             .crypto => |crypto_frame| self.processCrypto(kind, crypto_frame, now_ns),
 878             .handshake_done => self.processHandshakeDone(kind, now_ns),
 879             .connection_close => |close_frame| self.processClose(kind, close_frame, now_ns),
 880             .stream,
 881             .reset_stream,
 882             .stop_sending,
 883             .max_data,
 884             .max_stream_data,
 885             .max_streams,
 886             .data_blocked,
 887             .stream_data_blocked,
 888             .streams_blocked,
 889             => self.processStreamFrame(kind, value, now_ns),
 890             else => {
 891                 self.fail(
 892                     quic.connection.TransportError.protocol_violation,
 893                     frameType(value),
 894                     "frame not implemented",
 895                     now_ns,
 896                 );
 897                 return null;
 898             },
 899         };
 900     }
 901 
 902     fn processAck(
 903         self: *Connection,
 904         kind: quic.connection.SpaceKind,
 905         value: quic.frame.Ack,
 906         now_ns: u64,
 907     ) ?bool {
 908         const sink = AckSink{ .connection = self, .kind = kind };
 909         const acknowledged = self.space(kind).processAck(value, sink) catch {
 910             self.fail(
 911                 quic.connection.TransportError.protocol_violation,
 912                 0x02,
 913                 "ACK for unsent packet",
 914                 now_ns,
 915             );
 916             return null;
 917         };
 918         self.sampleRoundTrip(kind, value, acknowledged, now_ns);
 919         if (kind == .handshake) self.handshake_acknowledged = true;
 920         if (acknowledged.records != 0 and self.peerCompletedAddressValidation()) self.pto_count = 0;
 921         self.detectLoss(kind, now_ns);
 922         if (kind == .application) self.keys.observeAck(value);
 923         return false;
 924     }
 925 
 926     /// Runs one detection pass over a space at the delay in force, serving as the single function
 927     /// starting loss detection so every pass uses the same delay. That delay is worked out from the
 928     /// latest and the smoothed measurement of the path. Whatever the pass removed is added to the
 929     /// connection's counters.
 930     fn detectLoss(self: *Connection, kind: quic.connection.SpaceKind, now_ns: u64) void {
 931         const delay_ns = quic.connection.recovery.lossDelayNs(
 932             self.rtt.latest_ns,
 933             self.rtt.smoothed_ns,
 934         );
 935         const sink = LossSink{ .connection = self, .kind = kind };
 936         const lost = self.space(kind).detectLost(now_ns, delay_ns, sink);
 937         self.stats_value.bytes_lost +|= lost.bytes;
 938     }
 939 
 940     /// Arms the one recovery deadline the connection reports, deciding which single deadline
 941     /// `nextTimeout` will report for recovery. While any space is waiting on the time rule, that
 942     /// wait governs and no probe is armed at all. With packets outstanding the function arms the
 943     /// soonest probe, unless an unvalidated server could not afford to send it. With nothing
 944     /// outstanding the function arms a client's anti-deadlock probe. A connection that has left
 945     /// handshaking or established arms nothing.
 946     fn armProbeTimeout(self: *Connection, now_ns: u64) void {
 947         self.pto_deadline_ns = null;
 948         if (!isOpen(self.status_value)) {
 949             self.pto_anchor_ns = null;
 950             return;
 951         }
 952         for (&self.spaces) |*space_value| {
 953             if (space_value.loss_deadline_ns == null) continue;
 954             self.pto_anchor_ns = null;
 955             return;
 956         }
 957         if (self.bytesInFlight() != 0) {
 958             self.pto_anchor_ns = null;
 959             const probe = self.armedProbe() orelse return;
 960             if (self.amplificationBlocks(probe.kind)) return;
 961             self.pto_deadline_ns = probe.deadline_ns;
 962             self.pto_space = probe.kind;
 963             return;
 964         }
 965         self.armDeadlockProbe(now_ns);
 966     }
 967 
 968     /// Arms the anti-deadlock probe from the anchor, keeping a client sending while it waits for a
 969     /// server flight that never came. A client keeps it armed with nothing outstanding until a
 970     /// Handshake acknowledgment, or a confirmed handshake, gives the peer its proof of the address.
 971     /// It points at the Handshake space if Handshake keys exist, and at the Initial space if
 972     /// Handshake keys are absent. With no write keys in the space it picked, the function leaves
 973     /// the timer disarmed and empties the anchor.
 974     fn armDeadlockProbe(self: *Connection, now_ns: u64) void {
 975         std.debug.assert(self.bytesInFlight() == 0);
 976         if (self.peerCompletedAddressValidation()) {
 977             self.pto_anchor_ns = null;
 978             return;
 979         }
 980         const kind: quic.connection.SpaceKind =
 981             if (self.keys.write(.handshake) != null) .handshake else .initial;
 982         if (self.keys.write(kind) == null) {
 983             self.pto_anchor_ns = null;
 984             return;
 985         }
 986         const anchor_ns = self.pto_anchor_ns orelse now_ns;
 987         self.pto_anchor_ns = anchor_ns;
 988         self.pto_space = kind;
 989         self.pto_deadline_ns = quic.connection.recovery.probeDeadlineNs(
 990             anchor_ns,
 991             self.probePeriodNs(kind),
 992         );
 993     }
 994 
 995     /// Picks the soonest probe deadline among the spaces holding packets the peer has yet to
 996     /// settle, selecting the single winning probe timer among the three spaces. Each space measures
 997     /// its deadline from the last packet it sent that the peer owes an answer to. The application
 998     /// space is left out until the handshake is confirmed. With all spaces settled, the function
 999     /// returns null.
1000     fn armedProbe(self: *const Connection) ?Probe {
1001         var earliest: ?Probe = null;
1002         for ([_]quic.connection.SpaceKind{ .initial, .handshake, .application }) |kind| {
1003             const space_value = &self.spaces[spaceIndex(kind)];
1004             if (space_value.bytesInFlight() == 0) continue;
1005             if (kind == .application and !self.handshake_confirmed) break;
1006             const sent_ns = space_value.last_ack_eliciting_sent_ns orelse continue;
1007             const deadline_ns = quic.connection.recovery.probeDeadlineNs(
1008                 sent_ns,
1009                 self.probePeriodNs(kind),
1010             );
1011             if (earliest) |current| {
1012                 if (deadline_ns >= current.deadline_ns) continue;
1013             }
1014             earliest = .{ .deadline_ns = deadline_ns, .kind = kind };
1015         }
1016         return earliest;
1017     }
1018 
1019     /// Works out how long one space waits for an answer, at the doubling now in force, defining the
1020     /// period added to a send time for every probe deadline. The wait rests on the connection's
1021     /// smoothed measurement and its spread.
1022     fn probePeriodNs(self: *const Connection, kind: quic.connection.SpaceKind) u64 {
1023         const delay_ns = self.probeAckDelayNs(kind);
1024         return quic.connection.recovery.probePeriodNs(
1025             self.rtt.smoothed_ns,
1026             self.rtt.variation_ns,
1027             delay_ns,
1028             self.pto_count,
1029         );
1030     }
1031 
1032     /// Reads the peer's `max_ack_delay` parameter into nanoseconds, for the application space and
1033     /// only past handshake confirmation, isolating the rule that adds the peer's delay only in one
1034     /// space and only after one point. It yields zero for the other two spaces, ahead of that
1035     /// confirmation, and before the peer's parameters have arrived.
1036     fn probeAckDelayNs(self: *const Connection, kind: quic.connection.SpaceKind) u64 {
1037         if (kind != .application) return 0;
1038         if (!self.handshake_confirmed) return 0;
1039         const parameters = self.peer_parameters orelse return 0;
1040         return maxAckDelayNs(parameters.max_ack_delay);
1041     }
1042 
1043     /// Says whether the peer has proof of this endpoint's address, deciding both whether the
1044     /// anti-deadlock probe stays armed and whether an acknowledgment resets the backoff. A server
1045     /// always has it, because a client proves the server's address by finishing the handshake with
1046     /// it. A client has it once a Handshake acknowledgment arrives, or once the handshake is
1047     /// confirmed.
1048     fn peerCompletedAddressValidation(self: *const Connection) bool {
1049         if (self.config.role == .server) return true;
1050         return self.handshake_acknowledged or self.handshake_confirmed;
1051     }
1052 
1053     /// Says whether an unvalidated server is short of the budget one probe in the space would cost,
1054     /// so the timer asks before arming a probe that would spin. That budget is three times what the
1055     /// client has sent this server, less what the server has sent back. The timer then waits on the
1056     /// client's next datagram to lift the budget. A client, and a server whose peer is validated,
1057     /// are never short.
1058     fn amplificationBlocks(self: *const Connection, kind: quic.connection.SpaceKind) bool {
1059         if (self.config.role != .server) return false;
1060         if (self.client_address_validated) return false;
1061         return self.remainingAmplificationBudget() < sendRoomMin(kind);
1062     }
1063 
1064     /// Owes the armed space its probe packets once the deadline has passed, turning an expired
1065     /// deadline into packets the next `send` call emits. One packet is owed when nothing is
1066     /// outstanding, and two otherwise. It then lifts the doubling count, empties the anchor the
1067     /// anti-deadlock probe measured from, adds one to the timeout counter, and arms the timer
1068     /// afresh. `send` puts the owed packets out, forcing a PING into each.
1069     fn expireProbeTimeout(self: *Connection, now_ns: u64) void {
1070         std.debug.assert(isOpen(self.status_value));
1071         const deadline = self.pto_deadline_ns orelse return;
1072         if (now_ns < deadline) return;
1073         const kind = self.pto_space;
1074         const owed: u8 = if (self.bytesInFlight() == 0)
1075             1
1076         else
1077             quic.connection.recovery.probe_packets;
1078         self.probe_packets[spaceIndex(kind)] = owed;
1079         self.pto_count +|= 1;
1080         self.pto_anchor_ns = null;
1081         increment(&self.stats_value.probe_timeouts);
1082         self.armProbeTimeout(now_ns);
1083     }
1084 
1085     /// Runs a detection pass over every space whose wait has run out, providing the path through
1086     /// which a caller calling back at the reported deadline reaches the loss pass. `receive`,
1087     /// `send`, and `close` all arrive here by way of `advanceTime`.
1088     fn detectExpiredLoss(self: *Connection, now_ns: u64) void {
1089         std.debug.assert(isOpen(self.status_value));
1090         for ([_]quic.connection.SpaceKind{ .initial, .handshake, .application }) |kind| {
1091             const deadline = self.space(kind).loss_deadline_ns orelse continue;
1092             if (now_ns < deadline) continue;
1093             self.detectLoss(kind, now_ns);
1094         }
1095     }
1096 
1097     /// Measures the path from one ACK frame as the single source feeding the round-trip estimate,
1098     /// enforcing two conditions that determine whether an acknowledgment contributes a sample. A
1099     /// measurement wants the ACK frame's largest number to be one this ACK settled first. It also
1100     /// wants at least one packet the peer owed an answer to among what this ACK settled. What it
1101     /// measures is the time since that packet went out, less the delay the peer reported.
1102     fn sampleRoundTrip(
1103         self: *Connection,
1104         kind: quic.connection.SpaceKind,
1105         value: quic.frame.Ack,
1106         acknowledged: quic.connection.Acknowledged,
1107         now_ns: u64,
1108     ) void {
1109         if (!acknowledged.ack_eliciting) return;
1110         const sent_ns = acknowledged.largest_sent_ns orelse return;
1111         const latest_ns = quic.connection.recovery.sample(sent_ns, now_ns) orelse return;
1112         self.rtt.update(latest_ns, self.peerAckDelayNs(kind, value));
1113     }
1114 
1115     /// Works out how much of the gap one ACK's sender says it spent before answering, centralizing
1116     /// the rule that counts delay only in one space and caps it only after one point. Initial and
1117     /// Handshake acknowledgments omit this delay figure. The peer's `max_ack_delay` holds that
1118     /// figure down once the handshake is confirmed. The figure is zero until the peer's parameters
1119     /// have arrived.
1120     fn peerAckDelayNs(
1121         self: *const Connection,
1122         kind: quic.connection.SpaceKind,
1123         value: quic.frame.Ack,
1124     ) u64 {
1125         const parameters = self.peer_parameters orelse return 0;
1126         const maximum_ns: ?u64 = if (self.handshake_confirmed)
1127             maxAckDelayNs(parameters.max_ack_delay)
1128         else
1129             null;
1130         return quic.connection.recovery.reportedDelayNs(
1131             kind == .application,
1132             value.delay,
1133             parameters.ack_delay_exponent,
1134             maximum_ns,
1135         );
1136     }
1137 
1138     /// Applies one stream or flow control frame as the entry point where these frames enter the
1139     /// connection, which only a 1-RTT packet may carry. The same frame inside an Initial or
1140     /// Handshake packet ends the connection with PROTOCOL_VIOLATION. Answering with null leaves the
1141     /// packet unacknowledged. An arriving STOP_SENDING resets the sending half, a MAX_STREAM_DATA
1142     /// lifts the stream's allowance, and a MAX_DATA lifts the connection's. An arriving MAX_STREAMS
1143     /// lifts how many bidirectional streams the peer allows.
1144     fn processStreamFrame(
1145         self: *Connection,
1146         kind: quic.connection.SpaceKind,
1147         value: quic.frame.Frame,
1148         now_ns: u64,
1149     ) ?bool {
1150         std.debug.assert(isOpen(self.status_value));
1151         if (kind != .application) {
1152             self.fail(
1153                 quic.connection.TransportError.protocol_violation,
1154                 frameType(value),
1155                 "stream frame outside 1-RTT",
1156                 now_ns,
1157             );
1158             return null;
1159         }
1160         const received = &self.stats_value.stream_received;
1161         switch (value) {
1162             .stream => |data| return self.processStreamData(data, now_ns),
1163             .reset_stream => |reset| return self.processResetStream(reset, now_ns),
1164             .stop_sending => |stop| {
1165                 if (!self.admitStream(stop.stream_id, 0x05, now_ns)) return null;
1166                 increment(&received.stop_sending);
1167                 _ = self.stream_send.reset(stop.error_code);
1168             },
1169             .max_stream_data => |limit| {
1170                 if (!self.admitStream(limit.stream_id, 0x11, now_ns)) return null;
1171                 increment(&received.max_stream_data);
1172                 self.stream_send.credit.raise(limit.maximum);
1173             },
1174             .stream_data_blocked => |limit| {
1175                 if (!self.admitStream(limit.stream_id, 0x15, now_ns)) return null;
1176                 increment(&received.stream_data_blocked);
1177             },
1178             .max_data => |maximum| {
1179                 increment(&received.max_data);
1180                 self.connection_credit.raise(maximum);
1181             },
1182             .data_blocked => increment(&received.data_blocked),
1183             .max_streams => |limit| {
1184                 increment(&received.max_streams);
1185                 if (!limit.unidirectional) {
1186                     self.peer_streams_bidi = @max(self.peer_streams_bidi, limit.maximum);
1187                 }
1188             },
1189             .streams_blocked => increment(&received.streams_blocked),
1190             else => unreachable,
1191         }
1192         return true;
1193     }
1194 
1195     /// Puts one STREAM frame's data in order on the receiving half, delivering arriving STREAM data
1196     /// to the receiving part of stream 0. With the reassembly table full, the packet goes
1197     /// unacknowledged and the `stream_ranges` counter climbs. Data past a window ends the
1198     /// connection with FLOW_CONTROL_ERROR, and a final size at odds with one already settled ends
1199     /// it with FINAL_SIZE_ERROR.
1200     fn processStreamData(self: *Connection, data: quic.frame.Stream, now_ns: u64) ?bool {
1201         const frame_type = frameType(.{ .stream = data });
1202         if (!self.admitStream(data.stream_id, frame_type, now_ns)) return null;
1203         const window = &self.connection_window;
1204         self.stream_receive.receive(window, data.offset, data.data, data.fin) catch |failure| {
1205             if (failure == error.RangesFull) {
1206                 increment(&self.stats_value.drops.stream_ranges);
1207                 return null;
1208             }
1209             const code = if (failure == error.FlowControl)
1210                 quic.connection.TransportError.flow_control_error
1211             else
1212                 quic.connection.TransportError.final_size_error;
1213             self.fail(code, frame_type, "STREAM data", now_ns);
1214             return null;
1215         };
1216         const received = &self.stats_value.stream_received;
1217         increment(&received.stream_frames);
1218         received.stream_bytes +|= data.data.len;
1219         return true;
1220     }
1221 
1222     fn processResetStream(self: *Connection, reset: quic.frame.ResetStream, now_ns: u64) ?bool {
1223         if (!self.admitStream(reset.stream_id, 0x04, now_ns)) return null;
1224         const window = &self.connection_window;
1225         const code = reset.error_code;
1226         const final = reset.final_size;
1227         self.stream_receive.resetReceived(window, code, final) catch |failure| {
1228             const transport_code = if (failure == error.FlowControl)
1229                 quic.connection.TransportError.flow_control_error
1230             else
1231                 quic.connection.TransportError.final_size_error;
1232             self.fail(transport_code, 0x04, "RESET_STREAM final size", now_ns);
1233             return null;
1234         };
1235         increment(&self.stats_value.stream_received.reset_stream);
1236         return true;
1237     }
1238 
1239     /// Runs the identifier checks as every frame naming a stream passes through it, and opens
1240     /// stream 0 on a server so the server first learns stream 0 exists. A frame naming a stream
1241     /// this endpoint should have opened itself ends the connection with STREAM_STATE_ERROR, unless
1242     /// it names stream 0 and stream 0 is open. A unidirectional identifier, or one whose sequence
1243     /// reaches the advertised limit, ends the connection with STREAM_LIMIT_ERROR. The function
1244     /// answers false after ending the connection.
1245     fn admitStream(self: *Connection, stream_id: StreamId, frame_type: u62, now_ns: u64) bool {
1246         const local: quic.connection.stream.Initiator = switch (self.config.role) {
1247             .client => .client,
1248             .server => .server,
1249         };
1250         if (quic.connection.stream.initiator(stream_id) == local) {
1251             if (stream_id == 0 and self.stream_open) return true;
1252             self.fail(
1253                 quic.connection.TransportError.stream_state_error,
1254                 frame_type,
1255                 "stream not opened",
1256                 now_ns,
1257             );
1258             return false;
1259         }
1260         const limit = quic.connection.parameters.localStreamsBidi(self.config.role);
1261         const unidirectional = quic.connection.stream.direction(stream_id) == .unidirectional;
1262         if (unidirectional or quic.connection.stream.sequence(stream_id) >= limit) {
1263             self.fail(
1264                 quic.connection.TransportError.stream_limit_error,
1265                 frame_type,
1266                 "stream limit",
1267                 now_ns,
1268             );
1269             return false;
1270         }
1271         std.debug.assert(stream_id == 0);
1272         self.stream_open = true;
1273         return true;
1274     }
1275 
1276     fn processCrypto(
1277         self: *Connection,
1278         kind: quic.connection.SpaceKind,
1279         value: quic.frame.Crypto,
1280         now_ns: u64,
1281     ) ?bool {
1282         const stream = &self.crypto_streams[spaceIndex(kind)];
1283         stream.receive(value.offset, value.data) catch |failure| {
1284             const code = if (failure == error.BufferExceeded)
1285                 quic.connection.TransportError.crypto_buffer_exceeded
1286             else
1287                 quic.connection.TransportError.protocol_violation;
1288             self.fail(code, 0x06, "CRYPTO reassembly", now_ns);
1289             return null;
1290         };
1291         if (!self.driveTls(kind, now_ns)) return null;
1292         return true;
1293     }
1294 
1295     fn driveTls(self: *Connection, kind: quic.connection.SpaceKind, now_ns: u64) bool {
1296         const engine = if (self.engine) |*value| value else return false;
1297         const stream = &self.crypto_streams[spaceIndex(kind)];
1298         for (0..self.limits.crypto_buffer_bytes) |_| {
1299             const bytes = stream.contiguous();
1300             if (bytes.len == 0) break;
1301             engine.receive(kind.level(), bytes) catch {
1302                 const alert = engine.alert() orelse quic.tls.Alert.internal_error;
1303                 self.fail(@intCast(alert.quicError()), 0x06, "TLS alert", now_ns);
1304                 return false;
1305             };
1306             stream.consume(bytes.len);
1307         }
1308         self.keys.installTls(engine) catch {
1309             self.fail(quic.connection.TransportError.internal_error, 0x06, "TLS keys", now_ns);
1310             return false;
1311         };
1312         if (!self.authenticatePeer(now_ns)) return false;
1313         self.observeTlsState();
1314         return self.status_value != .closing;
1315     }
1316 
1317     fn authenticatePeer(self: *Connection, now_ns: u64) bool {
1318         if (self.peer_parameters_authenticated) return true;
1319         const engine = if (self.engine) |*value| value else return true;
1320         const peer_info = engine.peer() orelse return true;
1321         const source = self.peer_source_cid orelse return true;
1322         const parameters = quic.connection.parameters.validatePeer(
1323             self.config.role,
1324             peer_info.transport_parameters,
1325             source,
1326             self.original_dcid,
1327         ) catch {
1328             self.fail(
1329                 quic.connection.TransportError.transport_parameter_error,
1330                 null,
1331                 "transport parameters",
1332                 now_ns,
1333             );
1334             return false;
1335         };
1336         self.peer_parameters = parameters;
1337         self.connection_credit.raise(parameters.initial_max_data);
1338         const send_limit = quic.connection.parameters.streamSendLimit(
1339             self.config.role,
1340             parameters,
1341         );
1342         self.stream_send.credit.raise(send_limit);
1343         self.peer_streams_bidi = parameters.initial_max_streams_bidi;
1344         self.peer_parameters_authenticated = true;
1345         self.effective_idle_timeout_ms = quic.connection.parameters.effectiveIdle(
1346             self.config.max_idle_timeout,
1347             parameters.max_idle_timeout,
1348         );
1349         return true;
1350     }
1351 
1352     fn observeTlsState(self: *Connection) void {
1353         std.debug.assert(isOpen(self.status_value));
1354         const engine = if (self.engine) |*value| value else return;
1355         if (self.config.role != .server) return;
1356         if (engine.state() != .handshake_confirmed) return;
1357         if (self.status_value == .handshaking) {
1358             self.pending_handshake_done = true;
1359             self.status_value = .established;
1360         }
1361         self.handshake_confirmed = true;
1362         self.discardHandshakeKeys();
1363     }
1364 
1365     fn processHandshakeDone(
1366         self: *Connection,
1367         kind: quic.connection.SpaceKind,
1368         now_ns: u64,
1369     ) ?bool {
1370         std.debug.assert(isOpen(self.status_value));
1371         if (kind != .application or self.config.role != .client) {
1372             self.fail(
1373                 quic.connection.TransportError.protocol_violation,
1374                 0x1e,
1375                 "invalid HANDSHAKE_DONE",
1376                 now_ns,
1377             );
1378             return null;
1379         }
1380         const engine = if (self.engine) |*value| value else return null;
1381         engine.confirm();
1382         self.handshake_confirmed = true;
1383         self.discardHandshakeKeys();
1384         if (self.status_value == .handshaking) self.status_value = .established;
1385         self.handshake_done_received = true;
1386         increment(&self.stats_value.handshake_done_received);
1387         return true;
1388     }
1389 
1390     fn processClose(
1391         self: *Connection,
1392         kind: quic.connection.SpaceKind,
1393         value: quic.frame.ConnectionClose,
1394         now_ns: u64,
1395     ) ?bool {
1396         if (value.application and kind != .application) {
1397             self.fail(
1398                 quic.connection.TransportError.protocol_violation,
1399                 0x1d,
1400                 "application close level",
1401                 now_ns,
1402             );
1403             return null;
1404         }
1405         if (self.status_value != .closing) {
1406             self.storeReason(
1407                 value.error_code,
1408                 value.application,
1409                 value.frame_type,
1410                 value.reason,
1411                 true,
1412             );
1413         }
1414         self.close_deadline_ns = self.close_deadline_ns orelse closeDeadline(now_ns);
1415         self.status_value = .draining;
1416         self.close_pending = false;
1417         return false;
1418     }
1419 
1420     fn sendClosing(self: *Connection, out: []u8, now_ns: u64) usize {
1421         std.debug.assert(self.status_value == .closing);
1422         std.debug.assert(self.close_reason_value != null);
1423         if (!self.close_pending) return 0;
1424         const kind = self.closeSpace() orelse {
1425             self.status_value = .closed;
1426             return 0;
1427         };
1428         const limit = self.sendLimit(out.len);
1429         var length: usize = 0;
1430         if (kind == .application and self.keys.write(.handshake) != null) {
1431             length = self.sendClosePacket(.handshake, out[0..limit], now_ns);
1432         }
1433         length += self.sendClosePacket(kind, out[length..limit], now_ns);
1434         if (length == 0) return 0;
1435         std.debug.assert(length <= limit);
1436         std.debug.assert(self.close_deadline_ns != null);
1437         self.close_pending = false;
1438         self.advanceCloseResponseLimit();
1439         self.recordDatagramSent(length);
1440         return length;
1441     }
1442 
1443     fn sendClosePacket(
1444         self: *Connection,
1445         kind: quic.connection.SpaceKind,
1446         out: []u8,
1447         now_ns: u64,
1448     ) usize {
1449         std.debug.assert(out.len <= self.limits.datagram_bytes);
1450         std.debug.assert(self.keys.write(kind) != null);
1451         const packet_limit: usize = if (kind == .initial) 1200 else out.len;
1452         if (out.len < packet_limit) return 0;
1453         const plan = self.planPacket(kind, packet_limit, now_ns) orelse return 0;
1454         var output = quic.cursor.Write.init(self.storage.packet[0..plan.payload_capacity]);
1455         const reason = self.close_reason_value.?;
1456         const application = reason.application and kind == .application;
1457         const converted = reason.application and !application;
1458         quic.frame.encode(.{ .connection_close = .{
1459             .application = application,
1460             .error_code = if (converted)
1461                 quic.connection.TransportError.application_error
1462             else
1463                 reason.error_code,
1464             .frame_type = if (application) null else reason.frame_type orelse 0,
1465             .reason = if (converted) &.{} else reason.reason,
1466         } }, &output) catch return 0;
1467         const payload = Payload{
1468             .bytes = output.written(),
1469             .summary = .{ .connection_close = true },
1470             .ack_eliciting = false,
1471             .sent_ack = false,
1472             .sent_ping = false,
1473             .sent_handshake_done = false,
1474             .sent_close = true,
1475         };
1476         const minimum: u16 = if (kind == .initial) 1200 else 0;
1477         const count = self.assemblePayload(kind, plan.number, payload, minimum, out, now_ns);
1478         std.debug.assert(count <= out.len);
1479         return count;
1480     }
1481 
1482     fn sendSpace(
1483         self: *Connection,
1484         kind: quic.connection.SpaceKind,
1485         out: []u8,
1486         available: usize,
1487         minimum_bytes: u16,
1488         force_ping: bool,
1489         now_ns: u64,
1490     ) usize {
1491         std.debug.assert(available <= out.len);
1492         std.debug.assert(available <= self.limits.datagram_bytes);
1493         if (available < sendRoomMin(kind)) return 0;
1494         if (self.keys.write(kind) == null) return 0;
1495         const payload_limit = if (kind == .initial and minimum_bytes != 0)
1496             @min(available, @as(usize, minimum_bytes))
1497         else
1498             available;
1499         const plan = self.planPacket(kind, payload_limit, now_ns) orelse return 0;
1500         const payload = self.buildPayload(
1501             kind,
1502             plan.payload_capacity,
1503             force_ping,
1504             now_ns,
1505         ) catch {
1506             self.fail(
1507                 quic.connection.TransportError.internal_error,
1508                 null,
1509                 "packet assembly",
1510                 now_ns,
1511             );
1512             return 0;
1513         } orelse return 0;
1514         return self.assemblePayload(kind, plan.number, payload, minimum_bytes, out, now_ns);
1515     }
1516 
1517     fn buildPayload(
1518         self: *Connection,
1519         kind: quic.connection.SpaceKind,
1520         available: usize,
1521         force_ping: bool,
1522         now_ns: u64,
1523     ) PayloadError!?Payload {
1524         std.debug.assert(available <= self.storage.packet.len);
1525         var output = quic.cursor.Write.init(self.storage.packet[0..available]);
1526         var payload = Payload{
1527             .bytes = &.{},
1528             .summary = .{},
1529             .ack_eliciting = false,
1530             .sent_ack = false,
1531             .sent_ping = false,
1532             .sent_handshake_done = false,
1533             .sent_close = false,
1534         };
1535         const space_value = self.space(kind);
1536         const record_room = space_value.sent.hasCapacity();
1537         const application = kind == .application;
1538         const eliciting = force_ping or (application and self.applicationFramesPending());
1539         const send_ack = space_value.ack_pending and
1540             ((record_room and eliciting) or space_value.ackDue(now_ns));
1541         if (send_ack) payload.sent_ack = try self.emitAck(space_value, &output, now_ns);
1542         payload.summary.ack = payload.sent_ack;
1543         if (record_room) {
1544             if (application) try self.emitApplicationControl(&output, &payload);
1545             if (force_ping and !payload.ack_eliciting) try emitPing(&output, &payload);
1546             if (try self.emitCrypto(kind, &output)) |crypto_summary| {
1547                 payload.summary.crypto = crypto_summary;
1548                 payload.ack_eliciting = true;
1549             }
1550             if (application) try self.emitStreamFrames(&output, &payload);
1551         }
1552         if (output.index == 0) return null;
1553         payload.bytes = output.written();
1554         return payload;
1555     }
1556 
1557     fn emitAck(
1558         self: *Connection,
1559         space_value: *quic.connection.Space,
1560         output: *quic.cursor.Write,
1561         now_ns: u64,
1562     ) PayloadError!bool {
1563         const start = output.index;
1564         const delay = space_value.ackDelay(now_ns, self.config.ack_delay_exponent);
1565         space_value.received.encode(delay, output) catch |failure| switch (failure) {
1566             error.NoSpace => {
1567                 output.index = start;
1568                 return false;
1569             },
1570             else => |other| return other,
1571         };
1572         return true;
1573     }
1574 
1575     fn emitApplicationControl(
1576         self: *Connection,
1577         output: *quic.cursor.Write,
1578         payload: *Payload,
1579     ) PayloadError!void {
1580         if (self.pending_handshake_done) {
1581             if (try encodeDeferred(output, .{ .handshake_done = {} })) {
1582                 payload.summary.handshake_done = true;
1583                 payload.sent_handshake_done = true;
1584                 payload.ack_eliciting = true;
1585             }
1586         }
1587         if (self.pending_ping) try emitPing(output, payload);
1588     }
1589 
1590     /// Packs the flow control frames first, and a single STREAM frame for stream 0 after them, into
1591     /// whatever room the packet has left, constructing the stream half of one 1-RTT payload. The
1592     /// function packs the stream frames once stream 0 is open. A packet that took any of them
1593     /// obliges the peer to answer.
1594     fn emitStreamFrames(
1595         self: *Connection,
1596         output: *quic.cursor.Write,
1597         payload: *Payload,
1598     ) PayloadError!void {
1599         const start = output.index;
1600         try self.emitConnectionFlow(output, &payload.summary);
1601         if (self.stream_open) {
1602             try self.emitStreamControl(output, &payload.summary);
1603             try self.emitStream(output, &payload.summary);
1604         }
1605         if (output.index > start) payload.ack_eliciting = true;
1606     }
1607 
1608     fn emitConnectionFlow(
1609         self: *Connection,
1610         output: *quic.cursor.Write,
1611         summary: *quic.connection.FrameSummary,
1612     ) PayloadError!void {
1613         if (self.connection_window.update()) |limit| {
1614             if (try encodeDeferred(output, .{ .max_data = limit })) {
1615                 summary.max_data = limit;
1616             }
1617         }
1618         if (self.connectionBlocked()) |limit| {
1619             if (try encodeDeferred(output, .{ .data_blocked = limit })) {
1620                 summary.data_blocked = limit;
1621             }
1622         }
1623         if (self.streams_blocked_pending) {
1624             const limit = quic.frame.StreamLimit{
1625                 .unidirectional = false,
1626                 .maximum = self.peer_streams_bidi,
1627             };
1628             if (try encodeDeferred(output, .{ .streams_blocked = limit })) {
1629                 summary.streams_blocked = limit;
1630             }
1631         }
1632     }
1633 
1634     fn emitStreamControl(
1635         self: *Connection,
1636         output: *quic.cursor.Write,
1637         summary: *quic.connection.FrameSummary,
1638     ) PayloadError!void {
1639         std.debug.assert(self.stream_open);
1640         if (self.stream_send.resetFrame(0)) |reset| {
1641             if (try encodeDeferred(output, .{ .reset_stream = reset })) {
1642                 summary.reset_stream = reset;
1643             }
1644         }
1645         if (self.stream_receive.stop_pending) {
1646             const code = self.stream_receive.stop_code.?;
1647             const stop = quic.frame.StopSending{ .stream_id = 0, .error_code = code };
1648             if (try encodeDeferred(output, .{ .stop_sending = stop })) {
1649                 summary.stop_sending = stop;
1650             }
1651         }
1652         if (self.stream_receive.windowUpdate()) |maximum| {
1653             const limit = quic.frame.StreamData{ .stream_id = 0, .maximum = maximum };
1654             if (try encodeDeferred(output, .{ .max_stream_data = limit })) {
1655                 summary.max_stream_data = limit;
1656             }
1657         }
1658         if (self.stream_send.blocked()) |maximum| {
1659             const limit = quic.frame.StreamData{ .stream_id = 0, .maximum = maximum };
1660             if (try encodeDeferred(output, .{ .stream_data_blocked = limit })) {
1661                 summary.stream_data_blocked = limit;
1662             }
1663         }
1664     }
1665 
1666     /// Packs a single STREAM frame for stream 0, last of all, sizing the frame to whatever room is
1667     /// left. Bytes going a second time travel ahead of fresh ones, since the pick starts at the
1668     /// sending half's next offset. The length field goes in when padding follows, which occurs when
1669     /// the frame would otherwise end short of a full header protection sample. The FIN travels on
1670     /// the last byte. A frame too large for the room left keeps its bytes back, for some later
1671     /// packet to carry.
1672     fn emitStream(
1673         self: *Connection,
1674         output: *quic.cursor.Write,
1675         summary: *quic.connection.FrameSummary,
1676     ) PayloadError!void {
1677         std.debug.assert(self.stream_open);
1678         const send_part = &self.stream_send;
1679         const credit = self.connection_credit.available();
1680         const offset = send_part.nextOffset();
1681         const remaining = output.remaining();
1682         const plain_max = frameDataCapacity(0, offset, remaining, false) orelse return;
1683         const plain = send_part.nextChunk(plain_max, credit) orelse return;
1684         std.debug.assert(plain.offset == offset);
1685         const plain_header = frameHeaderBytes(0, offset, plain.data.len, false);
1686         const plain_end = output.index + plain_header + plain.data.len;
1687         const length_present = plain_end < quic.connection.assemble.sampled_bytes_min;
1688         var chunk = plain;
1689         if (length_present) {
1690             const framed_max = frameDataCapacity(0, offset, remaining, true) orelse return;
1691             chunk = send_part.nextChunk(framed_max, credit) orelse return;
1692         }
1693         const value = quic.connection.stream.frame(0, chunk, length_present);
1694         if (!try encodeDeferred(output, value)) return;
1695         summary.stream = .{
1696             .stream_id = 0,
1697             .offset = chunk.offset,
1698             .length = @intCast(chunk.data.len),
1699             .fin = chunk.fin,
1700         };
1701     }
1702 
1703     /// Packs one CRYPTO frame for the space so handshake bytes reach a packet. Handshake bytes
1704     /// waiting in that space go first, and TLS is asked for nothing new. Otherwise fresh TLS bytes
1705     /// move the send offset on. TLS has no way to take bytes back, so fresh bytes that will not fit
1706     /// the packet join the ones waiting.
1707     fn emitCrypto(
1708         self: *Connection,
1709         kind: quic.connection.SpaceKind,
1710         output: *quic.cursor.Write,
1711     ) PayloadError!?quic.connection.CryptoSummary {
1712         std.debug.assert(output.remaining() <= self.limits.datagram_bytes);
1713         const engine = if (self.engine) |*value| value else return null;
1714         const index = spaceIndex(kind);
1715         std.debug.assert(engine.emitted(kind.level()).len == self.crypto_send_offsets[index]);
1716         if (!self.crypto_lost[index].isEmpty()) return self.emitLostCrypto(kind, output);
1717         const offset = self.crypto_send_offsets[index];
1718         const maximum = cryptoDataCapacity(offset, output.remaining(), self.storage.scratch.len);
1719         if (maximum == 0) return null;
1720         const count = engine.emit(kind.level(), self.storage.scratch[0..maximum]);
1721         std.debug.assert(count <= maximum);
1722         if (count == 0) return null;
1723         self.crypto_send_offsets[index] += @intCast(count);
1724         const data = self.storage.scratch[0..count];
1725         if (!try encodeDeferred(output, .{ .crypto = .{ .offset = offset, .data = data } })) {
1726             self.crypto_lost[index].add(offset, @intCast(count));
1727             return null;
1728         }
1729         return .{ .offset = offset, .length = @intCast(count) };
1730     }
1731 
1732     /// Packs one CRYPTO frame from the first waiting offset, carrying as many waiting bytes as fit,
1733     /// to rebuild a lost handshake frame from bytes TLS already emitted. The bytes come back out of
1734     /// the TLS engine's own record of what it produced. The function takes the packed bytes out of
1735     /// the waiting stretch there and then. Doing so there and then is safe, because the packet is
1736     /// written down as sent immediately after packing, or the connection fails.
1737     fn emitLostCrypto(
1738         self: *Connection,
1739         kind: quic.connection.SpaceKind,
1740         output: *quic.cursor.Write,
1741     ) PayloadError!?quic.connection.CryptoSummary {
1742         const engine = if (self.engine) |*value| value else return null;
1743         const lost = &self.crypto_lost[spaceIndex(kind)];
1744         std.debug.assert(!lost.isEmpty());
1745         const flight = engine.emitted(kind.level());
1746         std.debug.assert(lost.end <= flight.len);
1747         const offset = lost.start;
1748         const room = output.remaining();
1749         const waiting: usize = @intCast(lost.length());
1750         const count = cryptoDataCapacity(offset, room, @min(waiting, room));
1751         if (count == 0) return null;
1752         const data = flight[@intCast(offset)..][0..count];
1753         const value = quic.frame.Frame{ .crypto = .{ .offset = offset, .data = data } };
1754         if (!try encodeDeferred(output, value)) return null;
1755         lost.advance(@intCast(count));
1756         return .{ .offset = offset, .length = @intCast(count) };
1757     }
1758 
1759     fn assemblePayload(
1760         self: *Connection,
1761         kind: quic.connection.SpaceKind,
1762         number: quic.connection.NumberEncoding,
1763         payload: Payload,
1764         minimum_bytes: u16,
1765         out: []u8,
1766         now_ns: u64,
1767     ) usize {
1768         std.debug.assert(out.len <= self.limits.datagram_bytes);
1769         std.debug.assert(payload.bytes.len <= self.limits.datagram_bytes);
1770         const space_value = self.space(kind);
1771         if (payload.ack_eliciting) std.debug.assert(space_value.sent.hasCapacity());
1772         const write_keys = self.keys.write(kind) orelse {
1773             self.fail(quic.connection.TransportError.internal_error, null, "write keys", now_ns);
1774             return 0;
1775         };
1776         const destination_cid = self.peer_cid orelse {
1777             self.fail(quic.connection.TransportError.internal_error, null, "peer CID", now_ns);
1778             return 0;
1779         };
1780         const packet_type: quic.connection.assemble.PacketType = switch (kind) {
1781             .initial => .initial,
1782             .handshake => .handshake,
1783             .application => .one_rtt,
1784         };
1785         const built = quic.connection.assemble.packet(write_keys, .{
1786             .packet_type = packet_type,
1787             .destination = destination_cid,
1788             .source = self.local_cid,
1789             .number = number,
1790             .key_phase = self.keys.send_phase,
1791             .minimum_bytes = minimum_bytes,
1792         }, payload.bytes, out) catch |failure| {
1793             if (failure == error.ConfidentialityLimitReached) {
1794                 self.fail(
1795                     quic.connection.TransportError.aead_limit_reached,
1796                     null,
1797                     "AEAD confidentiality limit",
1798                     now_ns,
1799                 );
1800             } else {
1801                 self.fail(
1802                     quic.connection.TransportError.internal_error,
1803                     null,
1804                     "packet protection",
1805                     now_ns,
1806                 );
1807             }
1808             return 0;
1809         };
1810         if (!self.recordPacketSent(space_value, kind, number, payload, built, now_ns)) return 0;
1811         self.commitPayload(kind, payload, now_ns);
1812         increment(&self.stats_value.packets_sent);
1813         self.touchActivityOnSend(now_ns, payload.ack_eliciting);
1814         return built.length;
1815     }
1816 
1817     fn recordPacketSent(
1818         self: *Connection,
1819         space_value: *quic.connection.Space,
1820         kind: quic.connection.SpaceKind,
1821         number: quic.connection.NumberEncoding,
1822         payload: Payload,
1823         built: quic.connection.assemble.Built,
1824         now_ns: u64,
1825     ) bool {
1826         std.debug.assert(built.length <= self.limits.datagram_bytes);
1827         std.debug.assert(payload.bytes.len <= built.payload_length);
1828         std.debug.assert(number.packet_number == space_value.next_packet_number);
1829         if (!payload.ack_eliciting) {
1830             space_value.next_packet_number += 1;
1831             return true;
1832         }
1833         space_value.recordSent(.{
1834             .packet_number = number.packet_number,
1835             .time_sent_ns = now_ns,
1836             .ack_eliciting = true,
1837             .acknowledged = false,
1838             .lost = false,
1839             .in_flight_bytes = built.length,
1840             .key_phase = self.keys.send_phase,
1841             .key_phase_present = kind == .application,
1842             .frames = payload.summary,
1843         }) catch {
1844             self.fail(
1845                 quic.connection.TransportError.internal_error,
1846                 null,
1847                 "sent records",
1848                 now_ns,
1849             );
1850             return false;
1851         };
1852         return true;
1853     }
1854 
1855     fn planPacket(
1856         self: *Connection,
1857         kind: quic.connection.SpaceKind,
1858         packet_bytes: usize,
1859         now_ns: u64,
1860     ) ?PacketPlan {
1861         std.debug.assert(packet_bytes <= self.limits.datagram_bytes);
1862         const destination = self.peer_cid orelse {
1863             self.fail(quic.connection.TransportError.internal_error, null, "peer CID", now_ns);
1864             return null;
1865         };
1866         const number = self.space(kind).numberEncoding() catch {
1867             self.fail(quic.connection.TransportError.internal_error, null, "packet number", now_ns);
1868             return null;
1869         };
1870         const number_bytes: usize = number.bits / 8;
1871         const reserve = packetReserve(
1872             kind,
1873             packet_bytes,
1874             @intCast(number_bytes),
1875             destination.length,
1876             self.local_cid.length,
1877         );
1878         const sampled = quic.connection.assemble.sampled_bytes_min - number_bytes;
1879         if (reserve + @max(sampled, 1) > packet_bytes) return null;
1880         std.debug.assert(reserve < packet_bytes);
1881         return .{ .number = number, .payload_capacity = packet_bytes - reserve };
1882     }
1883 
1884     fn commitPayload(
1885         self: *Connection,
1886         kind: quic.connection.SpaceKind,
1887         payload: Payload,
1888         now_ns: u64,
1889     ) void {
1890         if (payload.sent_ack) {
1891             const space_value = self.space(kind);
1892             space_value.markAckSent();
1893             increment(&self.stats_value.ack_frames_sent);
1894             if (kind == .application) self.keys.observeAckSent(space_value.largest_received.?);
1895         }
1896         if (payload.ack_eliciting) {
1897             const owed = &self.probe_packets[spaceIndex(kind)];
1898             if (owed.* != 0) owed.* -= 1;
1899         }
1900         if (payload.sent_ping) self.pending_ping = false;
1901         if (payload.sent_handshake_done) {
1902             self.pending_handshake_done = false;
1903             increment(&self.stats_value.handshake_done_sent);
1904         }
1905         if (payload.sent_close) self.close_pending = false;
1906         if (kind == .application) self.commitStreamFrames(payload.summary);
1907         if (kind == .handshake and self.config.role == .client) self.discardInitialKeys();
1908         if (kind == .application and self.keys.application_write.?.confidentialityExhausted()) {
1909             self.fail(
1910                 quic.connection.TransportError.aead_limit_reached,
1911                 null,
1912                 "AEAD confidentiality limit",
1913                 now_ns,
1914             );
1915         }
1916     }
1917 
1918     fn commitStreamFrames(self: *Connection, summary: quic.connection.FrameSummary) void {
1919         const sent_stats = &self.stats_value.stream_sent;
1920         if (summary.max_data) |limit| {
1921             self.connection_window.advertise(limit);
1922             increment(&sent_stats.max_data);
1923         }
1924         if (summary.data_blocked) |limit| {
1925             self.connection_credit.markBlocked(limit);
1926             increment(&sent_stats.data_blocked);
1927         }
1928         if (summary.streams_blocked != null) {
1929             self.streams_blocked_pending = false;
1930             self.streams_blocked_sent = true;
1931             increment(&sent_stats.streams_blocked);
1932         }
1933         if (summary.reset_stream != null) {
1934             self.stream_send.commitReset();
1935             increment(&sent_stats.reset_stream);
1936         }
1937         if (summary.stop_sending != null) {
1938             self.stream_receive.stop_pending = false;
1939             increment(&sent_stats.stop_sending);
1940         }
1941         if (summary.max_stream_data) |limit| {
1942             self.stream_receive.window.advertise(limit.maximum);
1943             increment(&sent_stats.max_stream_data);
1944         }
1945         if (summary.stream_data_blocked) |limit| {
1946             self.stream_send.commitBlocked(limit.maximum);
1947             increment(&sent_stats.stream_data_blocked);
1948         }
1949         const range = summary.stream orelse return;
1950         const new_bytes = self.stream_send.commitChunk(range.offset, range.length, range.fin);
1951         self.connection_credit.consume(new_bytes);
1952         increment(&sent_stats.stream_frames);
1953         sent_stats.stream_bytes +|= range.length;
1954     }
1955 
1956     /// Decides what one lost 1-RTT packet puts back in the queue, centralizing the whole
1957     /// retransmission policy for that packet in one place. Stream 0 decides for the STREAM bytes,
1958     /// the FIN, the RESET_STREAM, and the STOP_SENDING. The two MAX frames go again, each carrying
1959     /// the figure now in force. The three BLOCKED frames go again while the sender still stands at
1960     /// the figure the lost one reported. HANDSHAKE_DONE goes again.
1961     fn loseApplicationFrames(self: *Connection, frames: quic.connection.FrameSummary) void {
1962         std.debug.assert(isOpen(self.status_value));
1963         if (frames.handshake_done) self.pending_handshake_done = true;
1964         if (frames.max_data) |limit| self.connection_window.loseLimit(limit);
1965         if (frames.data_blocked) |limit| self.connection_credit.loseBlocked(limit);
1966         if (frames.streams_blocked) |limit| self.loseStreamsBlocked(limit);
1967         const send_part = &self.stream_send;
1968         const receive_part = &self.stream_receive;
1969         if (frames.stream) |range| send_part.lose(range.offset, range.length, range.fin);
1970         if (frames.reset_stream != null) send_part.loseReset();
1971         if (frames.stop_sending != null) receive_part.loseStop();
1972         if (frames.max_stream_data) |limit| receive_part.window.loseLimit(limit.maximum);
1973         if (frames.stream_data_blocked) |limit| send_part.credit.loseBlocked(limit.maximum);
1974     }
1975 
1976     /// Puts STREAMS_BLOCKED back in the queue while stream 0 is still unopened and the peer still
1977     /// allows the same number of streams the lost frame reported, resending the blocked report
1978     /// while that condition holds.
1979     fn loseStreamsBlocked(self: *Connection, limit: quic.frame.StreamLimit) void {
1980         std.debug.assert(!limit.unidirectional);
1981         if (self.stream_open) return;
1982         if (self.peer_streams_bidi != limit.maximum) return;
1983         self.streams_blocked_pending = true;
1984     }
1985 
1986     fn validateConnectionIds(self: *Connection, view: PacketView) bool {
1987         if (self.peer_source_cid == null) {
1988             const source = view.source orelse return false;
1989             if (view.kind != .initial) return false;
1990             self.peer_source_cid = source;
1991             self.peer_cid = source;
1992         } else if (view.source) |source| {
1993             if (!sameCid(self.peer_source_cid.?, source)) return false;
1994         }
1995         if (self.config.role == .server and view.kind == .initial) {
1996             if (sameCid(view.destination, self.original_dcid.?)) return true;
1997         }
1998         return sameCid(view.destination, self.local_cid);
1999     }
2000 
2001     /// Drops the Initial keys, everything the Initial space held for recovery, and its waiting
2002     /// handshake bytes, so an abandoned space leaves no timer or record behind. A client arrives
2003     /// here as it sends each Handshake packet, and a server as it takes one in. Only the first call
2004     /// does anything, which keeps a repeat from putting the doubling count back to the start.
2005     fn discardInitialKeys(self: *Connection) void {
2006         if (self.initialKeysDiscarded()) return;
2007         self.keys.discardInitial();
2008         self.space(.initial).discard();
2009         self.crypto_lost[spaceIndex(.initial)] = .{};
2010         self.resetProbeTimeout(.initial);
2011         std.debug.assert(self.keys.write(.initial) == null);
2012         std.debug.assert(self.keys.read(.initial) == null);
2013     }
2014 
2015     /// Drops the Handshake keys, everything the Handshake space held for recovery, and its waiting
2016     /// handshake bytes, so an abandoned space leaves no timer or record behind. A client arrives
2017     /// here on each HANDSHAKE_DONE frame it takes in, and a server wherever TLS says the handshake
2018     /// stands confirmed. Only the first call does anything, which keeps a repeat from putting the
2019     /// doubling count back to the start.
2020     fn discardHandshakeKeys(self: *Connection) void {
2021         if (self.handshakeKeysDiscarded()) return;
2022         self.keys.discardHandshake();
2023         self.space(.handshake).discard();
2024         self.crypto_lost[spaceIndex(.handshake)] = .{};
2025         self.resetProbeTimeout(.handshake);
2026         std.debug.assert(self.keys.write(.handshake) == null);
2027         std.debug.assert(self.keys.read(.handshake) == null);
2028     }
2029 
2030     /// Puts the probe timeout of a space whose keys are gone back to the start, so a space that no
2031     /// longer exists stops contributing to consecutive backoff timeouts. The doubling count starts
2032     /// over, and no probe is owed to that space. The function empties the deadline and the
2033     /// anti-deadlock anchor, and every caller leaves through `send` or `receive`, which arm the
2034     /// timer afresh.
2035     fn resetProbeTimeout(self: *Connection, kind: quic.connection.SpaceKind) void {
2036         std.debug.assert(kind != .application);
2037         self.pto_count = 0;
2038         self.probe_packets[spaceIndex(kind)] = 0;
2039         self.pto_deadline_ns = null;
2040         self.pto_anchor_ns = null;
2041     }
2042 
2043     fn noteClosingDatagram(self: *Connection) void {
2044         std.debug.assert(self.status_value == .closing);
2045         std.debug.assert(self.close_response_packet_limit >= 1);
2046         self.close_packets_since_response +|= 1;
2047         if (self.close_packets_since_response >= self.close_response_packet_limit) {
2048             self.close_pending = true;
2049         }
2050     }
2051 
2052     fn advanceCloseResponseLimit(self: *Connection) void {
2053         std.debug.assert(self.status_value == .closing);
2054         std.debug.assert(self.close_response_packet_limit >= 1);
2055         self.close_packets_since_response = 0;
2056         self.close_response_packet_limit *|= 2;
2057     }
2058 
2059     fn fail(
2060         self: *Connection,
2061         error_code: u62,
2062         frame_type: ?u62,
2063         reason: []const u8,
2064         now_ns: u64,
2065     ) void {
2066         switch (self.status_value) {
2067             .handshaking, .established => {},
2068             .closing => {
2069                 std.debug.assert(self.close_deadline_ns != null);
2070                 return;
2071             },
2072             .draining, .closed => return,
2073         }
2074         std.debug.assert(self.close_deadline_ns == null);
2075         self.storeReason(error_code, false, frame_type, reason, false);
2076         self.status_value = .closing;
2077         self.close_pending = true;
2078         self.close_deadline_ns = closeDeadline(now_ns);
2079     }
2080 
2081     fn storeReason(
2082         self: *Connection,
2083         error_code: u62,
2084         application: bool,
2085         frame_type: ?u62,
2086         reason: []const u8,
2087         remote: bool,
2088     ) void {
2089         std.debug.assert(reason.len <= self.storage.reason.len);
2090         @memcpy(self.storage.reason[0..reason.len], reason);
2091         self.close_reason_value = .{
2092             .error_code = error_code,
2093             .application = application,
2094             .frame_type = frame_type,
2095             .reason = self.storage.reason[0..reason.len],
2096             .remote = remote,
2097         };
2098     }
2099 
2100     fn closeSpace(self: *Connection) ?quic.connection.SpaceKind {
2101         if (self.keys.write(.application) != null) return .application;
2102         if (self.keys.write(.handshake) != null) return .handshake;
2103         if (self.keys.write(.initial) != null) return .initial;
2104         return null;
2105     }
2106 
2107     /// Says whether an identifier names the one stream this connection has open, providing the
2108     /// single initial check for every public method that names an already-open stream. `write`,
2109     /// `finish`, `read`, `resetStream`, `stopSending`, `sendState`, `receiveState`, and
2110     /// `streamStats` all pass through it. The check asserts that the connection still holds its
2111     /// storage, so a call made after the caller took that storage back trips in a debug build.
2112     /// Identifier 0 is the one it answers true for.
2113     fn streamKnown(self: *const Connection, id: StreamId) bool {
2114         std.debug.assert(!self.deinitialized);
2115         if (id != 0) return false;
2116         return self.stream_open;
2117     }
2118 
2119     fn streamOpenForApplication(self: *const Connection, id: StreamId) bool {
2120         if (!self.streamKnown(id)) return false;
2121         return isOpen(self.status_value);
2122     }
2123 
2124     fn connectionBlocked(self: *const Connection) ?u62 {
2125         if (!self.stream_open) return null;
2126         const send_part = &self.stream_send;
2127         const waiting = send_part.reset_code == null and send_part.sent < send_part.written;
2128         return self.connection_credit.blocked(waiting);
2129     }
2130 
2131     /// Says whether any 1-RTT control, flow control, or stream frame is waiting, which lets an ACK
2132     /// travel alongside one because an ACK alone does not oblige the peer to answer. The function
2133     /// covers a waiting HANDSHAKE_DONE, PING, and STREAMS_BLOCKED, a connection window figure, and
2134     /// a connection blocked report. Once stream 0 is open, the function covers a waiting reset, a
2135     /// waiting stop, a stream window figure, a stream blocked report, and a pick ready to go.
2136     fn applicationFramesPending(self: *const Connection) bool {
2137         if (self.pending_handshake_done) return true;
2138         if (self.pending_ping) return true;
2139         if (self.streams_blocked_pending) return true;
2140         if (self.connection_window.update() != null) return true;
2141         if (!self.stream_open) return false;
2142         if (self.stream_send.reset_pending) return true;
2143         if (self.stream_receive.stop_pending) return true;
2144         if (self.stream_receive.windowUpdate() != null) return true;
2145         if (self.stream_send.blocked() != null) return true;
2146         if (self.connectionBlocked() != null) return true;
2147         const credit = self.connection_credit.available();
2148         return self.stream_send.nextChunk(std.math.maxInt(u16), credit) != null;
2149     }
2150 
2151     fn space(self: *Connection, kind: quic.connection.SpaceKind) *quic.connection.Space {
2152         std.debug.assert(spaceIndex(kind) < self.spaces.len);
2153         return &self.spaces[spaceIndex(kind)];
2154     }
2155 
2156     fn sendLimit(self: *const Connection, out_length: usize) usize {
2157         var limit = @min(out_length, self.limits.datagram_bytes);
2158         if (self.config.role == .server and !self.client_address_validated) {
2159             limit = @min(limit, self.remainingAmplificationBudget());
2160         }
2161         return limit;
2162     }
2163 
2164     fn remainingAmplificationBudget(self: *const Connection) usize {
2165         const received = std.math.mul(u64, self.received_before_validation, 3) catch
2166             std.math.maxInt(u64);
2167         if (received <= self.sent_before_validation) return 0;
2168         return std.math.cast(usize, received - self.sent_before_validation) orelse
2169             std.math.maxInt(usize);
2170     }
2171 
2172     fn recordDatagramSent(self: *Connection, length: usize) void {
2173         increment(&self.stats_value.datagrams_sent);
2174         if (self.config.role == .server and !self.client_address_validated) {
2175             self.sent_before_validation +|= length;
2176         }
2177     }
2178 
2179     fn touchActivity(self: *Connection, now_ns: u64) void {
2180         self.timer_started = true;
2181         self.last_activity_ns = now_ns;
2182     }
2183 
2184     fn touchActivityOnSend(self: *Connection, now_ns: u64, ack_eliciting: bool) void {
2185         if (!ack_eliciting) return;
2186         self.touchActivity(now_ns);
2187     }
2188 
2189     fn idleDeadline(self: *const Connection) ?u64 {
2190         if (!self.timer_started) return null;
2191         if (self.effective_idle_timeout_ms == 0) return null;
2192         const duration = std.math.mul(
2193             u64,
2194             self.effective_idle_timeout_ms,
2195             std.time.ns_per_ms,
2196         ) catch std.math.maxInt(u64);
2197         return std.math.add(u64, self.last_activity_ns, duration) catch std.math.maxInt(u64);
2198     }
2199 
2200     fn advanceTime(self: *Connection, now_ns: u64) void {
2201         if (self.close_deadline_ns) |deadline| {
2202             if (now_ns >= deadline) {
2203                 self.status_value = .closed;
2204                 self.close_pending = false;
2205                 return;
2206             }
2207         }
2208         if (!isOpen(self.status_value)) return;
2209         self.detectExpiredLoss(now_ns);
2210         if (!isOpen(self.status_value)) return;
2211         self.expireProbeTimeout(now_ns);
2212         if (!isOpen(self.status_value)) return;
2213         const idle = self.idleDeadline() orelse return;
2214         if (now_ns < idle) return;
2215         self.storeReason(0, false, null, "idle timeout", false);
2216         self.status_value = .closed;
2217     }
2218 };
2219 
2220 fn initSpaces(storage: *quic.connection.Storage) [3]quic.connection.Space {
2221     return .{
2222         quic.connection.Space.init(.initial, storage.ranges(0), storage.records(0)),
2223         quic.connection.Space.init(.handshake, storage.ranges(1), storage.records(1)),
2224         quic.connection.Space.init(.application, storage.ranges(2), storage.records(2)),
2225     };
2226 }
2227 
2228 fn initCryptoStreams(storage: *quic.connection.Storage) [3]quic.connection.Reassembler {
2229     return .{
2230         quic.connection.Reassembler.init(storage.crypto_bytes[0], storage.crypto_present[0]),
2231         quic.connection.Reassembler.init(storage.crypto_bytes[1], storage.crypto_present[1]),
2232         quic.connection.Reassembler.init(storage.crypto_bytes[2], storage.crypto_present[2]),
2233     };
2234 }
2235 
2236 fn inspectPacket(bytes: []const u8, destination_length: u5) ViewError!PacketView {
2237     if (bytes.len == 0) return error.Malformed;
2238     if (bytes[0] & 0x80 == 0) {
2239         const short = quic.packet.decodeShort(bytes, destination_length) catch
2240             return error.Malformed;
2241         return .{
2242             .kind = .application,
2243             .length = bytes.len,
2244             .packet_number_offset = short.packet_number_offset,
2245             .destination = short.destination,
2246             .source = null,
2247         };
2248     }
2249     const decoded = quic.packet.decodeLong(bytes) catch |failure| {
2250         if (failure == error.UnsupportedVersion) return error.Unsupported;
2251         return error.Malformed;
2252     };
2253     const metadata: LongMetadata = switch (decoded) {
2254         .initial => |value| .{
2255             .kind = .initial,
2256             .length = value.length,
2257             .offset = value.packet_number_offset,
2258             .destination = value.common.destination,
2259             .source = value.common.source,
2260         },
2261         .handshake => |value| .{
2262             .kind = .handshake,
2263             .length = value.length,
2264             .offset = value.packet_number_offset,
2265             .destination = value.common.destination,
2266             .source = value.common.source,
2267         },
2268         else => return error.Unsupported,
2269     };
2270     const length = std.math.cast(usize, metadata.length) orelse return error.Malformed;
2271     if (metadata.offset > bytes.len) return error.Malformed;
2272     if (length > bytes.len - metadata.offset) return error.Malformed;
2273     return .{
2274         .kind = metadata.kind,
2275         .length = metadata.offset + length,
2276         .packet_number_offset = metadata.offset,
2277         .destination = metadata.destination,
2278         .source = metadata.source,
2279     };
2280 }
2281 
2282 /// Writes one frame, or puts the cursor back to the position where it stood and answers false when
2283 /// the frame will not fit, leaving the packet exactly as it was during frame-by-frame packing. The
2284 /// frame then travels in a later packet, since the state that produced it is left alone.
2285 fn encodeDeferred(output: *quic.cursor.Write, value: quic.frame.Frame) PayloadError!bool {
2286     const start = output.index;
2287     quic.frame.encode(value, output) catch |failure| switch (failure) {
2288         error.NoSpace => {
2289             output.index = start;
2290             return false;
2291         },
2292         else => |other| return other,
2293     };
2294     return true;
2295 }
2296 
2297 fn emitPing(output: *quic.cursor.Write, payload: *Payload) PayloadError!void {
2298     const written = try encodeDeferred(output, .{ .ping = {} });
2299     if (!written) return;
2300     payload.summary.ping = true;
2301     payload.sent_ping = true;
2302     payload.ack_eliciting = true;
2303 }
2304 
2305 /// Gives the frame type number that a close reason reports, providing the exact code for a
2306 /// CONNECTION_CLOSE frame. A STREAM frame's number carries its OFF, LEN, and FIN bits, and the
2307 /// numbers for ACK, MAX_STREAMS, and STREAMS_BLOCKED each turn on which variant it is.
2308 fn frameType(value: quic.frame.Frame) u62 {
2309     return switch (value) {
2310         .padding => 0x00,
2311         .ping => 0x01,
2312         .ack => |ack| if (ack.ecn == null) 0x02 else 0x03,
2313         .reset_stream => 0x04,
2314         .stop_sending => 0x05,
2315         .crypto => 0x06,
2316         .new_token => 0x07,
2317         .stream => |data| streamFrameType(data),
2318         .max_data => 0x10,
2319         .max_stream_data => 0x11,
2320         .max_streams => |limit| if (limit.unidirectional) 0x13 else 0x12,
2321         .data_blocked => 0x14,
2322         .stream_data_blocked => 0x15,
2323         .streams_blocked => |limit| if (limit.unidirectional) 0x17 else 0x16,
2324         .new_connection_id => 0x18,
2325         .retire_connection_id => 0x19,
2326         .path_challenge => 0x1a,
2327         .path_response => 0x1b,
2328         .connection_close => |close_frame| if (close_frame.application) 0x1d else 0x1c,
2329         .handshake_done => 0x1e,
2330         .datagram => |datagram| if (datagram.length_present) 0x31 else 0x30,
2331     };
2332 }
2333 
2334 fn streamFrameType(data: quic.frame.Stream) u62 {
2335     var value: u62 = 0x08;
2336     if (data.offset_present) value |= 0x04;
2337     if (data.length_present) value |= 0x02;
2338     if (data.fin) value |= 0x01;
2339     return value;
2340 }
2341 
2342 fn preferredCipherSuite(suite: quic.crypto.Suite) std.crypto.tls.CipherSuite {
2343     return switch (suite) {
2344         .aes_128_gcm_sha256 => .AES_128_GCM_SHA256,
2345         .chacha20_poly1305_sha256 => .CHACHA20_POLY1305_SHA256,
2346     };
2347 }
2348 
2349 /// Gives the least room the send path wants before it will plan a packet in the space, so a
2350 /// datagram too small to carry one is left alone. A datagram carrying an Initial packet wants 1200
2351 /// bytes, and anything else wants 64.
2352 fn sendRoomMin(kind: quic.connection.SpaceKind) usize {
2353     return if (kind == .initial) 1200 else 64;
2354 }
2355 
2356 fn packetMinimum(
2357     kind: quic.connection.SpaceKind,
2358     available: usize,
2359     carries_initial: bool,
2360     can_coalesce_handshake: bool,
2361 ) u16 {
2362     std.debug.assert(available <= std.math.maxInt(u16));
2363     if (kind == .initial) {
2364         if (can_coalesce_handshake and available >= 1200) return 256;
2365         return 1200;
2366     }
2367     if (kind == .handshake and carries_initial) return @intCast(available);
2368     return 0;
2369 }
2370 
2371 fn packetReserve(
2372     kind: quic.connection.SpaceKind,
2373     packet_bytes: usize,
2374     packet_number_bytes: u3,
2375     destination_bytes: u5,
2376     source_bytes: u5,
2377 ) usize {
2378     std.debug.assert(packet_bytes <= quic.crypto.packet.packet_bytes_max);
2379     std.debug.assert(packet_number_bytes >= 1);
2380     std.debug.assert(packet_number_bytes <= 4);
2381     const length_bytes: usize = quic.varint.encodedLength(@intCast(packet_bytes));
2382     const destination: usize = destination_bytes;
2383     const source: usize = source_bytes;
2384     const header_bytes: usize = switch (kind) {
2385         .initial => 1 + 4 + 1 + destination + 1 + source + 1 + length_bytes,
2386         .handshake => 1 + 4 + 1 + destination + 1 + source + length_bytes,
2387         .application => 1 + destination,
2388     };
2389     return header_bytes + packet_number_bytes + quic.crypto.packet.tag_bytes;
2390 }
2391 
2392 fn closeReasonCapacity() usize {
2393     const cid_bytes = quic.packet.connection_id_bytes_max;
2394     const frame_bytes: usize = 1 + 8 + 8 + @as(usize, quic.varint.encodedLength(1200));
2395     const initial = packetReserve(.initial, 1200, 4, cid_bytes, cid_bytes) + frame_bytes;
2396     const handshake = packetReserve(.handshake, 1200, 4, cid_bytes, cid_bytes) + frame_bytes;
2397     const application = packetReserve(.application, 1200, 4, cid_bytes, cid_bytes) + frame_bytes;
2398     return @min(1200 - initial, (1200 - handshake - application) / 2);
2399 }
2400 
2401 fn closeDeadline(now_ns: u64) u64 {
2402     return std.math.add(u64, now_ns, closing_period_ns) catch std.math.maxInt(u64);
2403 }
2404 
2405 fn isOpen(status: quic.connection.Status) bool {
2406     return status == .handshaking or status == .established;
2407 }
2408 
2409 fn cryptoDataCapacity(offset: u62, available: usize, storage_bytes: usize) usize {
2410     std.debug.assert(available <= quic.crypto.packet.packet_bytes_max);
2411     std.debug.assert(storage_bytes <= std.math.maxInt(u20));
2412     const fixed = 1 + @as(usize, quic.varint.encodedLength(offset));
2413     if (available <= fixed) return 0;
2414     var data_bytes = @min(storage_bytes, available - fixed);
2415     for (0..4) |_| {
2416         const length_bytes: usize = quic.varint.encodedLength(@intCast(data_bytes));
2417         const header_bytes = fixed + length_bytes;
2418         if (header_bytes > available) return 0;
2419         if (data_bytes <= available - header_bytes) return data_bytes;
2420         data_bytes = @min(storage_bytes, available - header_bytes);
2421     }
2422     return 0;
2423 }
2424 
2425 fn sameCid(left: quic.packet.ConnectionId, right: quic.packet.ConnectionId) bool {
2426     return std.mem.eql(u8, left.slice(), right.slice());
2427 }
2428 
2429 fn spaceIndex(kind: quic.connection.SpaceKind) usize {
2430     return @backingInt(kind);
2431 }
2432 
2433 fn maxAckDelayNs(delay_ms: u14) u64 {
2434     return @as(u64, delay_ms) * std.time.ns_per_ms;
2435 }
2436 
2437 fn earlier(current: ?u64, candidate: u64) u64 {
2438     return if (current) |value| @min(value, candidate) else candidate;
2439 }
2440 
2441 fn increment(value: *u64) void {
2442     value.* +|= 1;
2443 }