Skip to content

Commit

Permalink
quic: accept streams before handshake confirmed
Browse files Browse the repository at this point in the history
Fixes a bug that causes connections to break if the client eagerly
sends stream data.
  • Loading branch information
riptl authored and ripatel-fd committed Dec 22, 2024
1 parent ed0fef7 commit 2b052f9
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 9 deletions.
17 changes: 8 additions & 9 deletions src/waltz/quic/fd_quic.c
Original file line number Diff line number Diff line change
Expand Up @@ -2732,8 +2732,7 @@ void
fd_quic_tls_cb_handshake_complete( fd_quic_tls_hs_t * hs,
void * context ) {
(void)hs;
fd_quic_conn_t * conn = (fd_quic_conn_t*)context;
fd_quic_conn_stream_rx_t * srx = conn->srx;
fd_quic_conn_t * conn = (fd_quic_conn_t *)context;

/* need to send quic handshake completion */
switch( conn->state ) {
Expand All @@ -2751,13 +2750,6 @@ fd_quic_tls_cb_handshake_complete( fd_quic_tls_hs_t * hs,
}
conn->handshake_complete = 1;
conn->state = FD_QUIC_CONN_STATE_HANDSHAKE_COMPLETE;

if( conn->server ) {
/* Remove flow control limits */
srx->rx_sup_stream_id = (1UL<<60) + FD_QUIC_STREAM_TYPE_UNI_CLIENT;
srx->rx_max_data = (1UL<<62UL) - 1UL;
}

return;

default:
Expand Down Expand Up @@ -4361,6 +4353,13 @@ fd_quic_conn_create( fd_quic_t * quic,
srx->rx_tot_data = 0;
srx->rx_streams_active = 0L;

if( state->transport_params.initial_max_streams_uni_present ) {
srx->rx_sup_stream_id = (state->transport_params.initial_max_streams_uni<<2) + FD_QUIC_STREAM_TYPE_UNI_CLIENT;
}
if( state->transport_params.initial_max_data ) {
srx->rx_max_data = state->transport_params.initial_max_data;
}

/* points to free tx space */
conn->tx_ptr = conn->tx_buf;
conn->tx_sz = sizeof( conn->tx_buf );
Expand Down
40 changes: 40 additions & 0 deletions src/waltz/quic/tests/test_quic_conformance.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,45 @@ test_quic_pktnum_skip( fd_quic_sandbox_t * sandbox,

}

__attribute__((noinline)) void
test_quic_conn_initial_limits( fd_quic_sandbox_t * sandbox,
fd_rng_t * rng ) {
(void)rng;

fd_quic_sandbox_init( sandbox, FD_QUIC_ROLE_SERVER );
fd_quic_transport_params_t * params = &fd_quic_get_state( sandbox->quic )->transport_params;
params->initial_max_data = 987654321UL;
params->initial_max_streams_uni = 8192UL;

/* Create a connection that's not yet established */
ulong our_conn_id = 1234UL;
fd_quic_conn_id_t peer_conn_id = fd_quic_conn_id_new( &our_conn_id, 8UL );
uint dst_ip_addr = FD_IP4_ADDR( 192, 168, 1, 1 );
ushort dst_udp_port = 8080;
fd_quic_conn_t * conn = fd_quic_conn_create( sandbox->quic, our_conn_id, &peer_conn_id, dst_ip_addr, dst_udp_port, 1 );
FD_TEST( conn );
FD_TEST( conn->state == FD_QUIC_CONN_STATE_HANDSHAKE );

/* Ensure stream frames are accepted
(Rationale: The application encryption level becomes available before
the handshake is confirmed; Quota would have been granted already via
QUIC transport params) */
uchar buf[ 1024 ];
fd_quic_stream_frame_t stream_frame =
{ .stream_id = FD_QUIC_STREAM_TYPE_UNI_CLIENT,
.length_opt = 1,
.length = 1UL };
ulong sz = fd_quic_encode_stream_frame( buf, sizeof(buf), &stream_frame );
FD_TEST( sz!=FD_QUIC_ENCODE_FAIL );
buf[ sz++ ] = '0';
fd_quic_sandbox_send_lone_frame( sandbox, conn, buf, sz );
FD_TEST( conn->state == FD_QUIC_CONN_STATE_HANDSHAKE ); /* conn not killed */

/* Double check RX limits */
FD_TEST( conn->srx->rx_sup_stream_id == 32770UL ); /* (8192<<2)+2 */
FD_TEST( conn->srx->rx_max_data == 987654321UL );
}

static __attribute__((noinline)) void
test_quic_parse_path_challenge( void ) {
fd_quic_path_challenge_frame_t path_challenge[1];
Expand Down Expand Up @@ -337,6 +376,7 @@ main( int argc,
test_quic_ping_frame ( sandbox, rng );
test_quic_server_alpn_fail ( sandbox, rng );
test_quic_pktnum_skip ( sandbox, rng );
test_quic_conn_initial_limits ( sandbox, rng );
test_quic_parse_path_challenge();

/* Wind down */
Expand Down

0 comments on commit 2b052f9

Please sign in to comment.