Skip to content

Commit

Permalink
Release 2.4.4
Browse files Browse the repository at this point in the history
- [API] Add lsquic_alpn2ver() to aid parsing Alt-Svc header.
- [BUGFIX] NULL dereference when H3 frame header would be split.
- [BUGFIX] Do not close fixed-size H3 frame prematurely.
- [BUGFIX] Allow PING frames in IETF mini conn.
- [BUGFIX] Mini conns: don't send any packets after receiving
  CONNECTION_CLOSE.
- [BUGFIX] Client migration: reserve slot for DCID from transport params.
- [BUGFIX] Allow max_early_data_size=0 -- early_data might not be there.
- [BUGFIX] Use an invalid stream number to reset BPT cache (zero is now a
  valid stream number).
- [SPEC] Use FINAL_SIZE_ERROR when FIN mismatch is detected.
- [OPTIMIZATION] Closed connection only gets one chance to send packets.
- [OPTIMIZATION] Flush headers stream before packetizing stream data.
- [OPTIMIZATION] process QPACK encoder STREAM frames immediately.
- Update ls-qpack to v0.10.1.
  • Loading branch information
Dmitri Tikhonov committed Oct 8, 2019
1 parent 1245d2e commit 662de5e
Show file tree
Hide file tree
Showing 15 changed files with 388 additions and 57 deletions.
18 changes: 18 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
2019-10-08
- 2.4.4
- [API] Add lsquic_alpn2ver() to aid parsing Alt-Svc header.
- [BUGFIX] NULL dereference when H3 frame header would be split.
- [BUGFIX] Do not close fixed-size H3 frame prematurely.
- [BUGFIX] Allow PING frames in IETF mini conn.
- [BUGFIX] Mini conns: don't send any packets after receiving
CONNECTION_CLOSE.
- [BUGFIX] Client migration: reserve slot for DCID from transport params.
- [BUGFIX] Allow max_early_data_size=0 -- early_data might not be there.
- [BUGFIX] Use an invalid stream number to reset BPT cache (zero is now a
valid stream number).
- [SPEC] Use FINAL_SIZE_ERROR when FIN mismatch is detected.
- [OPTIMIZATION] Closed connection only gets one chance to send packets.
- [OPTIMIZATION] Flush headers stream before packetizing stream data.
- [OPTIMIZATION] process QPACK encoder STREAM frames immediately.
- Update ls-qpack to v0.10.1.

2019-09-30
- 2.4.3
- Add GQUIC versions to the list of h3 ALPNs for Alt-Svc header.
Expand Down
12 changes: 8 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ ENDIF()

MESSAGE(STATUS "Build type: ${CMAKE_BUILD_TYPE}")

OPTION(LSQUIC_FIU "Use Fault Injection in Userspace (FIU)" OFF)


IF (NOT MSVC)

Expand All @@ -35,18 +37,20 @@ IF(CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9.3)
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -Wno-missing-field-initializers")
ENDIF()

IF(LSQUIC_FIU)
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -DFIU_ENABLE=1")
SET(LIBS ${LIBS} fiu)
ENDIF()

IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -O0 -g3")
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -Werror")
IF(CMAKE_C_COMPILER MATCHES "clang" AND
NOT "$ENV{TRAVIS}" MATCHES "^true$")
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -fsanitize=address")
ENDIF()
# Uncomment to enable fault injection testing via libfiu:
#SET (MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -DFIU_ENABLE=1")
# Uncomment to enable cleartext protocol mode (no crypto):
#SET (MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -DLSQUIC_ENABLE_HANDSHAKE_DISABLE=1")
#SET(LIBS ${LIBS} fiu)
ELSE()
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -O3 -g0")
# Comment out the following line to compile out debug messages:
Expand Down Expand Up @@ -187,7 +191,7 @@ ENDIF()
IF (CMAKE_SYSTEM_NAME STREQUAL Windows)
FIND_LIBRARY(EVENT_LIB event)
ELSE()
FIND_LIBRARY(EVENT_LIB libevent.a)
FIND_LIBRARY(EVENT_LIB libevent.a libevent.so)
ENDIF()
IF(EVENT_LIB)
MESSAGE(STATUS "Found event: ${EVENT_LIB}")
Expand Down
6 changes: 5 additions & 1 deletion include/lsquic.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ extern "C" {

#define LSQUIC_MAJOR_VERSION 2
#define LSQUIC_MINOR_VERSION 4
#define LSQUIC_PATCH_VERSION 3
#define LSQUIC_PATCH_VERSION 4

/**
* Engine flags:
Expand Down Expand Up @@ -1505,6 +1505,10 @@ lsquic_conn_crypto_cipher (const lsquic_conn_t *c);
enum lsquic_version
lsquic_str2ver (const char *str, size_t len);

/** Translate ALPN (e.g. "h3", "h3-23", "h3-Q046") to LSQUIC enum */
enum lsquic_version
lsquic_alpn2ver (const char *alpn, size_t len);

/**
* This function closes all mini connections and marks all full connection
* as going away. In server mode, this also causes the engine to stop
Expand Down
34 changes: 34 additions & 0 deletions src/liblsquic/gen-verstrs.pl
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
*/
#include <assert.h>
#include <string.h>
#include "lsquic.h"
Expand Down Expand Up @@ -127,4 +128,37 @@
C_CODE
print OUT <<'C_CODE';
enum lsquic_version
lsquic_alpn2ver (const char *alpn, size_t len)
{
static const struct el {
size_t len;
char alpn[10];
enum lsquic_version version;
} map[] = {
C_CODE
for ($i = 0; $i < @versions; ++$i) {
print OUT " {sizeof(\"h3-Q0$versions[$i]\")-1,\"h3-Q0$versions[$i]\", $enums[$i]},\n";
}
for ($i = 0; $i < @draft_versions; ++$i) {
print OUT " {sizeof(\"h3-$draft_versions[$i]\")-1,\"h3-$draft_versions[$i]\", LSQVER_ID$draft_versions[$i]},\n";
}
print OUT <<'C_CODE';
};
const struct el *el;
if (alpn)
for (el = map; el < map + sizeof(map) / sizeof(map[0]); ++el)
if (el->len == len && 0 == strncmp(el->alpn, alpn, len))
return el->version;
return -1;
}
C_CODE
close OUT;
7 changes: 6 additions & 1 deletion src/liblsquic/lsquic_enc_sess_ietf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1154,8 +1154,13 @@ iquic_new_session_cb (SSL *ssl, SSL_SESSION *session)
assert(enc_sess->esi_enpub->enp_stream_if->on_zero_rtt_info);

max_early_data_size = SSL_SESSION_get_max_early_data_size(session);
if (0xFFFFFFFFu != max_early_data_size)
if (max_early_data_size && 0xFFFFFFFFu != max_early_data_size)
{
/* XXX We do not catch the case when early_data extension is present
* and max_early_data_size is set to zero, which is an invalid value.
* This is because there is no way to check this using existing
* BoringSSL APIs.
*/
/* See [draft-ietf-quic-tls-23], Section 4.5 */
LSQ_INFO("max_early_data_size=0x%X, protocol violation",
max_early_data_size);
Expand Down
5 changes: 4 additions & 1 deletion src/liblsquic/lsquic_engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -1922,7 +1922,10 @@ coi_reheap (struct conns_out_iter *iter, lsquic_engine_t *engine)
{
TAILQ_REMOVE(&iter->coi_active_list, conn, cn_next_out);
conn->cn_flags &= ~LSCONN_COI_ACTIVE;
lsquic_mh_insert(iter->coi_heap, conn, conn->cn_last_sent);
if ((conn->cn_flags & CONN_REF_FLAGS) != LSCONN_HAS_OUTGOING)
lsquic_mh_insert(iter->coi_heap, conn, conn->cn_last_sent);
else /* Closed connection gets one shot at sending packets */
(void) engine_decref_conn(engine, conn, LSCONN_HAS_OUTGOING);
}
while ((conn = TAILQ_FIRST(&iter->coi_inactive_list)))
{
Expand Down
41 changes: 41 additions & 0 deletions src/liblsquic/lsquic_full_conn_ietf.c
Original file line number Diff line number Diff line change
Expand Up @@ -4507,6 +4507,12 @@ process_stream_frame (struct ietf_full_conn *conn,
return 0;
}

/* Don't wait for the regular on_read dispatch in order to save an
* unnecessary blocked/unblocked sequence.
*/
if ((conn->ifc_flags & IFC_HTTP) && conn->ifc_qdh.qdh_enc_sm_in == stream)
lsquic_stream_dispatch_read_events(conn->ifc_qdh.qdh_enc_sm_in);

return parsed_len;
}

Expand Down Expand Up @@ -4809,6 +4815,30 @@ retire_dcids_prior_to (struct ietf_full_conn *conn, unsigned retire_prior_to)
}


/* We need to be able to allocate a DCE slot to begin migration or to retire
* the DCID in transport parameters.
*/
static int
must_reserve_one_dce_slot (struct ietf_full_conn *conn)
{
struct lsquic_conn *const lconn = &conn->ifc_conn;
const struct transport_params *params;

if (conn->ifc_flags & IFC_SERVER)
return 0;

if (lsquic_send_ctl_1rtt_acked(&conn->ifc_send_ctl))
return 0;

params = lconn->cn_esf.i->esfi_get_peer_transport_params(
lconn->cn_enc_session);
if (params) /* Just in case */
return !!(params->tp_flags & (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6));
else
return 0;
}


static unsigned
process_new_connection_id_frame (struct ietf_full_conn *conn,
struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len)
Expand Down Expand Up @@ -4883,6 +4913,16 @@ process_new_connection_id_frame (struct ietf_full_conn *conn,

if (dce)
{
if (must_reserve_one_dce_slot(conn))
{
for (el = dce + 1; el < DCES_END(conn) && *el; ++el)
;
if (el == DCES_END(conn))
{
action_str = "Ignored (last slot reserved for migration)";
goto end;
}
}
*dce = lsquic_malo_get(conn->ifc_pub.mm->malo.dcid_elem);
if (*dce)
{
Expand All @@ -4901,6 +4941,7 @@ process_new_connection_id_frame (struct ietf_full_conn *conn,
else
action_str = "Ignored (no slots available)";

end:
LSQ_DEBUGC("Got new connection ID from peer: seq=%"PRIu64"; "
"cid: %"CID_FMT". %s.", seqno, CID_BITS(&cid), action_str);
return parsed_len;
Expand Down
34 changes: 25 additions & 9 deletions src/liblsquic/lsquic_mini_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,24 @@ process_blocked_frame (struct mini_conn *mc, lsquic_packet_in_t *packet_in,
}


static mconn_packno_set_t
drop_packets_out (struct mini_conn *mc)
{
struct lsquic_packet_out *packet_out;
mconn_packno_set_t in_flight = 0;

while ((packet_out = TAILQ_FIRST(&mc->mc_packets_out)))
{
TAILQ_REMOVE(&mc->mc_packets_out, packet_out, po_next);
if (packet_out->po_flags & PO_SENT)
in_flight |= MCONN_PACKET_MASK(packet_out->po_packno);
mini_destroy_packet(mc, packet_out);
}

return in_flight;
}


static unsigned
process_connection_close_frame (struct mini_conn *mc,
lsquic_packet_in_t *packet_in, const unsigned char *p, size_t len)
Expand All @@ -350,6 +368,8 @@ process_connection_close_frame (struct mini_conn *mc,
uint16_t reason_len;
uint8_t reason_off;
int parsed_len;

(void) drop_packets_out(mc);
parsed_len = mc->mc_conn.cn_pf->pf_parse_connect_close_frame(p, len,
NULL, &error_code, &reason_len, &reason_off);
if (parsed_len < 0)
Expand Down Expand Up @@ -1700,8 +1720,7 @@ mini_conn_ci_destroy (struct lsquic_conn *lconn)
assert(!(lconn->cn_flags & LSCONN_HASHED));
struct mini_conn *mc = (struct mini_conn *) lconn;
lsquic_packet_in_t *packet_in;
lsquic_packet_out_t *packet_out;
mconn_packno_set_t still_deferred = 0, in_flight = 0;
mconn_packno_set_t still_deferred = 0, in_flight;
enum lsq_log_level log_level;
#if LSQUIC_RECORD_INORD_HIST
char inord_str[0x100];
Expand All @@ -1717,13 +1736,10 @@ mini_conn_ci_destroy (struct lsquic_conn *lconn)
still_deferred |= MCONN_PACKET_MASK(packet_in->pi_packno);
lsquic_packet_in_put(&mc->mc_enpub->enp_mm, packet_in);
}
while ((packet_out = TAILQ_FIRST(&mc->mc_packets_out)))
{
TAILQ_REMOVE(&mc->mc_packets_out, packet_out, po_next);
if (packet_out->po_flags & PO_SENT)
in_flight |= MCONN_PACKET_MASK(packet_out->po_packno);
mini_destroy_packet(mc, packet_out);
}
if (TAILQ_EMPTY(&mc->mc_packets_out))
in_flight = ~0ull; /* Indicates that packets were dropped before */
else
in_flight = drop_packets_out(mc);
if (mc->mc_conn.cn_enc_session)
mc->mc_conn.cn_esf.g->esf_destroy(mc->mc_conn.cn_enc_session);
log_level = warning_is_warranted(mc) ? LSQ_LOG_WARN : LSQ_LOG_DEBUG;
Expand Down
43 changes: 40 additions & 3 deletions src/liblsquic/lsquic_mini_conn_ietf.c
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,42 @@ imico_process_ack_frame (IMICO_PROC_FRAME_ARGS)
}


static unsigned
imico_process_ping_frame (IMICO_PROC_FRAME_ARGS)
{
LSQ_DEBUG("got a PING frame, do nothing");
return 1;
}


static unsigned
imico_process_connection_close_frame (IMICO_PROC_FRAME_ARGS)
{
struct lsquic_packet_out *packet_out;
uint64_t error_code;
uint16_t reason_len;
uint8_t reason_off;
int parsed_len, app_error;

while ((packet_out = TAILQ_FIRST(&conn->imc_packets_out)))
{
TAILQ_REMOVE(&conn->imc_packets_out, packet_out, po_next);
imico_destroy_packet(conn, packet_out);
}
conn->imc_flags |= IMC_CLOSE_RECVD;
parsed_len = conn->imc_conn.cn_pf->pf_parse_connect_close_frame(p, len,
&app_error, &error_code, &reason_len, &reason_off);
if (parsed_len < 0)
return 0;
EV_LOG_CONNECTION_CLOSE_FRAME_IN(LSQUIC_LOG_CONN_ID, error_code,
(int) reason_len, (const char *) p + reason_off);
LSQ_INFO("Received CONNECTION_CLOSE frame (%s-level code: %"PRIu64"; "
"reason: %.*s)", app_error ? "application" : "transport",
error_code, (int) reason_len, (const char *) p + reason_off);
return 0; /* This shuts down the connection */
}


static unsigned
imico_process_invalid_frame (IMICO_PROC_FRAME_ARGS)
{
Expand All @@ -814,15 +850,15 @@ static unsigned (*const imico_process_frames[N_QUIC_FRAMES])
[QUIC_FRAME_STREAM] = imico_process_stream_frame,
[QUIC_FRAME_CRYPTO] = imico_process_crypto_frame,
[QUIC_FRAME_ACK] = imico_process_ack_frame,
[QUIC_FRAME_PING] = imico_process_ping_frame,
[QUIC_FRAME_CONNECTION_CLOSE] = imico_process_connection_close_frame,
/* XXX: Some of them are invalid, while others are unexpected. We treat
* them the same: handshake cannot proceed.
*/
[QUIC_FRAME_RST_STREAM] = imico_process_invalid_frame,
[QUIC_FRAME_CONNECTION_CLOSE] = imico_process_invalid_frame,
[QUIC_FRAME_MAX_DATA] = imico_process_invalid_frame,
[QUIC_FRAME_MAX_STREAM_DATA] = imico_process_invalid_frame,
[QUIC_FRAME_MAX_STREAMS] = imico_process_invalid_frame,
[QUIC_FRAME_PING] = imico_process_invalid_frame,
[QUIC_FRAME_BLOCKED] = imico_process_invalid_frame,
[QUIC_FRAME_STREAM_BLOCKED] = imico_process_invalid_frame,
[QUIC_FRAME_STREAMS_BLOCKED] = imico_process_invalid_frame,
Expand Down Expand Up @@ -1422,7 +1458,8 @@ ietf_mini_conn_ci_tick (struct lsquic_conn *lconn, lsquic_time_t now)

if (conn->imc_flags & IMC_ERROR)
{
imico_generate_conn_close(conn);
if (!(conn->imc_flags & IMC_CLOSE_RECVD))
imico_generate_conn_close(conn);
tick |= TICK_CLOSE;
}
else if (conn->imc_flags & IMC_HSK_OK)
Expand Down
1 change: 1 addition & 0 deletions src/liblsquic/lsquic_mini_conn_ietf.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ struct ietf_mini_conn
IMC_BAD_TRANS_PARAMS = 1 << 16,
IMC_ADDR_VALIDATED = 1 << 17,
IMC_HSK_PACKET_SENT = 1 << 18,
IMC_CLOSE_RECVD = 1 << 19,
} imc_flags;
struct mini_crypto_stream imc_streams[N_ENC_LEVS];
void *imc_stream_ps[N_ENC_LEVS];
Expand Down
11 changes: 1 addition & 10 deletions src/liblsquic/lsquic_send_ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ lsquic_send_ctl_init (lsquic_send_ctl_t *ctl, struct lsquic_alarmset *alset,
sizeof(ctl->sc_buffered_packets[0]); ++i)
TAILQ_INIT(&ctl->sc_buffered_packets[i].bpq_packets);
ctl->sc_max_packno_bits = PACKNO_BITS_2; /* Safe value before verneg */
ctl->sc_cached_bpt.stream_id = UINT64_MAX;
}


Expand Down Expand Up @@ -2347,16 +2348,6 @@ lsquic_send_ctl_get_packet_for_stream (lsquic_send_ctl_t *ctl,
}



int
lsquic_send_ctl_buffered_and_same_prio_as_headers (struct lsquic_send_ctl *ctl,
const struct lsquic_stream *stream)
{
return !lsquic_send_ctl_schedule_stream_packets_immediately(ctl)
&& BPT_HIGHEST_PRIO == send_ctl_lookup_bpt(ctl, stream);
}


#ifdef NDEBUG
static
#elif __GNUC__
Expand Down
Loading

0 comments on commit 662de5e

Please sign in to comment.