tiny.quic.connection.stream
Defined in connection.
API (67)
Actions
Public operations.
Credit.available: Counts what is left to send under the allowance so the send path sizes each chunk against it.Credit.blocked: Hands back the figure a BLOCKED frame would report so the send path decides whether that frame belongs in the packet it is building.Credit.consume: Charges bytes that have gone out against the allowance so the send path records each newly sent byte here.Credit.initCredit.loseBlocked: Forgets the figure noted for the loss path so a sender still held up reports itself a second time after the report is lost.Credit.markBlocked: Notes which figure a BLOCKED frame has carried.Credit.raise: Lifts the allowance to a larger figure the peer has granted.Range.emptyReceive.initReceive.loseStop: Puts STOP_SENDING back in the queue for the loss path after its packet was lost, so the frame goes out again.Receive.read: Copies the waiting bytes in offset order for an application taking its bytes, and says whether the read reached the final size.Receive.readable: Counts the bytes waiting in order at the read offset, so the caller learns how much one read can copy.Receive.receive: Takes in one arriving STREAM frame's data for the stream, putting up with bytes that repeat or overlap what has arrived already.Receive.resetReceived: Applies one arriving RESET_STREAM frame for the stream once the final size and both windows check out.Receive.stop: Puts a STOP_SENDING frame in the queue while the peer might still send, so an application tells the peer to stop sending.Receive.windowUpdate: Offers a larger MAXSTREAMDATA figure while more data may yet arrive, so the send path can decide whether a MAXSTREAMDATA frame belongs in the packet it is building.Send.acknowledge: Frees the ring bytes one acknowledged STREAM frame covered, and trims them off whichever end of the waiting stretch they reach, so an acknowledged packet frees the send buffer.Send.acknowledgeReset: Notes the acknowledgment of the RESETSTREAM frame and carries the half into Reset Recvd, so an acknowledged RESETSTREAM ends the sending part.Send.blocked: Hands back the figure a STREAMDATABLOCKED frame would report while this stream's own credit holds the sender up, so the send path decides whether that frame belongs in the packet being built.Send.buffered: Counts what the ring is holding, measured from the oldest byte the peer has yet to acknowledge, sowriteaccepts what room remains.Send.commitBlocked: Notes that a STREAMDATABLOCKED frame went out, for the send path to call once the frame is in a sealed packet.Send.commitChunk: Takes an entry in the table for the pick that has gone out, and reports how many of its bytes had never gone before, for the packet builder to call once the packet holding the frame is sealed and charge that count to connection credit.Send.commitReset: Notes that a RESET_STREAM frame went out and carries the half into Reset Sent, for the send path to call once the frame is in a sealed packet.Send.finish: Settles the final size at the last byte the application wrote, so the application ends its side of the stream.Send.initSend.lose: Gives up the table entry a lost STREAM frame held, and puts its bytes, with a closing flag no acknowledgment has covered, in the stretch that goes ahead of fresh bytes, so lost bytes go out again ahead of new ones.Send.loseReset: Puts RESETSTREAM back in the queue after a loss, while the half sits in Reset Sent, so a lost RESETSTREAM goes out again.Send.nextChunk: Picks out up todata_maxbytes in order for the next STREAM frame, so the packet builder receives the payload for that frame.Send.nextOffset: Gives the offset the next STREAM frame will start at, so the packet builder can size the frame header against that offset before asking for a chunk.Send.pending: Says whether this half has anything for the packet being built, so the send path decides whether to request a frame.Send.reset: Gives up on the bytes waiting, sent and unsent alike, and queues RESET_STREAM so an application can abandon the stream, returning whether the reset was taken.Send.resetFrame: Hands back the RESET_STREAM frame that is waiting for a packet, so the send path can insert that frame into the packet being built.Send.write: Takes application bytes into the ring so they enter the stream, accepting as many as free room allows, and reports how many it took.SentRange.emptyWindow.advertise: Notes the figure carried by a MAXDATA frame, or by a MAXSTREAMDATA frame, that has gone out, then clears `limitlost`.Window.allows: Says whether an arrived total is still inside what this endpoint offered so the receiving part checks arriving data before accepting it, because a false answer closes the connection with FLOWCONTROLERROR.Window.initWindow.loseLimit: Marks the figure in force as lost for the loss path when the lost frame carried it, so the peer still learns a limit whose frame was lost.Window.record: Notes an arrived total for the receiving part afterallowshas accepted the data.Window.release: Notes bytes the application has taken, or bytes a reset has thrown away, so reading stream bytes earns the peer more room.Window.update: Offers a larger figure once the application has taken half a window so the send path decides whether a MAXDATA or MAXSTREAM_DATA frame belongs in the packet it is building.direction: Reads out of the identifier's second bit whether both sides may send, soadmitStreamrejects a unidirectional stream outright.frame: Assembles the STREAM frame around one pick, so the packet builder turns the chunk into the frame it encodes.frameDataCapacity: Works out the most data a STREAM frame can carry insideavailablebytes, so the packet builder turns the room left in a packet into a byte count it can ask the sending part for.frameHeaderBytes: Counts the bytes a STREAM frame spends ahead oflengthbytes of data, so the packet builder knows the header size before determining how many data bytes fit.initiator: Reads the opener out of the identifier's lowest bit, soadmitStreamcalls this function first because a frame for a stream this endpoint should have opened itself is a state error.receiveTransition: Applies every move of the receiving part, taking one event against the current state and giving back the state it lands in so a move the table has no entry for is caught at the table.sendTransition: Applies every move of the sending part, taking one event against the current state and giving back the state it lands in so a move the table has no entry for is caught at the table.sequence: Counts the streams of the same opener and kind that come before this one, soadmitStreamcompares the sequence against the advertised stream limit.
Types and contracts
Public types and contracts.
Chunk: The bytes and the closing flag picked out for one STREAM frame, so the packet builder can turn the chunk into a frame.Credit: Tracks what the peer has allowed this endpoint to send, over one stream or over the whole connection.Direction: Whether one endpoint or both may send on a stream.Initiator: Which of the two endpoints opened a stream.Range: One stretch of arrived bytes for the caller sizing the range table, held as the offset it starts at and the offset it ends at.ReadResult: Result of one read, recording how many bytes the call copied and whether it carried the read offset to the final size.Receive: The half of one stream that takes data in, held for stream 0 by the connection and driven from arriving frames, working out of a ring and a range table the caller supplies.ReceiveErrorReceiveEvent: Events that carry the receiving part from one state to the next, grouped so a caller names everything that can move that half.ReceiveState: States the other half of a stream, the receiving part, passes through, returned byConnection.receiveStateso a caller learns how far the receiving part has traveled.Send: The half of one stream that puts data out, working out of a ring and a range table the caller supplies, so the connection holds one for stream 0 and drives it from application writes and recovery.SendEvent: Events that carry the sending part from one state to the next, grouped so a caller names everything that can move that half.SendState: States one half of a stream, the sending part, passes through, returned byConnection.sendStateso a caller learns how far the sending part has traveled.SentRange: One STREAM frame that has gone out, held until an acknowledgment or a loss settles it, so the caller can size the range table to hold one entry for each outstanding frame.StreamId: The number that names one QUIC stream serves as the type for every stream argument in the public API.TransitionErrorWindow: Tracks what this endpoint has told the peer it will take, over one stream or over the whole connection.
Namespaces
Public namespaces.
Source
Source: lib/quic/src/connection/stream/flow.zig:7
/// Tracks what the peer has allowed this endpoint to send, over one stream or over the whole/// connection. The sending part of a stream and the connection each hold one so every byte sent is/// charged against it. Its fields are that allowance, how much of it has gone, and the figure a/// BLOCKED frame last reported. What has gone stays inside the allowance.pub const Credit = struct { limit: u62, used: u62 = 0, blocked_limit: ?u62 = null, pub fn init(limit: u62) Credit { return .{ .limit = limit }; } /// Counts what is left to send under the allowance so the send path sizes each chunk against /// it. pub fn available(self: Credit) u62 { std.debug.assert(self.used <= self.limit); return self.limit - self.used; } /// Lifts the allowance to a larger figure the peer has granted. An arriving MAX_DATA or /// MAX_STREAM_DATA frame reaches the credit through this call. A figure at or under the /// allowance in hand leaves it alone, so a frame arriving behind its neighbors is harmless. pub fn raise(self: *Credit, maximum: u62) void { std.debug.assert(self.used <= self.limit); if (maximum <= self.limit) return; self.limit = maximum; } /// Charges bytes that have gone out against the allowance so the send path records each newly /// sent byte here. The count stays inside what was left. pub fn consume(self: *Credit, count: u62) void { std.debug.assert(count <= self.available()); self.used += count; std.debug.assert(self.used <= self.limit); } /// Hands back the figure a BLOCKED frame would report so the send path decides whether that /// frame belongs in the packet it is building. The call answers while bytes are waiting and the /// allowance is spent. Each figure is reported once: one a sent frame already carried yields /// nothing until the peer lifts the allowance. pub fn blocked(self: Credit, waiting: bool) ?u62 { if (!waiting) return null; if (self.available() != 0) return null; const reported = self.blocked_limit orelse return self.limit; return if (reported == self.limit) null else self.limit; } /// Notes which figure a BLOCKED frame has carried. The send path calls this once the frame is /// in a sealed packet. That figure stays at or under the allowance in force. pub fn markBlocked(self: *Credit, limit: u62) void { std.debug.assert(limit <= self.limit); self.blocked_limit = limit; } /// Forgets the figure noted for the loss path so a sender still held up reports itself a second /// time after the report is lost. A lost frame carrying a stale figure leaves the note alone, /// because a later frame has carried the figure in force since. pub fn loseBlocked(self: *Credit, limit: u62) void { const reported = self.blocked_limit orelse return; std.debug.assert(reported <= self.limit); if (reported != limit) return; self.blocked_limit = null; }};Source: lib/quic/src/connection/stream/flow.zig:75
/// Tracks what this endpoint has told the peer it will take, over one stream or over the whole/// connection. The receiving part of a stream and the connection each hold one so the window/// decides both what arriving data is allowed and when a limit frame goes out. Its fields are the/// window width, the figure in force, the totals arrived and given up to the application, and the/// given-up total at which that figure was set. `init` opens with the figure set to the window/// width.pub const Window = struct { size: u62, limit: u62, received: u62 = 0, consumed: u62 = 0, update_base: u62 = 0, /// Flag set when the packet carrying the figure in force was lost, so a window with no new room /// still asks for a limit frame by having `update` offer that same figure a second time. /// `advertise` clears it. limit_lost: bool = false, pub fn init(size: u62) Window { return .{ .size = size, .limit = size }; } /// Says whether an arrived total is still inside what this endpoint offered so the receiving /// part checks arriving data before accepting it, because a false answer closes the connection /// with FLOW_CONTROL_ERROR. A total level with the figure is taken, and one byte beyond it is /// turned away. pub fn allows(self: Window, received: u64) bool { return received <= self.limit; } /// Notes an arrived total for the receiving part after `allows` has accepted the data. The /// total stays inside the figure in force. A total under one already noted leaves it alone. pub fn record(self: *Window, received: u62) void { std.debug.assert(received <= self.limit); if (received > self.received) self.received = received; } /// Notes bytes the application has taken, or bytes a reset has thrown away, so reading stream /// bytes earns the peer more room. The given-up total climbs and stays at or under the arrived /// total. pub fn release(self: *Window, consumed: u62) void { std.debug.assert(consumed >= self.consumed); std.debug.assert(consumed <= self.received); self.consumed = consumed; } /// Offers a larger figure once the application has taken half a window so the send path decides /// whether a MAX_DATA or MAX_STREAM_DATA frame belongs in the packet it is building. That /// figure is the given-up total plus one window width, stopping at the largest u62 value. With /// `limit_lost` set and no larger figure due, the call offers the figure in force a second /// time. The call offers nothing when no frame is called for. pub fn update(self: Window) ?u62 { std.debug.assert(self.consumed >= self.update_base); const progress: u64 = self.consumed - self.update_base; if (progress * 2 >= self.size) { const next = std.math.add(u62, self.consumed, self.size) catch std.math.maxInt(u62); if (next > self.limit) return next; } return if (self.limit_lost) self.limit else null; } /// Notes the figure carried by a MAX_DATA frame, or by a MAX_STREAM_DATA frame, that has gone /// out, then clears `limit_lost`. The send path calls this once the limit frame is in a sealed /// packet. The figure climbs, save when a loss forces the same one out a second time. Noting a /// larger figure moves the mark that the next half window is counted from. pub fn advertise(self: *Window, limit: u62) void { std.debug.assert(limit <= std.math.add(u62, self.consumed, self.size) catch limit); if (limit == self.limit) { std.debug.assert(self.limit_lost); self.limit_lost = false; return; } std.debug.assert(limit > self.limit); self.limit_lost = false; self.limit = limit; self.update_base = self.consumed; } /// Marks the figure in force as lost for the loss path when the lost frame carried it, so the /// peer still learns a limit whose frame was lost. A lost frame carrying a stale figure calls /// for nothing, because a later frame has carried the figure in force since. pub fn loseLimit(self: *Window, limit: u62) void { std.debug.assert(limit <= self.limit); if (limit != self.limit) return; self.limit_lost = true; }};Source: lib/quic/src/connection/stream/id.zig:13
/// Whether one endpoint or both may send on a stream. This connection carries one bidirectional/// stream, so a unidirectional identifier closes the connection.pub const Direction = enum { bidirectional, unidirectional };Source: lib/quic/src/connection/stream/id.zig:9
/// Which of the two endpoints opened a stream. `admitStream` compares it against this endpoint's/// own role to decide whether an arriving frame names a stream this endpoint opened.pub const Initiator = enum { client, server };Source: lib/quic/src/connection/stream/receive.zig:9
/// One stretch of arrived bytes for the caller sizing the range table, held as the offset it starts/// at and the offset it ends at. Every stretch sits at or above the read offset, because a read/// trims away what it takes.pub const Range = struct { start: u62, end: u62, pub fn empty() Range { return .{ .start = 0, .end = 0 }; }};Source: lib/quic/src/connection/stream/receive.zig:21
/// Result of one read, recording how many bytes the call copied and whether it carried the read/// offset to the final size. `read` returns this result so an application learns from the FIN flag/// that the stream ended.pub const ReadResult = struct { bytes: usize, fin: bool,};Source: lib/quic/src/connection/stream/receive.zig:33
/// The half of one stream that takes data in, held for stream 0 by the connection and driven from/// arriving frames, working out of a ring and a range table the caller supplies. This half holds/// that ring and table, the stream's window, the state, the read offset, the final size, and the/// codes a reset and a stop carried. `init` wants both the ring and the table nonempty, and a/// window no wider than the ring.pub const Receive = struct { bytes: []u8, ranges: []Range, window: stream.Window, state: stream.ReceiveState = .recv, count: u16 = 0, head: usize = 0, read_offset: u62 = 0, final_size: ?u62 = null, reset_code: ?u62 = null, stop_code: ?u62 = null, stop_pending: bool = false, pub fn init(bytes: []u8, ranges: []Range, window: u62) Receive { std.debug.assert(bytes.len > 0); std.debug.assert(ranges.len > 0); std.debug.assert(ranges.len <= std.math.maxInt(u16)); std.debug.assert(window <= bytes.len); for (ranges) |*range| range.* = Range.empty(); return .{ .bytes = bytes, .ranges = ranges, .window = stream.Window.init(window) }; } /// Takes in one arriving STREAM frame's data for the stream, putting up with bytes that repeat /// or overlap what has arrived already. The bytes new to the half are charged against this /// stream's window and against the connection window handed in. Data past either window answers /// `FlowControl`, and data that moves a settled final size or runs beyond one answers /// `FinalSize`. Data ending past the highest offset a stream can reach answers `FlowControl` as /// well. A packet that would want one stretch more than the table holds answers `RangesFull`. /// Once the half has everything, or has been reset, later data is charged against both windows /// and then thrown away. A frame carrying FIN settles the final size and moves the half to Size /// Known. pub fn receive( self: *Receive, connection: *stream.Window, offset: u62, data: []const u8, fin: bool, ) ReceiveError!void { if (data.len > std.math.maxInt(u62) - offset) return error.FlowControl; const end = offset + @as(u62, @intCast(data.len)); try self.checkFinal(end, fin); const growth = try self.admit(connection, end); if (self.discarding()) return; const start = @max(offset, self.read_offset); if (start < end) { try self.insert(start, end); const skipped: usize = @intCast(start - offset); stream.ring.write(self.bytes, self.ringIndex(start), data[skipped..]); } self.window.record(end); connection.record(connection.received + growth); if (fin and self.final_size == null) { self.final_size = end; self.state = stream.receiveTransition(self.state, .receive_fin) catch unreachable; } self.observeComplete(); } /// Counts the bytes waiting in order at the read offset, so the caller learns how much one read /// can copy. The call answers zero after a reset, and zero while a hole sits at the read /// offset. pub fn readable(self: *const Receive) usize { if (self.reset_code != null) return 0; if (self.count == 0) return 0; const first = self.ranges[0]; if (first.start != self.read_offset) return 0; return @intCast(first.end - first.start); } /// Copies the waiting bytes in offset order for an application taking its bytes, and says /// whether the read reached the final size. What the call copies is given up to this stream's /// window and to the connection window, releasing room back to the peer so the peer earns more /// room. A read that passes the final size moves the half to Data Read. On a stream the peer /// reset, the call copies nothing and moves the half to Reset Read. pub fn read(self: *Receive, connection: *stream.Window, output: []u8) ReadResult { switch (self.state) { .reset_recvd => { self.state = stream.receiveTransition(.reset_recvd, .read_reset) catch unreachable; return .{ .bytes = 0, .fin = false }; }, .reset_read => return .{ .bytes = 0, .fin = false }, .recv, .size_known, .data_recvd, .data_read => {}, } const count = @min(output.len, self.readable()); stream.ring.read(self.bytes, self.head, output[0..count]); self.consume(count); connection.release(connection.consumed + @as(u62, @intCast(count))); const fin = if (self.final_size) |final| self.read_offset == final else false; if (fin and self.state == .data_recvd) { self.state = stream.receiveTransition(.data_recvd, .read_all) catch unreachable; } return .{ .bytes = count, .fin = fin }; } /// Applies one arriving RESET_STREAM frame for the stream once the final size and both windows /// check out. A final size at odds with one already settled, or under what has arrived already, /// answers `FinalSize`, and a final size past either window answers `FlowControl`. Every byte /// up to the final size is given up to the connection window, the ones the application will /// never see among them. The call throws away the arrived stretches, keeps the error code, /// drops a STOP_SENDING that was waiting, and moves the half to Reset Recvd. pub fn resetReceived( self: *Receive, connection: *stream.Window, code: u62, final: u62, ) error{ FlowControl, FinalSize }!void { if (self.final_size) |known| { if (final != known) return error.FinalSize; } if (final < self.window.received) return error.FinalSize; const growth = try self.admit(connection, final); if (self.discarding()) return; self.window.record(final); connection.record(connection.received + growth); connection.release(connection.consumed + (final - self.read_offset)); self.final_size = final; self.reset_code = code; self.stop_pending = false; self.removeRanges(0, self.count); self.state = stream.receiveTransition(self.state, .receive_reset) catch unreachable; } /// Puts a STOP_SENDING frame in the queue while the peer might still send, so an application /// tells the peer to stop sending. The call answers false on a second call, and false once the /// half holds everything or has been reset, so the returned flag says whether the request was /// taken. pub fn stop(self: *Receive, code: u62) bool { if (self.stop_code != null) return false; if (self.discarding()) return false; self.stop_code = code; self.stop_pending = true; return true; } /// Puts STOP_SENDING back in the queue for the loss path after its packet was lost, so the /// frame goes out again. The call queues nothing once the half holds everything or has been /// reset, because the peer has stopped by then. A stop code is in hand when this function is /// called. pub fn loseStop(self: *Receive) void { std.debug.assert(self.stop_code != null); if (self.discarding()) return; self.stop_pending = true; } /// Offers a larger MAX_STREAM_DATA figure while more data may yet arrive, so the send path can /// decide whether a MAX_STREAM_DATA frame belongs in the packet it is building. Once the half /// has left Recv the final size is settled, so more room would buy nothing and the call offers /// none. pub fn windowUpdate(self: *const Receive) ?u62 { if (self.state != .recv) return null; return self.window.update(); } fn checkFinal(self: *const Receive, end: u62, fin: bool) error{FinalSize}!void { if (self.final_size) |final| { if (end > final) return error.FinalSize; if (fin and end != final) return error.FinalSize; return; } if (fin and end < self.window.received) return error.FinalSize; } fn admit( self: *const Receive, connection: *const stream.Window, end: u62, ) error{FlowControl}!u62 { if (!self.window.allows(end)) return error.FlowControl; const growth = end -| self.window.received; if (!connection.allows(@as(u64, connection.received) + growth)) return error.FlowControl; return growth; } fn discarding(self: *const Receive) bool { return switch (self.state) { .recv, .size_known => false, .data_recvd, .data_read, .reset_recvd, .reset_read => true, }; } fn insert(self: *Receive, start: u62, end: u62) error{RangesFull}!void { std.debug.assert(start < end); std.debug.assert(start >= self.read_offset); var first: usize = self.count; for (0..self.count) |index| { if (self.ranges[index].end >= start) { first = index; break; } } var last = first; for (first..self.count) |index| { if (self.ranges[index].start > end) break; last = index + 1; } if (first == last) return self.insertAt(first, .{ .start = start, .end = end }); self.ranges[first] = .{ .start = @min(start, self.ranges[first].start), .end = @max(end, self.ranges[last - 1].end), }; self.removeRanges(first + 1, last - first - 1); } fn insertAt(self: *Receive, at: usize, range: Range) error{RangesFull}!void { std.debug.assert(at <= self.count); if (self.count == self.ranges.len) return error.RangesFull; for (0..self.count - at) |step| { const index = self.count - step; self.ranges[index] = self.ranges[index - 1]; } self.ranges[at] = range; self.count += 1; } fn removeRanges(self: *Receive, at: usize, removed: usize) void { std.debug.assert(at + removed <= self.count); const remaining = self.count - removed; for (at..remaining) |index| self.ranges[index] = self.ranges[index + removed]; for (remaining..self.count) |index| self.ranges[index] = Range.empty(); self.count = @intCast(remaining); } fn consume(self: *Receive, count: usize) void { if (count == 0) return; std.debug.assert(count <= self.readable()); const advance: u62 = @intCast(count); self.read_offset += advance; self.head = (self.head + count) % self.bytes.len; self.ranges[0].start += advance; if (self.ranges[0].start == self.ranges[0].end) self.removeRanges(0, 1); self.window.release(self.read_offset); } fn observeComplete(self: *Receive) void { if (self.state != .size_known) return; const final = self.final_size.?; const contiguous = self.read_offset + @as(u62, @intCast(self.readable())); if (contiguous != final) return; self.stop_pending = false; self.state = stream.receiveTransition(.size_known, .all_received) catch unreachable; } fn ringIndex(self: *const Receive, offset: u62) usize { std.debug.assert(offset >= self.read_offset); const distance: usize = @intCast(offset - self.read_offset); std.debug.assert(distance < self.bytes.len); return (self.head + distance) % self.bytes.len; }};Source: lib/quic/src/connection/stream/receive.zig:26
pub const ReceiveError = error{ FlowControl, FinalSize, RangesFull };Source: lib/quic/src/connection/stream/send.zig:24
/// The bytes and the closing flag picked out for one STREAM frame, so the packet builder can turn/// the chunk into a frame. The chunk holds the offset, those bytes, and that flag. The bytes point/// into the send ring.pub const Chunk = struct { offset: u62, data: []const u8, fin: bool,};Source: lib/quic/src/connection/stream/send.zig:36
/// The half of one stream that puts data out, working out of a ring and a range table the caller/// supplies, so the connection holds one for stream 0 and drives it from application writes and/// recovery. The half holds that ring and table, the peer's credit, the state, the offsets/// acknowledged, sent, and written, the final size, and the reset state. Those three offsets keep/// their order, acknowledged at or under sent and sent at or under written. `init` wants both the/// ring and the table nonempty.pub const Send = struct { bytes: []u8, ranges: []SentRange, credit: stream.Credit, state: stream.SendState = .ready, head: usize = 0, acknowledged: u62 = 0, sent: u62 = 0, written: u62 = 0, final_size: ?u62 = null, fin_sent: bool = false, fin_acknowledged: bool = false, /// The stretch of the stream that a lost frame put back in the queue, so the next chunk can /// start below the sent offset. Those bytes go out ahead of anything the application has newly /// written. lost: quic.connection.recovery.LostRange = .{}, /// Flag set when a lost frame carried the closing flag before an acknowledgment covered it, /// because a lost closing flag carries no bytes of its own and needs a dedicated flag. The flag /// clears once a copy goes out, once an acknowledgment covers the flag, or once a reset /// abandons the stream. fin_lost: bool = false, reset_code: ?u62 = null, reset_pending: bool = false, pub fn init(bytes: []u8, ranges: []SentRange, limit: u62) Send { std.debug.assert(bytes.len > 0); std.debug.assert(ranges.len > 0); for (ranges) |*range| range.* = SentRange.empty(); return .{ .bytes = bytes, .ranges = ranges, .credit = stream.Credit.init(limit) }; } /// Counts what the ring is holding, measured from the oldest byte the peer has yet to /// acknowledge, so `write` accepts what room remains. The count fits inside the ring. pub fn buffered(self: *const Send) usize { std.debug.assert(self.acknowledged <= self.sent); std.debug.assert(self.sent <= self.written); const count: usize = @intCast(self.written - self.acknowledged); std.debug.assert(count <= self.bytes.len); return count; } /// Takes application bytes into the ring so they enter the stream, accepting as many as free /// room allows, and reports how many it took. The call accepts nothing once the final size is /// settled or a reset has abandoned the stream. The call also stops at the highest offset a /// stream can reach. pub fn write(self: *Send, input: []const u8) usize { if (!self.writable()) return 0; const free = self.bytes.len - self.buffered(); const offset_room: u64 = std.math.maxInt(u62) - self.written; const count: usize = @intCast(@min(free, input.len, offset_room)); if (count == 0) return 0; stream.ring.write(self.bytes, self.ringIndex(self.written), input[0..count]); self.written += @intCast(count); std.debug.assert(self.buffered() <= self.bytes.len); return count; } /// Settles the final size at the last byte the application wrote, so the application ends its /// side of the stream. The call leaves state unchanged when the final size is settled already /// or the stream stands reset. pub fn finish(self: *Send) void { if (!self.writable()) return; self.final_size = self.written; } /// Says whether this half has anything for the packet being built, so the send path decides /// whether to request a frame. Lost bytes, a lost closing flag, bytes never sent, and a closing /// flag never sent each count. A reset leaves nothing waiting, having abandoned what was there. pub fn pending(self: *const Send) bool { if (self.reset_code != null) return false; if (!self.lost.isEmpty() or self.fin_lost) return true; if (self.sent < self.written) return true; const final = self.final_size orelse return false; std.debug.assert(final == self.sent); return !self.fin_sent; } /// Gives the offset the next STREAM frame will start at, so the packet builder can size the /// frame header against that offset before asking for a chunk. The start is the first byte /// waiting to go a second time, or, with none waiting, the first byte never sent. pub fn nextOffset(self: *const Send) u62 { if (self.lost.isEmpty()) return self.sent; std.debug.assert(self.lost.start >= self.acknowledged); std.debug.assert(self.lost.end <= self.sent); return self.lost.start; } /// Picks out up to `data_max` bytes in order for the next STREAM frame, so the packet builder /// receives the payload for that frame. Bytes going a second time come first, then a closing /// flag on its own, and both travel free of credit. Bytes going out for the first time stop at /// this stream's own credit and at `connection_credit`. The pick also stops at the buffer end /// where the ring wraps, and at the longest payload a frame may carry. The closing flag travels /// with the pick that reaches the final size. The call returns null when the half has nothing /// waiting, and returns null when every entry in the table is taken. pub fn nextChunk(self: *const Send, data_max: usize, connection_credit: u62) ?Chunk { if (!self.pending()) return null; if (self.freeRange() == null) return null; if (!self.lost.isEmpty()) return self.lostChunk(data_max); if (self.fin_lost) return self.lostFin(); const index = self.ringIndex(self.sent); const credit: u64 = @min(self.credit.available(), connection_credit); const waiting: u64 = self.written - self.sent; const room: u64 = @min(data_max, self.bytes.len - index, std.math.maxInt(u16)); const count: usize = @intCast(@min(waiting, credit, room)); const end = self.sent + @as(u62, @intCast(count)); const fin = if (self.final_size) |final| end == final and !self.fin_sent else false; if (count == 0 and !fin) return null; return .{ .offset = self.sent, .data = self.bytes[index..][0..count], .fin = fin }; } /// Takes an entry in the table for the pick that has gone out, and reports how many of its /// bytes had never gone before, for the packet builder to call once the packet holding the /// frame is sealed and charge that count to connection credit. Only that figure is charged to /// the connection credit, because bytes going a second time sit under the highest offset /// already reached. A pick that had gone before reports zero and takes its bytes out of the /// waiting stretch. A pick of fresh bytes moves the sent offset on, spends this stream's /// credit, and moves the half's state. pub fn commitChunk(self: *Send, offset: u62, length: u16, fin: bool) u16 { const slot = self.freeRange() orelse unreachable; self.ranges[slot] = .{ .offset = offset, .length = length, .fin = fin, .outstanding = true, }; if (offset < self.sent or (fin and self.fin_sent)) { self.commitLost(offset, length, fin); return 0; } std.debug.assert(offset == self.sent); std.debug.assert(length <= self.written - self.sent); self.sent += length; self.credit.consume(length); if (fin) { std.debug.assert(self.sent == self.final_size.?); self.fin_sent = true; } const event: stream.SendEvent = if (fin) .send_fin else .send_data; self.state = stream.sendTransition(self.state, event) catch unreachable; return length; } /// Hands back the figure a STREAM_DATA_BLOCKED frame would report while this stream's own /// credit holds the sender up, so the send path decides whether that frame belongs in the /// packet being built. The sender counts as held up while the stream stands unreset and bytes /// wait to go. pub fn blocked(self: *const Send) ?u62 { const waiting = self.reset_code == null and self.sent < self.written; return self.credit.blocked(waiting); } /// Notes that a STREAM_DATA_BLOCKED frame went out, for the send path to call once the frame is /// in a sealed packet. That frame also starts the half moving, taking it out of Ready. pub fn commitBlocked(self: *Send, limit: u62) void { self.credit.markBlocked(limit); if (self.state != .ready) return; self.state = stream.sendTransition(.ready, .send_data) catch unreachable; } /// Frees the ring bytes one acknowledged STREAM frame covered, and trims them off whichever end /// of the waiting stretch they reach, so an acknowledged packet frees the send buffer. An /// acknowledgment covering the closing flag clears a lost one. Bytes come free in offset order, /// so an acknowledgment above a frame still outstanding frees nothing yet. The call passes over /// a frame this half has already released. The closing flag acknowledged with every byte behind /// it carries the half to Data Recvd. pub fn acknowledge(self: *Send, offset: u62, length: u16, fin: bool) void { const slot = self.findRange(offset, length, fin) orelse return; self.ranges[slot] = SentRange.empty(); self.lost.acknowledge(offset, length); if (fin) { self.fin_acknowledged = true; self.fin_lost = false; } self.releaseAcknowledged(); if (self.state != .data_sent) return; if (!self.fin_acknowledged) return; if (self.acknowledged != self.sent) return; self.state = stream.sendTransition(.data_sent, .all_acknowledged) catch unreachable; } /// Gives up the table entry a lost STREAM frame held, and puts its bytes, with a closing flag /// no acknowledgment has covered, in the stretch that goes ahead of fresh bytes, so lost bytes /// go out again ahead of new ones. A frame whose entry an acknowledgment or a reset has already /// given up calls for nothing. pub fn lose(self: *Send, offset: u62, length: u16, fin: bool) void { const slot = self.findRange(offset, length, fin) orelse return; std.debug.assert(offset >= self.acknowledged); std.debug.assert(offset + length <= self.sent); self.ranges[slot] = SentRange.empty(); self.lost.add(offset, length); if (fin and !self.fin_acknowledged) self.fin_lost = true; } /// Gives up on the bytes waiting, sent and unsent alike, and queues RESET_STREAM so an /// application can abandon the stream, returning whether the reset was taken. What a reset /// gives up on has no route back onto the wire. The call settles the final size at the highest /// offset already sent. The call returns false on a second call, and false once the half holds /// every acknowledgment or has sent its reset already. pub fn reset(self: *Send, code: u62) bool { if (self.reset_code != null) return false; switch (self.state) { .ready, .send, .data_sent => {}, .data_recvd, .reset_sent, .reset_recvd => return false, } self.reset_code = code; self.reset_pending = true; self.written = self.sent; self.final_size = self.sent; self.lost = .{}; self.fin_lost = false; for (self.ranges) |*range| range.* = SentRange.empty(); self.releaseAcknowledged(); std.debug.assert(self.buffered() == 0); return true; } /// Hands back the RESET_STREAM frame that is waiting for a packet, so the send path can insert /// that frame into the packet being built. That frame carries the error code, and the highest /// offset sent as its final size. The call returns null when no reset waits. pub fn resetFrame(self: *const Send, stream_id: u62) ?quic.frame.ResetStream { if (!self.reset_pending) return null; const code = self.reset_code.?; return .{ .stream_id = stream_id, .error_code = code, .final_size = self.sent }; } /// Notes that a RESET_STREAM frame went out and carries the half into Reset Sent, for the send /// path to call once the frame is in a sealed packet. When a loss has put one RESET_STREAM /// frame out already, the half stands in Reset Sent as the copy goes, and stays there. pub fn commitReset(self: *Send) void { std.debug.assert(self.reset_pending); self.reset_pending = false; if (self.state == .reset_sent) return; self.state = stream.sendTransition(self.state, .send_reset) catch unreachable; } /// Puts RESET_STREAM back in the queue after a loss, while the half sits in Reset Sent, so a /// lost RESET_STREAM goes out again. The copy carries the same code and final size, because /// `resetFrame` reads both out of the same fields. Once an acknowledgment has carried the half /// to Reset Recvd the peer knows, so nothing goes in the queue. pub fn loseReset(self: *Send) void { if (self.state != .reset_sent) return; std.debug.assert(self.reset_code != null); self.reset_pending = true; } /// Notes the acknowledgment of the RESET_STREAM frame and carries the half into Reset Recvd, so /// an acknowledged RESET_STREAM ends the sending part. Called from any state other than Reset /// Sent, the call leaves state unchanged. pub fn acknowledgeReset(self: *Send) void { if (self.state != .reset_sent) return; self.reset_pending = false; self.state = stream.sendTransition(.reset_sent, .reset_acknowledged) catch unreachable; } fn writable(self: *const Send) bool { if (self.final_size != null) return false; if (self.reset_code != null) return false; std.debug.assert(self.state != .data_sent); std.debug.assert(self.state != .data_recvd); return true; } fn lostChunk(self: *const Send, data_max: usize) ?Chunk { std.debug.assert(!self.lost.isEmpty()); const offset = self.lost.start; const index = self.ringIndex(offset); const room: u64 = @min(data_max, self.bytes.len - index, std.math.maxInt(u16)); const count: usize = @intCast(@min(self.lost.length(), room)); if (count == 0) return null; const end = offset + @as(u62, @intCast(count)); const fin = self.fin_lost and end == self.final_size.?; return .{ .offset = offset, .data = self.bytes[index..][0..count], .fin = fin }; } fn lostFin(self: *const Send) Chunk { std.debug.assert(self.fin_lost); std.debug.assert(self.fin_sent); std.debug.assert(self.final_size.? == self.sent); const index = self.ringIndex(self.sent); return .{ .offset = self.sent, .data = self.bytes[index..][0..0], .fin = true }; } fn commitLost(self: *Send, offset: u62, length: u16, fin: bool) void { if (fin) { std.debug.assert(self.fin_lost); self.fin_lost = false; } if (length == 0) return; std.debug.assert(offset == self.lost.start); self.lost.advance(length); } fn releaseAcknowledged(self: *Send) void { var lowest = self.sent; if (!self.lost.isEmpty()) lowest = @min(lowest, self.lost.start); for (self.ranges) |range| { if (range.outstanding and range.offset < lowest) lowest = range.offset; } std.debug.assert(lowest >= self.acknowledged); const released: usize = @intCast(lowest - self.acknowledged); std.debug.assert(released <= self.bytes.len); self.head = (self.head + released) % self.bytes.len; self.acknowledged = lowest; } fn ringIndex(self: *const Send, offset: u62) usize { std.debug.assert(offset >= self.acknowledged); const distance: usize = @intCast(offset - self.acknowledged); std.debug.assert(distance <= self.bytes.len); return (self.head + distance) % self.bytes.len; } fn freeRange(self: *const Send) ?usize { for (self.ranges, 0..) |range, index| { if (!range.outstanding) return index; } return null; } fn findRange(self: *const Send, offset: u62, length: u16, fin: bool) ?usize { for (self.ranges, 0..) |range, index| { if (!range.outstanding) continue; if (range.offset != offset) continue; if (range.length == length and range.fin == fin) return index; } return null; }};Source: lib/quic/src/connection/stream/send.zig:10
/// One STREAM frame that has gone out, held until an acknowledgment or a loss settles it, so the/// caller can size the range table to hold one entry for each outstanding frame. The entry holds/// the offset, the byte count, whether that frame closed the stream, and whether the entry is/// taken.pub const SentRange = struct { offset: u62, length: u16, fin: bool, outstanding: bool, pub fn empty() SentRange { return .{ .offset = 0, .length = 0, .fin = false, .outstanding = false }; }};Source: lib/quic/src/connection/stream/state.zig:45
/// Events that carry the receiving part from one state to the next, grouped so a caller names/// everything that can move that half.pub const ReceiveEvent = enum { /// A frame carrying data without the closing flag has arrived. receive_data, /// A frame carrying the closing flag has arrived. receive_fin, /// Every byte up to the final size has arrived. all_received, /// The application has taken every byte up to the final size. read_all, /// A RESET_STREAM frame has arrived. receive_reset, /// The application has seen the reset. read_reset,};Source: lib/quic/src/connection/stream/state.zig:34
/// States the other half of a stream, the receiving part, passes through, returned by/// `Connection.receiveState` so a caller learns how far the receiving part has traveled. These/// states are recv, size_known, data_recvd, data_read, reset_recvd, and reset_read.pub const ReceiveState = enum { recv, size_known, data_recvd, data_read, reset_recvd, reset_read,};Source: lib/quic/src/connection/stream/state.zig:17
/// Events that carry the sending part from one state to the next, grouped so a caller names/// everything that can move that half.pub const SendEvent = enum { /// A frame carrying data without the closing flag, or a STREAM_DATA_BLOCKED frame, has gone /// out. send_data, /// A frame carrying the closing flag has gone out. send_fin, /// The peer has acknowledged every byte up to the final size, and the closing flag with them. all_acknowledged, /// A RESET_STREAM frame has gone out. send_reset, /// The peer has acknowledged the RESET_STREAM frame. reset_acknowledged,};Source: lib/quic/src/connection/stream/state.zig:6
/// States one half of a stream, the sending part, passes through, returned by/// `Connection.sendState` so a caller learns how far the sending part has traveled. These states/// are ready, send, data_sent, data_recvd, reset_sent, and reset_recvd.pub const SendState = enum { ready, send, data_sent, data_recvd, reset_sent, reset_recvd,};Source: lib/quic/src/connection/stream/state.zig:60
pub const TransitionError = error{InvalidTransition};Source: lib/quic/src/connection/stream/id.zig:25
/// Reads out of the identifier's second bit whether both sides may send, so `admitStream` rejects a/// unidirectional stream outright. A zero there names a stream both sides send on, and a one names/// a stream only its opener sends on.pub fn direction(id: StreamId) Direction { return if (id & 0x02 == 0) .bidirectional else .unidirectional;}Source: lib/quic/src/connection/stream/id.zig:18
/// Reads the opener out of the identifier's lowest bit, so `admitStream` calls this function first/// because a frame for a stream this endpoint should have opened itself is a state error. A zero/// there names the client and a one names the server.pub fn initiator(id: StreamId) Initiator { return if (id & 0x01 == 0) .client else .server;}Source: lib/quic/src/connection/stream/id.zig:32
/// Counts the streams of the same opener and kind that come before this one, so `admitStream`/// compares the sequence against the advertised stream limit. The sequence is the identifier/// shifted past its two lowest bits.pub fn sequence(id: StreamId) u60 { return @intCast(id >> 2);}Source: lib/quic/src/connection/stream/send.zig:401
/// Assembles the STREAM frame around one pick, so the packet builder turns the chunk into the frame/// it encodes. The OFF bit goes in whenever the offset stands above zero.pub fn frame(stream_id: u62, chunk: Chunk, length_present: bool) quic.frame.Frame { return .{ .stream = .{ .stream_id = stream_id, .offset = chunk.offset, .offset_present = chunk.offset != 0, .length_present = length_present, .fin = chunk.fin, .data = chunk.data, } };}Source: lib/quic/src/connection/stream/send.zig:381
/// Works out the most data a STREAM frame can carry inside `available` bytes, so the packet builder/// turns the room left in a packet into a byte count it can ask the sending part for. The call/// returns null when even a frame without data cannot fit. The length field widens as the data/// grows, so the answer is settled in two passes.pub fn frameDataCapacity( stream_id: u62, offset: u62, available: usize, length_present: bool,) ?usize { const empty = frameHeaderBytes(stream_id, offset, 0, length_present); if (empty > available) return null; const first = available - empty; const header = frameHeaderBytes(stream_id, offset, first, length_present); if (header + first <= available) return first; std.debug.assert(header <= available); const second = available - header; const second_header = frameHeaderBytes(stream_id, offset, second, length_present); std.debug.assert(second_header + second <= available); return second;}Source: lib/quic/src/connection/stream/send.zig:369
/// Counts the bytes a STREAM frame spends ahead of `length` bytes of data, so the packet builder/// knows the header size before determining how many data bytes fit. Those bytes carry the frame/// type and the stream identifier always, the offset whenever it stands above zero, and the length/// whenever the caller asks for one.pub fn frameHeaderBytes(stream_id: u62, offset: u62, length: usize, length_present: bool) usize { std.debug.assert(length <= std.math.maxInt(u62)); var bytes: usize = 1 + @as(usize, quic.varint.encodedLength(stream_id)); if (offset != 0) bytes += quic.varint.encodedLength(offset); if (length_present) bytes += quic.varint.encodedLength(@intCast(length)); return bytes;}Source: lib/quic/src/connection/stream/state.zig:91
/// Applies every move of the receiving part, taking one event against the current state and giving/// back the state it lands in so a move the table has no entry for is caught at the table. An event/// the current state has no entry for answers `InvalidTransition`. Data Read and Reset Read lead/// nowhere further.pub fn receiveTransition(state: ReceiveState, event: ReceiveEvent) TransitionError!ReceiveState { return switch (state) { .recv => switch (event) { .receive_data => .recv, .receive_fin => .size_known, .receive_reset => .reset_recvd, .all_received, .read_all, .read_reset => error.InvalidTransition, }, .size_known => switch (event) { .receive_data => .size_known, .all_received => .data_recvd, .receive_reset => .reset_recvd, .receive_fin, .read_all, .read_reset => error.InvalidTransition, }, .data_recvd => if (event == .read_all) .data_read else error.InvalidTransition, .reset_recvd => if (event == .read_reset) .reset_read else error.InvalidTransition, .data_read, .reset_read => error.InvalidTransition, };}Source: lib/quic/src/connection/stream/state.zig:66
/// Applies every move of the sending part, taking one event against the current state and giving/// back the state it lands in so a move the table has no entry for is caught at the table. An event/// the current state has no entry for answers `InvalidTransition`. Data Recvd and Reset Recvd lead/// nowhere further.pub fn sendTransition(state: SendState, event: SendEvent) TransitionError!SendState { return switch (state) { .ready, .send => switch (event) { .send_data => .send, .send_fin => .data_sent, .send_reset => .reset_sent, .all_acknowledged, .reset_acknowledged => error.InvalidTransition, }, .data_sent => switch (event) { .all_acknowledged => .data_recvd, .send_reset => .reset_sent, .send_data, .send_fin, .reset_acknowledged => error.InvalidTransition, }, .reset_sent => switch (event) { .reset_acknowledged => .reset_recvd, .send_data, .send_fin, .all_acknowledged, .send_reset => error.InvalidTransition, }, .data_recvd, .reset_recvd => error.InvalidTransition, };}Source: lib/quic/src/connection/stream/id.zig:5
/// The number that names one QUIC stream serves as the type for every stream argument in the public/// API. The value is sixty-two bits wide and unsigned.pub const StreamId = u62;Source: lib/quic/src/connection/root.zig:13
pub const stream = @import("stream/root.zig");Source: lib/quic/src/connection/stream/root.zig
const flow = @import("flow.zig");const id = @import("id.zig");const receive = @import("receive.zig");const send = @import("send.zig");const state = @import("state.zig");pub const ring = @import("ring.zig");pub const StreamId = id.StreamId;pub const Initiator = id.Initiator;pub const Direction = id.Direction;pub const initiator = id.initiator;pub const direction = id.direction;pub const sequence = id.sequence;pub const SendState = state.SendState;pub const SendEvent = state.SendEvent;pub const ReceiveState = state.ReceiveState;pub const ReceiveEvent = state.ReceiveEvent;pub const TransitionError = state.TransitionError;pub const sendTransition = state.sendTransition;pub const receiveTransition = state.receiveTransition;pub const Credit = flow.Credit;pub const Window = flow.Window;pub const SentRange = send.SentRange;pub const Chunk = send.Chunk;pub const Send = send.Send;pub const frameHeaderBytes = send.frameHeaderBytes;pub const frameDataCapacity = send.frameDataCapacity;pub const frame = send.frame;pub const Range = receive.Range;pub const ReadResult = receive.ReadResult;pub const ReceiveError = receive.ReceiveError;pub const Receive = receive.Receive;Complete caller list for connection.stream.Receive.init
7 direct callers.
lib.quic.src.connection.stream.receive.test_RFC_9000_section_13.3_a_lost_STOP_SENDING_goes_out_again_until_Data_Recvd_or_Reset_Recvd[function] — test source atlib/quic/src/connection/stream/receive.zig:396in nearest public ownerlib.quic.src.connection.stream.receivelib.quic.src.connection.stream.receive.test_RFC_9000_section_2.2_reassembly_orders_gaps,_overlaps,_duplicates,_and_reordering[function] — test source atlib/quic/src/connection/stream/receive.zig:283in nearest public ownerlib.quic.src.connection.stream.receivelib.quic.src.connection.stream.receive.test_RFC_9000_section_2.2_received_range_records_maximum_and_maximum_plus_one[function] — test source atlib/quic/src/connection/stream/receive.zig:308in nearest public ownerlib.quic.src.connection.stream.receivelib.quic.src.connection.stream.receive.test_RFC_9000_section_3.2_RESET_STREAM_discards_unread_data_and_reports_the_code[function] — test source atlib/quic/src/connection/stream/receive.zig:357in nearest public ownerlib.quic.src.connection.stream.receivelib.quic.src.connection.stream.receive.test_RFC_9000_section_3.2_reading_through_the_FIN_reaches_Data_Read[function] — test source atlib/quic/src/connection/stream/receive.zig:378in nearest public ownerlib.quic.src.connection.stream.receivelib.quic.src.connection.stream.receive.test_RFC_9000_section_4.1_stream_and_connection_windows_accept_the_limit,_not_one_byte_past[function] — test source atlib/quic/src/connection/stream/receive.zig:325in nearest public ownerlib.quic.src.connection.stream.receivelib.quic.src.connection.stream.receive.test_RFC_9000_section_4.5_final_size_changes_close_with_FINAL_SIZE_ERROR[function] — test source atlib/quic/src/connection/stream/receive.zig:340in nearest public ownerlib.quic.src.connection.stream.receive
Complete caller list for connection.stream.Receive.receive
7 direct callers.
lib.quic.src.connection.stream.receive.test_RFC_9000_section_13.3_a_lost_STOP_SENDING_goes_out_again_until_Data_Recvd_or_Reset_Recvd[function] — test source atlib/quic/src/connection/stream/receive.zig:396in nearest public ownerlib.quic.src.connection.stream.receivelib.quic.src.connection.stream.receive.test_RFC_9000_section_2.2_reassembly_orders_gaps,_overlaps,_duplicates,_and_reordering[function] — test source atlib/quic/src/connection/stream/receive.zig:283in nearest public ownerlib.quic.src.connection.stream.receivelib.quic.src.connection.stream.receive.test_RFC_9000_section_2.2_received_range_records_maximum_and_maximum_plus_one[function] — test source atlib/quic/src/connection/stream/receive.zig:308in nearest public ownerlib.quic.src.connection.stream.receivelib.quic.src.connection.stream.receive.test_RFC_9000_section_3.2_RESET_STREAM_discards_unread_data_and_reports_the_code[function] — test source atlib/quic/src/connection/stream/receive.zig:357in nearest public ownerlib.quic.src.connection.stream.receivelib.quic.src.connection.stream.receive.test_RFC_9000_section_3.2_reading_through_the_FIN_reaches_Data_Read[function] — test source atlib/quic/src/connection/stream/receive.zig:378in nearest public ownerlib.quic.src.connection.stream.receivelib.quic.src.connection.stream.receive.test_RFC_9000_section_4.1_stream_and_connection_windows_accept_the_limit,_not_one_byte_past[function] — test source atlib/quic/src/connection/stream/receive.zig:325in nearest public ownerlib.quic.src.connection.stream.receivelib.quic.src.connection.stream.receive.test_RFC_9000_section_4.5_final_size_changes_close_with_FINAL_SIZE_ERROR[function] — test source atlib/quic/src/connection/stream/receive.zig:340in nearest public ownerlib.quic.src.connection.stream.receive
Complete call list for connection.stream.Receive.receive
7 direct calls.
lib.quic.src.connection.stream.receive.Receive.admit[method] — private source atlib/quic/src/connection/stream/receive.zig:195in nearest public ownerlib.quic.src.connection.stream.receivelib.quic.src.connection.stream.receive.Receive.checkFinal[method] — private source atlib/quic/src/connection/stream/receive.zig:186in nearest public ownerlib.quic.src.connection.stream.receivelib.quic.src.connection.stream.receive.Receive.discarding[method] — private source atlib/quic/src/connection/stream/receive.zig:206in nearest public ownerlib.quic.src.connection.stream.receivelib.quic.src.connection.stream.receive.Receive.insert[method] — private source atlib/quic/src/connection/stream/receive.zig:213in nearest public ownerlib.quic.src.connection.stream.receivelib.quic.src.connection.stream.receive.Receive.observeComplete[method] — private source atlib/quic/src/connection/stream/receive.zig:266in nearest public ownerlib.quic.src.connection.stream.receivelib.quic.src.connection.stream.receive.Receive.ringIndex[method] — private source atlib/quic/src/connection/stream/receive.zig:275in nearest public ownerlib.quic.src.connection.stream.receivetiny.quic.connection.stream.ring.write[function] atlib/quic/src/connection/stream/ring.zig:6
Complete caller list for connection.stream.Send.buffered
8 direct callers.
tiny.quic.connection.stream.Send.reset[method] atlib/quic/src/connection/stream/send.zig:234tiny.quic.connection.stream.Send.write[method] atlib/quic/src/connection/stream/send.zig:81lib.quic.src.connection.stream.send.test_RFC_9000_section_13.3_a_lost_FIN_goes_out_again_alone_or_on_the_last_lost_byte[function] — test source atlib/quic/src/connection/stream/send.zig:517in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_13.3_acknowledged_STREAM_frames_release_bytes_in_offset_order[function] — test source atlib/quic/src/connection/stream/send.zig:443in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_13.3_lost_STREAM_bytes_go_out_again_first_without_spending_credit[function] — test source atlib/quic/src/connection/stream/send.zig:475in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_19.4_reset_reports_the_sent_final_size_and_discards_unsent_bytes[function] — test source atlib/quic/src/connection/stream/send.zig:563in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_2.2_send_buffer_maximum_and_maximum_plus_one[function] — test source atlib/quic/src/connection/stream/send.zig:418in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_3.1_an_acknowledged_FIN_reaches_Data_Recvd[function] — test source atlib/quic/src/connection/stream/send.zig:547in nearest public ownerlib.quic.src.connection.stream.send
Complete caller list for connection.stream.Send.init
10 direct callers.
lib.quic.src.connection.stream.send.test_RFC_9000_section_13.3_a_lost_FIN_goes_out_again_alone_or_on_the_last_lost_byte[function] — test source atlib/quic/src/connection/stream/send.zig:517in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_13.3_a_lost_RESET_STREAM_goes_out_again_unchanged_until_acknowledged[function] — test source atlib/quic/src/connection/stream/send.zig:583in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_13.3_acknowledged_STREAM_frames_release_bytes_in_offset_order[function] — test source atlib/quic/src/connection/stream/send.zig:443in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_13.3_an_acknowledged_copy_trims_the_lost_bytes_it_delivered[function] — test source atlib/quic/src/connection/stream/send.zig:501in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_13.3_lost_STREAM_bytes_go_out_again_first_without_spending_credit[function] — test source atlib/quic/src/connection/stream/send.zig:475in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_13.3_sent_range_records_maximum_and_maximum_plus_one[function] — test source atlib/quic/src/connection/stream/send.zig:463in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_19.4_reset_reports_the_sent_final_size_and_discards_unsent_bytes[function] — test source atlib/quic/src/connection/stream/send.zig:563in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_2.2_send_buffer_maximum_and_maximum_plus_one[function] — test source atlib/quic/src/connection/stream/send.zig:418in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_3.1_an_acknowledged_FIN_reaches_Data_Recvd[function] — test source atlib/quic/src/connection/stream/send.zig:547in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_4.1_chunks_stop_at_stream_and_connection_credit[function] — test source atlib/quic/src/connection/stream/send.zig:427in nearest public ownerlib.quic.src.connection.stream.send
Complete caller list for connection.stream.Send.write
10 direct callers.
lib.quic.src.connection.stream.send.test_RFC_9000_section_13.3_a_lost_FIN_goes_out_again_alone_or_on_the_last_lost_byte[function] — test source atlib/quic/src/connection/stream/send.zig:517in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_13.3_a_lost_RESET_STREAM_goes_out_again_unchanged_until_acknowledged[function] — test source atlib/quic/src/connection/stream/send.zig:583in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_13.3_acknowledged_STREAM_frames_release_bytes_in_offset_order[function] — test source atlib/quic/src/connection/stream/send.zig:443in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_13.3_an_acknowledged_copy_trims_the_lost_bytes_it_delivered[function] — test source atlib/quic/src/connection/stream/send.zig:501in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_13.3_lost_STREAM_bytes_go_out_again_first_without_spending_credit[function] — test source atlib/quic/src/connection/stream/send.zig:475in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_13.3_sent_range_records_maximum_and_maximum_plus_one[function] — test source atlib/quic/src/connection/stream/send.zig:463in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_19.4_reset_reports_the_sent_final_size_and_discards_unsent_bytes[function] — test source atlib/quic/src/connection/stream/send.zig:563in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_2.2_send_buffer_maximum_and_maximum_plus_one[function] — test source atlib/quic/src/connection/stream/send.zig:418in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_3.1_an_acknowledged_FIN_reaches_Data_Recvd[function] — test source atlib/quic/src/connection/stream/send.zig:547in nearest public ownerlib.quic.src.connection.stream.sendlib.quic.src.connection.stream.send.test_RFC_9000_section_4.1_chunks_stop_at_stream_and_connection_credit[function] — test source atlib/quic/src/connection/stream/send.zig:427in nearest public ownerlib.quic.src.connection.stream.send
Audit
| Definitions | 67 |
|---|---|
| Public names | 67 |
| Members | 77 |
| Version | 26.7.0 |
| Revision | daab053ee433 |