Skip to content

Commit 55400fd

Browse files
quic: fix scheduling misses, svc_schedule validates conn
reset next_timeout in svc_schedule fix retx timeout ticks/ns issue prep schedule in gen_frames CRIT if svc_timer_cnt != active_conn_cnt schedule idle_timeout from last_activity, not now test_quic_conformance: update for service heap fix test_quic_keep_alive
1 parent 61d56d8 commit 55400fd

File tree

7 files changed

+61
-18
lines changed

7 files changed

+61
-18
lines changed

src/waltz/quic/fd_quic.c

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,16 @@ fd_quic_svc_schedule1( fd_quic_conn_t * conn ) {
690690
fd_quic_svc_schedule( fd_quic_get_state(conn->quic)->svc_timers, conn );
691691
}
692692

693+
/* Validation Helper */
694+
static inline void
695+
svc_cnt_eq_active_conn( fd_quic_svc_timers_t * timers, fd_quic_t * quic ) {
696+
ulong const event_cnt = fd_quic_svc_cnt_events( timers );
697+
ulong const conn_cnt = quic->metrics.conn_active_cnt;
698+
if( FD_UNLIKELY( event_cnt != conn_cnt ) ) {
699+
FD_LOG_CRIT(( "only %lu out of %lu connections are in timer", event_cnt, conn_cnt ));
700+
}
701+
}
702+
693703
/* validates the free conn list doesn't cycle, point nowhere, leak, or point to live conn */
694704
static void
695705
fd_quic_conn_free_validate( fd_quic_t * quic ) {
@@ -2252,6 +2262,8 @@ fd_quic_process_quic_packet_v1( fd_quic_t * quic,
22522262
break;
22532263
}
22542264

2265+
fd_quic_svc_schedule( state->svc_timers, conn );
2266+
22552267
if( FD_UNLIKELY( rc == FD_QUIC_PARSE_FAIL ) ) {
22562268
FD_DEBUG( FD_LOG_DEBUG(( "Rejected packet (type=%d)", long_packet_type )); )
22572269
return FD_QUIC_PARSE_FAIL;
@@ -2268,6 +2280,9 @@ fd_quic_process_quic_packet_v1( fd_quic_t * quic,
22682280
ulong dst_conn_id = fd_ulong_load_8( cur_ptr+1 );
22692281
conn = fd_quic_conn_query( state->conn_map, dst_conn_id );
22702282
rc = fd_quic_handle_v1_one_rtt( quic, conn, pkt, cur_ptr, cur_sz );
2283+
2284+
fd_quic_svc_schedule( state->svc_timers, conn );
2285+
22712286
if( FD_UNLIKELY( rc == FD_QUIC_PARSE_FAIL ) ) {
22722287
return FD_QUIC_PARSE_FAIL;
22732288
}
@@ -2283,6 +2298,7 @@ fd_quic_process_quic_packet_v1( fd_quic_t * quic,
22832298
int ack_type = fd_quic_lazy_ack_pkt( quic, conn, pkt );
22842299
quic->metrics.ack_tx[ ack_type ]++;
22852300

2301+
/* fd_quic_lazy_ack_pkt may have prepped schedule */
22862302
fd_quic_svc_schedule( state->svc_timers, conn );
22872303

22882304
if( pkt->rtt_ack_time ) {
@@ -2462,6 +2478,7 @@ fd_quic_process_packet_impl( fd_quic_t * quic,
24622478
}
24632479

24642480
rc = fd_quic_process_quic_packet_v1( quic, &pkt, cur_ptr, cur_sz );
2481+
svc_cnt_eq_active_conn( state->svc_timers, quic );
24652482

24662483
/* 0UL means no progress, so fail */
24672484
if( FD_UNLIKELY( ( rc == FD_QUIC_PARSE_FAIL ) |
@@ -2491,6 +2508,7 @@ fd_quic_process_packet_impl( fd_quic_t * quic,
24912508
/* short header packet
24922509
only one_rtt packets currently have short headers */
24932510
fd_quic_process_quic_packet_v1( quic, &pkt, cur_ptr, cur_sz );
2511+
svc_cnt_eq_active_conn( state->svc_timers, quic );
24942512
}
24952513

24962514
void
@@ -2875,7 +2893,7 @@ fd_quic_svc_poll( fd_quic_t * quic,
28752893
max_idle_timeout value advertised by both endpoints." */
28762894
FD_DEBUG( FD_LOG_WARNING(("%s conn %p conn_idx: %u closing due to idle timeout (%g ms)",
28772895
conn->server?"SERVER":"CLIENT",
2878-
(void *)conn, conn->conn_idx, (double)fd_quic_ticks_to_us(conn->idle_timeout_ticks) / 1e3 )); )
2896+
(void *)conn, conn->conn_idx, (double)fd_quic_ticks_to_us( quic, conn->idle_timeout_ticks ) / 1e3 )); )
28792897

28802898
fd_quic_set_conn_state( conn, FD_QUIC_CONN_STATE_DEAD );
28812899
quic->metrics.conn_timeout_cnt++;
@@ -2909,7 +2927,7 @@ fd_quic_svc_poll( fd_quic_t * quic,
29092927
break;
29102928
default:
29112929
/* prep idle timeout or keep alive at idle timeout/2 */
2912-
fd_quic_svc_prep_schedule( conn, state->now + (conn->idle_timeout_ticks>>(quic->config.keep_alive)) );
2930+
fd_quic_svc_prep_schedule( conn, conn->last_activity + (conn->idle_timeout_ticks>>(quic->config.keep_alive)) );
29132931
fd_quic_svc_schedule( state->svc_timers, conn );
29142932
break;
29152933
}
@@ -2927,6 +2945,7 @@ fd_quic_service( fd_quic_t * quic ) {
29272945
long now_ticks = fd_tickcount();
29282946

29292947
fd_quic_svc_timers_t * timers = state->svc_timers;
2948+
svc_cnt_eq_active_conn( timers, quic );
29302949
fd_quic_svc_event_t next = fd_quic_svc_timers_next( timers, now, 1 /* pop */);
29312950
if( FD_UNLIKELY( next.conn == NULL ) ) {
29322951
return 0;
@@ -3513,6 +3532,8 @@ fd_quic_gen_frames( fd_quic_conn_t * conn,
35133532
}
35143533
}
35153534

3535+
fd_quic_svc_prep_schedule( conn, pkt_meta_tmpl->expiry );
3536+
35163537
return payload_ptr;
35173538
}
35183539

@@ -3576,7 +3597,8 @@ fd_quic_conn_tx( fd_quic_t * quic,
35763597
ulong now = fd_quic_get_state( quic )->now;
35773598

35783599
/* initialize expiry and tx_time */
3579-
fd_quic_pkt_meta_t pkt_meta_tmpl[1] = {{.expiry = now+500000000UL, .tx_time = now}};
3600+
ulong const retx_timeout = fd_quic_us_to_ticks( quic, 500000UL ); /* 500 ms */
3601+
fd_quic_pkt_meta_t pkt_meta_tmpl[1] = {{.expiry = now+retx_timeout, .tx_time = now}};
35803602
// pkt_meta_tmpl->expiry = fd_quic_calc_expiry( conn, now );
35813603
//ulong margin = (ulong)(conn->rtt->smoothed_rtt) + (ulong)(3 * conn->rtt->var_rtt);
35823604
//if( margin < pkt_meta->expiry ) {
@@ -3855,7 +3877,6 @@ fd_quic_conn_tx( fd_quic_t * quic,
38553877
void
38563878
fd_quic_conn_service( fd_quic_t * quic, fd_quic_conn_t * conn, ulong now ) {
38573879
(void)now;
3858-
conn->svc_meta.next_timeout = ULONG_MAX;
38593880

38603881
/* Send new rtt measurement probe? */
38613882
if( FD_UNLIKELY(now > conn->last_ack + (ulong)conn->rtt_period_ticks) ) {
@@ -3947,6 +3968,7 @@ fd_quic_conn_service( fd_quic_t * quic, fd_quic_conn_t * conn, ulong now ) {
39473968
case FD_QUIC_CONN_STATE_INVALID:
39483969
/* fall thru */
39493970
default:
3971+
FD_LOG_CRIT(( "invalid conn state %u", conn->state ));
39503972
return;
39513973
}
39523974

@@ -3972,12 +3994,6 @@ fd_quic_conn_free( fd_quic_t * quic,
39723994

39733995
fd_quic_state_t * state = fd_quic_get_state( quic );
39743996

3975-
/* no need to remove this connection from the events queue
3976-
free is called from two places:
3977-
fini - service will never be called again. All events are destroyed
3978-
service - removes event before calling free. Event only allowed to be
3979-
enqueued once */
3980-
39813997
/* remove all stream ids from map, and free stream */
39823998

39833999
/* remove used streams */
@@ -4034,12 +4050,12 @@ fd_quic_conn_free( fd_quic_t * quic,
40344050
}
40354051
conn->tls_hs = NULL;
40364052

4053+
/* remove from service queue */
40374054
fd_quic_svc_cancel( state->svc_timers, conn );
40384055

40394056
/* put connection back in free list */
40404057
conn->free_conn_next = state->free_conn_list;
40414058
state->free_conn_list = conn->conn_idx;
4042-
fd_quic_set_conn_state( conn, FD_QUIC_CONN_STATE_INVALID );
40434059

40444060
quic->metrics.conn_active_cnt--;
40454061

@@ -4066,7 +4082,6 @@ fd_quic_connect( fd_quic_t * quic,
40664082
}
40674083
}
40684084

4069-
40704085
fd_rng_t * rng = state->_rng;
40714086

40724087
/* create conn ids for us and them

src/waltz/quic/fd_quic_svc_q.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,7 @@ typedef fd_quic_svc_event_t fd_quic_svc_queue_prq_t;
1919

2020
ulong
2121
fd_quic_svc_timers_footprint( ulong max_conn ) {
22-
ulong offset = 0UL;
23-
offset = fd_ulong_align_up( offset, fd_quic_svc_queue_prq_align() );
24-
offset += fd_quic_svc_queue_prq_footprint( max_conn );
25-
return offset;
22+
return fd_quic_svc_queue_prq_footprint( max_conn );
2623
}
2724

2825
ulong
@@ -78,9 +75,19 @@ fd_quic_svc_cancel( fd_quic_svc_timers_t * timers,
7875
void
7976
fd_quic_svc_schedule( fd_quic_svc_timers_t * timers,
8077
fd_quic_conn_t * conn ) {
78+
79+
/* if conn null or invalid, do not schedule */
80+
if( FD_UNLIKELY( !conn || conn->state == FD_QUIC_CONN_STATE_INVALID ) ) {
81+
/* cleaner/safer to check in here for now. If function call overhead
82+
becomes a constraint, move check to caller */
83+
return;
84+
}
85+
8186
ulong idx = conn->svc_meta.idx;
8287
ulong expiry = conn->svc_meta.next_timeout;
8388

89+
conn->svc_meta.next_timeout = ULONG_MAX; /* reset next_timeout */
90+
8491
if( FD_UNLIKELY( idx != FD_QUIC_SVC_IDX_INVAL ) ) {
8592
/* find current expiry */
8693
fd_quic_svc_event_t * event = timers + idx;
@@ -95,6 +102,7 @@ fd_quic_svc_schedule( fd_quic_svc_timers_t * timers,
95102
conn->svc_meta.idx = FD_QUIC_SVC_IDX_INVAL;
96103
}
97104
}
105+
/* TODO: potential perf improvement combining remove and insert(?) */
98106

99107
/* insert new element */
100108
fd_quic_svc_event_t e = {
@@ -161,3 +169,8 @@ fd_quic_svc_get_event( fd_quic_svc_timers_t * timers,
161169
if( idx == FD_QUIC_SVC_IDX_INVAL ) return NULL;
162170
return timers + idx;
163171
}
172+
173+
ulong
174+
fd_quic_svc_cnt_events( fd_quic_svc_timers_t * timers ) {
175+
return fd_quic_svc_queue_prq_cnt( timers );
176+
}

src/waltz/quic/fd_quic_svc_q.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ fd_quic_svc_timers_init_conn( fd_quic_conn_t * conn );
5656

5757
/* fd_quic_svc_schedule schedules a connection timer.
5858
Uses conn->svc_meta.next_timeout as the expiry time.
59-
If already scheduled, keeps the earlier time. */
59+
If already scheduled, keeps the earlier time. Resets
60+
next_timeout to ULONG_MAX. */
6061
void
6162
fd_quic_svc_schedule( fd_quic_svc_timers_t * timers,
6263
fd_quic_conn_t * conn );
@@ -90,4 +91,10 @@ fd_quic_svc_event_t*
9091
fd_quic_svc_get_event( fd_quic_svc_timers_t * timers,
9192
fd_quic_conn_t * conn );
9293

94+
95+
/* fd_quic_svc_cnt_events returns the number of conns with active timers
96+
Primarily used for testing/validation. */
97+
ulong
98+
fd_quic_svc_cnt_events( fd_quic_svc_timers_t * timers );
99+
93100
#endif /* HEADER_fd_src_waltz_quic_fd_quic_svc_q_h */

src/waltz/quic/tests/fd_quic_sandbox.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,9 @@ fd_quic_sandbox_new_conn_established( fd_quic_sandbox_t * sandbox,
315315
conn->srx->rx_max_data_ackd = 0UL;
316316
conn->tx_initial_max_stream_data_uni = 0UL;
317317

318+
fd_quic_state_t * state = fd_quic_get_state( quic );
319+
fd_quic_svc_schedule( state->svc_timers, conn );
320+
318321
/* TODO set a realistic packet number */
319322

320323
return conn;

src/waltz/quic/tests/test_quic_conformance.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ test_quic_ping_frame( fd_quic_sandbox_t * sandbox,
120120
fd_quic_sandbox_init( sandbox, FD_QUIC_ROLE_SERVER );
121121
fd_quic_conn_t * conn = fd_quic_sandbox_new_conn_established( sandbox, rng );
122122
conn->ack_gen->is_elicited = 0;
123-
FD_TEST( conn->svc_meta.idx == FD_QUIC_SVC_IDX_INVAL );
123+
FD_TEST( conn->svc_meta.idx != FD_QUIC_SVC_IDX_INVAL );
124124

125125
uchar buf[1] = {0x01};
126126
fd_quic_sandbox_send_lone_frame( sandbox, conn, buf, sizeof(buf) );

src/waltz/quic/tests/test_quic_keep_alive.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ main( int argc, char ** argv ) {
129129
server_quic->config.idle_timeout = 1e7;
130130
client_quic->config.idle_timeout = 1e9;
131131

132+
server_quic->config.ack_delay = 1e6;
133+
client_quic->config.ack_delay = 1e6;
134+
132135
fd_quic_virtual_pair_t vp;
133136
fd_quic_virtual_pair_init( &vp, server_quic, client_quic );
134137

src/waltz/quic/tests/test_quic_svc_q.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ test_multiple_connections( fd_quic_svc_timers_t * timers,
105105
fd_quic_conn_t * conns[conn_cnt]; /* array of conn ptrs */
106106
for( uint i=0; i<conn_cnt; i++ ) {
107107
conns[i] = (fd_quic_conn_t *)(conn_base + i * conn_sz);
108+
conns[i]->state = FD_QUIC_CONN_STATE_ACTIVE;
108109
}
109110

110111
ulong now = 1000UL;
@@ -192,6 +193,7 @@ main( int argc, char ** argv ) {
192193

193194
{
194195
fd_quic_conn_t * conn = (fd_quic_conn_t *)create_mock_conns( &limits , 1);
196+
conn->state = FD_QUIC_CONN_STATE_ACTIVE;
195197
test_svc_schedule( timers, conn );
196198
test_svc_cancel( timers, conn );
197199
free( conn );

0 commit comments

Comments
 (0)