Line data Source code
1 : #include "fd_quic_ack_tx.h"
2 : #include "fd_quic_private.h"
3 :
4 : #include "fd_quic_proto.h"
5 : #include "fd_quic_proto.c"
6 :
7 : static inline int
8 : fd_quic_range_can_extend( fd_quic_range_t const * range,
9 81544654 : ulong idx ) {
10 81544654 : return idx+1UL >= range->offset_lo && idx <= range->offset_hi;
11 81544654 : }
12 :
13 : static inline int
14 : fd_quic_range_extend( fd_quic_range_t * range,
15 81220138 : ulong idx ) {
16 81220138 : int lo_decreased = idx < range->offset_lo;
17 81220138 : int hi_increased = idx >= range->offset_hi;
18 81220138 : range->offset_lo = fd_ulong_min( range->offset_lo, idx );
19 81220138 : range->offset_hi = fd_ulong_max( range->offset_hi, idx+1UL );
20 81220138 : return lo_decreased || hi_increased;
21 81220138 : }
22 :
23 : int
24 : fd_quic_ack_pkt( fd_quic_ack_gen_t * gen,
25 : ulong pkt_number,
26 : uint enc_level,
27 81544660 : ulong now ) {
28 :
29 81544660 : if( pkt_number == FD_QUIC_PKT_NUM_UNUSED ) return FD_QUIC_ACK_TX_NOOP;
30 :
31 : /* Can we merge pkt_number into the most recent ACK? */
32 81544654 : uint cached_seq = gen->head - 1U;
33 81544654 : fd_quic_ack_t * cached_ack = fd_quic_ack_queue_ele( gen, cached_seq );
34 81544654 : if( ( enc_level == cached_ack->enc_level ) &
35 81544654 : fd_quic_range_can_extend( &cached_ack->pkt_number, pkt_number ) ) {
36 :
37 : /* update timestamp */
38 81220138 : if( pkt_number >= cached_ack->pkt_number.offset_hi ) {
39 81220126 : cached_ack->ts = now;
40 81220126 : }
41 :
42 : /* add packet number to existing range */
43 81220138 : int changed = fd_quic_range_extend( &cached_ack->pkt_number, pkt_number );
44 :
45 : /* re-enqueue most recent ACK for sending */
46 81220138 : if( changed && gen->head==gen->tail ) {
47 233465 : gen->tail = cached_seq;
48 233465 : }
49 :
50 81220138 : FD_ACK_DEBUG( FD_LOG_DEBUG(( "gen=%p queue ACK for enc=%u pkt_num=%lu range=[%lu,%lu) seq=%u (merged)",
51 81220138 : (void *)gen, enc_level, pkt_number, cached_ack->pkt_number.offset_lo, cached_ack->pkt_number.offset_hi, cached_seq )); )
52 81220138 : return FD_QUIC_ACK_TX_MERGED;
53 :
54 81220138 : }
55 :
56 : /* Attempt to allocate another ACK queue entry */
57 324516 : if( gen->head - gen->tail >= FD_QUIC_ACK_QUEUE_CNT ) {
58 3 : FD_DEBUG( FD_LOG_DEBUG(( "ACK queue overflow! (excessive reordering)" )); )
59 3 : return FD_QUIC_ACK_TX_ENOSPC;
60 3 : }
61 :
62 : /* Start new pending ACK */
63 324513 : FD_ACK_DEBUG( FD_LOG_DEBUG(( "gen=%p queue ACK for enc=%u pkt_num=%lu seq=%u",
64 324513 : (void *)gen, enc_level, pkt_number, gen->head )); )
65 324513 : fd_quic_ack_t * next_ack = fd_quic_ack_queue_ele( gen, gen->head );
66 324513 : *next_ack = (fd_quic_ack_t) {
67 324513 : .pkt_number = { .offset_lo = pkt_number, .offset_hi = pkt_number+1UL },
68 324513 : .enc_level = (uchar)enc_level,
69 324513 : .ts = now
70 324513 : };
71 324513 : gen->head += 1U;
72 324513 : return FD_QUIC_ACK_TX_NEW;
73 324516 : }
74 :
75 : void
76 : fd_quic_ack_gen_abandon_enc_level( fd_quic_ack_gen_t * gen,
77 24096 : uint enc_level ) {
78 36144 : for( ; gen->tail != gen->head; gen->tail++ ) {
79 12048 : fd_quic_ack_t const * ack = fd_quic_ack_queue_ele( gen, gen->tail );
80 12048 : if( ack->enc_level > enc_level ) break;
81 12048 : FD_DEBUG( FD_LOG_DEBUG(( "gen=%p discard ACK for enc=%u range=[%lu,%lu) seq=%u",
82 12048 : (void *)gen, enc_level, ack->pkt_number.offset_lo, ack->pkt_number.offset_hi, gen->tail )); )
83 12048 : }
84 24096 : }
85 :
86 : extern ulong
87 : fd_quic_encode_ack_frame( uchar * buf,
88 : ulong sz,
89 : fd_quic_ack_frame_t * frame );
90 :
91 : uchar *
92 : fd_quic_gen_ack_frames( fd_quic_ack_gen_t * gen,
93 : uchar * payload_ptr,
94 : uchar * payload_end,
95 : uint enc_level,
96 : ulong now,
97 12902948 : float tick_per_us ) {
98 :
99 12902948 : FD_ACK_DEBUG( FD_LOG_DEBUG(( "[ACK gen] elicited=%d", gen->is_elicited )); )
100 : /* Never generate an ACK frame if no ACK-eliciting packet is pending.
101 : This prevents an infinite ACK loop. */
102 12902948 : if( !gen->is_elicited ) return payload_ptr;
103 :
104 : /* Attempt to send all ACK ranges */
105 251544 : ulong ranges_sent = 0UL;
106 497049 : for( ; gen->tail != gen->head; gen->tail++ ) {
107 245529 : fd_quic_ack_t * ack = fd_quic_ack_queue_ele( gen, gen->tail );
108 245529 : if( ack->enc_level != enc_level ) {
109 6 : FD_ACK_DEBUG( FD_LOG_DEBUG(( "need encryption level %u for ACKs but have %u", ack->enc_level, enc_level )); )
110 6 : break;
111 6 : }
112 :
113 245523 : ulong ack_delay_ticks = fd_ulong_sat_sub( now, ack->ts );
114 245523 : ulong ack_delay_us = (ulong)( (float)ack_delay_ticks / tick_per_us );
115 :
116 245523 : if( FD_UNLIKELY( ack->pkt_number.offset_lo == ack->pkt_number.offset_hi ) ) continue;
117 245523 : fd_quic_ack_frame_t ack_frame = {
118 245523 : .type = 0x02, /* type 0x02 is the base ack, 0x03 indicates ECN */
119 245523 : .largest_ack = ack->pkt_number.offset_hi - 1U,
120 245523 : .ack_delay = ack_delay_us,
121 245523 : .ack_range_count = 0, /* no fragments */
122 245523 : .first_ack_range = ack->pkt_number.offset_hi - ack->pkt_number.offset_lo - 1U,
123 245523 : };
124 245523 : ulong frame_sz = fd_quic_encode_ack_frame( payload_ptr, (ulong)( payload_end - payload_ptr ), &ack_frame );
125 245523 : if( FD_UNLIKELY( frame_sz==FD_QUIC_ENCODE_FAIL ) ) {
126 18 : FD_DEBUG( FD_LOG_DEBUG(( "insufficient buffer space to send ACK" )); )
127 18 : break;
128 18 : }
129 245505 : payload_ptr += frame_sz;
130 245505 : ranges_sent += 1UL;
131 245505 : FD_ACK_DEBUG( FD_LOG_DEBUG(( "gen=%p sending ACK enc=%u range=[%lu,%lu) seq=%u sz=%lu",
132 245505 : (void *)gen, enc_level, ack->pkt_number.offset_lo, ack->pkt_number.offset_hi, gen->tail, frame_sz )); )
133 245505 : }
134 :
135 : /* If all frames were flushed, reset status bits. */
136 251544 : if( gen->head == gen->tail ) {
137 251520 : gen->is_elicited = 0;
138 251520 : } else {
139 24 : FD_ACK_DEBUG( FD_LOG_DEBUG(( "Not all ACK frames were flushed" )); )
140 24 : }
141 :
142 251544 : int const flushed = !gen->is_elicited;
143 251544 : FD_DTRACE_PROBE_3( fd_quic_gen_ack_frames, enc_level, ranges_sent, flushed );
144 :
145 251544 : return payload_ptr;
146 12902948 : }
|