Skip to content

Commit

Permalink
Merge pull request #415 from h2o/kazuho/connection-close-in-all-epochs
Browse files Browse the repository at this point in the history
Send CONNECTION_CLOSE in all available epochs
  • Loading branch information
kazuho authored Nov 13, 2020
2 parents 3696bde + 0cfef38 commit e6e8069
Showing 1 changed file with 48 additions and 27 deletions.
75 changes: 48 additions & 27 deletions lib/quicly.c
Original file line number Diff line number Diff line change
Expand Up @@ -3873,32 +3873,53 @@ size_t quicly_send_retry(quicly_context_t *ctx, ptls_aead_context_t *token_encry
return ret == 0 ? buf.off : SIZE_MAX;
}

static int send_handshake_flow(quicly_conn_t *conn, size_t epoch, quicly_send_context_t *s, int ack_only, int send_probe)
static struct st_quicly_pn_space_t *setup_send_space(quicly_conn_t *conn, size_t epoch, quicly_send_context_t *s)
{
struct st_quicly_pn_space_t *ack_space = NULL;
int ret = 0;
struct st_quicly_pn_space_t *space = NULL;

switch (epoch) {
case QUICLY_EPOCH_INITIAL:
if (conn->initial == NULL || (s->current.cipher = &conn->initial->cipher.egress)->aead == NULL)
return 0;
return NULL;
s->current.first_byte = QUICLY_PACKET_TYPE_INITIAL;
ack_space = &conn->initial->super;
space = &conn->initial->super;
break;
case QUICLY_EPOCH_HANDSHAKE:
if (conn->handshake == NULL || (s->current.cipher = &conn->handshake->cipher.egress)->aead == NULL)
return 0;
return NULL;
s->current.first_byte = QUICLY_PACKET_TYPE_HANDSHAKE;
ack_space = &conn->handshake->super;
space = &conn->handshake->super;
break;
case QUICLY_EPOCH_0RTT:
case QUICLY_EPOCH_1RTT:
if (conn->application == NULL || conn->application->cipher.egress.key.header_protection == NULL)
return NULL;
if ((epoch == QUICLY_EPOCH_0RTT) == conn->application->one_rtt_writable)
return NULL;
s->current.cipher = &conn->application->cipher.egress.key;
s->current.first_byte = epoch == QUICLY_EPOCH_0RTT ? QUICLY_PACKET_TYPE_0RTT : QUICLY_QUIC_BIT;
space = &conn->application->super;
break;
default:
assert(!"logic flaw");
return 0;
break;
}

return space;
}

static int send_handshake_flow(quicly_conn_t *conn, size_t epoch, quicly_send_context_t *s, int ack_only, int send_probe)
{
struct st_quicly_pn_space_t *space;
int ret = 0;

/* setup send epoch, or return if it's impossible to send in this epoch */
if ((space = setup_send_space(conn, epoch, s)) == NULL)
return 0;

/* send ACK */
if (ack_space != NULL && (ack_space->unacked_count != 0 || send_probe))
if ((ret = send_ack(conn, ack_space, s)) != 0)
if (space != NULL && (space->unacked_count != 0 || send_probe))
if ((ret = send_ack(conn, space, s)) != 0)
goto Exit;

if (!ack_only) {
Expand Down Expand Up @@ -3927,12 +3948,16 @@ static int send_handshake_flow(quicly_conn_t *conn, size_t epoch, quicly_send_co
return ret;
}

static int send_connection_close(quicly_conn_t *conn, quicly_send_context_t *s)
static int send_connection_close(quicly_conn_t *conn, size_t epoch, quicly_send_context_t *s)
{
uint64_t error_code, offending_frame_type;
const char *reason_phrase;
int ret;

/* setup send epoch, or return if it's impossible to send in this epoch */
if (setup_send_space(conn, epoch, s) == NULL)
return 0;

/* determine the payload, masking the application error when sending the frame using an unauthenticated epoch */
error_code = conn->egress.connection_close.error_code;
offending_frame_type = conn->egress.connection_close.frame_type;
Expand Down Expand Up @@ -4157,9 +4182,9 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s)
if ((ret = send_handshake_flow(conn, QUICLY_EPOCH_HANDSHAKE, s, ack_only, min_packets_to_send != 0)) != 0)
goto Exit;

/* send encrypted frames */
if (conn->application != NULL && (s->current.cipher = &conn->application->cipher.egress.key)->header_protection != NULL) {
s->current.first_byte = conn->application->one_rtt_writable ? QUICLY_QUIC_BIT : QUICLY_PACKET_TYPE_0RTT;
/* setup 0-RTT or 1-RTT send context (as the availability of the two epochs are mutually exclusive, we can try 1-RTT first as an
* optimization), then send application data if that succeeds */
if (setup_send_space(conn, QUICLY_EPOCH_1RTT, s) != NULL || setup_send_space(conn, QUICLY_EPOCH_0RTT, s) != NULL) {
/* acks */
if (conn->application->one_rtt_writable && conn->egress.send_ack_at <= conn->stash.now &&
conn->application->super.unacked_count != 0) {
Expand Down Expand Up @@ -4346,20 +4371,14 @@ int quicly_send(quicly_conn_t *conn, quicly_address_t *dest, quicly_address_t *s
}
}
if (conn->super.state == QUICLY_STATE_CLOSING && conn->egress.send_ack_at <= conn->stash.now) {
destroy_all_streams(conn, 0, 0); /* delayed until the emission of CONNECTION_CLOSE frame to allow quicly_close to be
* called from a stream handler */
if (conn->application != NULL && conn->application->one_rtt_writable) {
s.current.cipher = &conn->application->cipher.egress.key;
s.current.first_byte = QUICLY_QUIC_BIT;
} else if (conn->handshake != NULL && (s.current.cipher = &conn->handshake->cipher.egress)->aead != NULL) {
s.current.first_byte = QUICLY_PACKET_TYPE_HANDSHAKE;
} else {
s.current.cipher = &conn->initial->cipher.egress;
assert(s.current.cipher->aead != NULL);
s.current.first_byte = QUICLY_PACKET_TYPE_INITIAL;
/* destroy all streams; doing so is delayed until the emission of CONNECTION_CLOSE frame to allow quicly_close to be
* called from a stream handler */
destroy_all_streams(conn, 0, 0);
/* send CONNECTION_CLOSE in all possible epochs */
for (size_t epoch = 0; epoch < QUICLY_NUM_EPOCHS; ++epoch) {
if ((ret = send_connection_close(conn, epoch, &s)) != 0)
goto Exit;
}
if ((ret = send_connection_close(conn, &s)) != 0)
goto Exit;
if ((ret = commit_send_packet(conn, &s, QUICLY_COMMIT_SEND_PACKET_MODE_SMALL)) != 0)
goto Exit;
}
Expand Down Expand Up @@ -5385,6 +5404,8 @@ static int handle_payload(quicly_conn_t *conn, size_t epoch, const uint8_t *_src
/* slow path */
--state.src;
if ((state.frame_type = quicly_decodev(&state.src, state.end)) == UINT64_MAX) {
state.frame_type =
QUICLY_FRAME_TYPE_PADDING; /* we cannot signal the offending frame type when failing to decode the frame type */
ret = QUICLY_TRANSPORT_ERROR_FRAME_ENCODING;
break;
}
Expand Down

0 comments on commit e6e8069

Please sign in to comment.