diff --git a/CHANGELOG b/CHANGELOG index 21574be..6d4e95f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,11 @@ +2020-03-02 + - 2.12.0 + - [FEATURE] QUIC timestamps extension. + - [API] New: ea_alpn that is used when not in HTTP mode. + - [BUGFIX] SNI is mandatory only for HTTP/3 and gQUIC. + - [BUGFIX] Benign double-free -- issue #110. + - [BUGFIX] Printing of transport parameters. + 2020-02-24 - 2.11.1 - [FEATURE] QUIC and HTTP/3 Internet Draft 27 support. diff --git a/docs/apiref.rst b/docs/apiref.rst index b88a66b..2457351 100644 --- a/docs/apiref.rst +++ b/docs/apiref.rst @@ -239,7 +239,7 @@ optional members. .. member:: struct ssl_ctx_st * (*ea_get_ssl_ctx)(void *peer_ctx) Get SSL_CTX associated with a peer context. Mandatory in server - mode. + mode. This is use for default values for SSL instantiation. .. member:: const struct lsquic_hset_if *ea_hsi_if .. member:: void *ea_hsi_ctx @@ -268,6 +268,8 @@ optional members. In a multi-process setup, it may be useful to observe the CID lifecycle. This optional set of callbacks makes it possible. +.. _apiref-engine-settings: + Engine Settings --------------- @@ -348,7 +350,7 @@ settings structure: .. member:: unsigned es_max_header_list_size This corresponds to SETTINGS_MAX_HEADER_LIST_SIZE - (RFC 7540, Section 6.5.2). 0 means no limit. Defaults + (:rfc:`7540#section-6.5.2`). 0 means no limit. Defaults to :func:`LSQUIC_DF_MAX_HEADER_LIST_SIZE`. .. member:: const char *es_ua @@ -685,6 +687,12 @@ settings structure: Default value is :macro:`LSQUIC_DF_DELAYED_ACKS` + .. member:: int es_timestamps + + Enable timestamps extension. Allowed values are 0 and 1. + + Default value is @ref LSQUIC_DF_TIMESTAMPS + To initialize the settings structure to library defaults, use the following convenience function: @@ -940,7 +948,7 @@ that the library uses to send packets. .. member:: int ecn - ECN: Valid values are 0 - 3. See RFC 3168. + ECN: Valid values are 0 - 3. See :rfc:`3168`. ECN may be set by IETF QUIC connections if ``es_ecn`` is set. @@ -1465,7 +1473,7 @@ fields yourself. In that case, the header set must be "read" from the stream vi Get header set associated with the stream. The header set is created by ``hsi_create_header_set()`` callback. After this call, the ownership of - the header set is trasnferred to the caller. + the header set is transferred to the caller. This call must precede calls to :func:`lsquic_stream_read()`, :func:`lsquic_stream_readv()`, and :func:`lsquic_stream_readf()`. diff --git a/docs/conf.py b/docs/conf.py index 030f4cb..b6a6442 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -24,9 +24,9 @@ copyright = u'2020, LiteSpeed Technologies' author = u'LiteSpeed Technologies' # The short X.Y version -version = u'2.11' +version = u'2.12' # The full version, including alpha/beta/rc tags -release = u'2.11.1' +release = u'2.12.0' # -- General configuration --------------------------------------------------- diff --git a/docs/gettingstarted.rst b/docs/gettingstarted.rst index 7e81d92..41fb09b 100644 --- a/docs/gettingstarted.rst +++ b/docs/gettingstarted.rst @@ -1,2 +1,71 @@ -Getting Started with LSQUIC -=========================== +Getting Started +=============== + +Supported Platforms +------------------- + +LSQUIC compiles and runs on Linux, FreeBSD, and Mac OS. It has been +tested on i386, x86_64, as well as Raspberry Pi. + +Windows support is on the TODO list. + +Dependencies +------------ + +LSQUIC library uses: + +- zlib_; +- BoringSSL_; and +- `ls-qpack`_ (as a Git submodule). + +The accompanying demo command-line tools use libevent_. + +What's in the box +----------------- + +- ``src/liblsquic`` -- the library +- ``test`` -- demo client and server programs +- ``test/unittests`` -- unit tests + +Building +-------- + +To build the library, follow instructions in the README_ file. + +Demo Examples +------------- + +Fetch Google home page: + +:: + + ./http_client -s www.google.com -p / -o version=Q050 + +Run your own server (it does not touch the filesystem, don't worry): + +:: + + ./http_server -c www.example.com,fullchain.pem,privkey.pem -s 0.0.0.0:4433 + +Grab a page from your server: + +:: + + ./http_client -H www.example.com -s 127.0.0.1:4433 -p / + +You can play with various options, of which there are many. Use +the ``-h`` command-line flag to see them. + +Next steps +---------- + +If you want to use LSQUIC in your program, check out the :doc:`tutorial` and +the :doc:`apiref`. + +:doc:`internals` covers some library internals. + +.. _zlib: https://www.zlib.net/ +.. _BoringSSL: https://boringssl.googlesource.com/boringssl/ +.. _`ls-qpack`: https://github.com/litespeedtech/ls-qpack +.. _libevent: https://libevent.org/ +.. _README: https://github.com/litespeedtech/lsquic/blob/master/README.md diff --git a/docs/index.rst b/docs/index.rst index 8f80be9..872b3cd 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,9 +3,6 @@ LSQUIC Documentation This is the documentation for LSQUIC_ |release|, last updated |today|. -Introduction ------------- - LiteSpeed QUIC (LSQUIC) Library is an open-source implementation of QUIC and HTTP/3 functionality for servers and clients. LSQUIC is: @@ -38,7 +35,9 @@ Contents :maxdepth: 2 gettingstarted + tutorial apiref + internals Indices and tables ================== diff --git a/docs/internals.rst b/docs/internals.rst new file mode 100644 index 0000000..8613260 --- /dev/null +++ b/docs/internals.rst @@ -0,0 +1,11 @@ +********* +Internals +********* + +Connection Management +===================== + +References to connections can exist in six different places in an +engine. + +.. image:: lsquic-engine-conns.png diff --git a/docs/lsquic-engine-conns.drawio b/docs/lsquic-engine-conns.drawio new file mode 100644 index 0000000..a5ad8ed --- /dev/null +++ b/docs/lsquic-engine-conns.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/lsquic-engine-conns.png b/docs/lsquic-engine-conns.png new file mode 100644 index 0000000..1852d4e Binary files /dev/null and b/docs/lsquic-engine-conns.png differ diff --git a/include/lsquic.h b/include/lsquic.h index 37974c0..b98203e 100644 --- a/include/lsquic.h +++ b/include/lsquic.h @@ -24,8 +24,8 @@ extern "C" { #endif #define LSQUIC_MAJOR_VERSION 2 -#define LSQUIC_MINOR_VERSION 11 -#define LSQUIC_PATCH_VERSION 1 +#define LSQUIC_MINOR_VERSION 12 +#define LSQUIC_PATCH_VERSION 0 /** * Engine flags: @@ -205,6 +205,9 @@ struct ssl_st; * constructor. */ +/* `sni' may be NULL if engine is not HTTP mode and client TLS transport + * parameters did not include the SNI. + */ typedef struct ssl_ctx_st * (*lsquic_lookup_cert_f)( void *lsquic_cert_lookup_ctx, const struct sockaddr *local, const char *sni); @@ -330,6 +333,9 @@ typedef struct ssl_ctx_st * (*lsquic_lookup_cert_f)( /** Turn off delayed ACKs extension by default */ #define LSQUIC_DF_DELAYED_ACKS 0 +/** Turn on timestamp extension by default */ +#define LSQUIC_DF_TIMESTAMPS 1 + /* 1: Cubic; 2: BBR */ #define LSQUIC_DF_CC_ALGO 1 @@ -724,6 +730,13 @@ struct lsquic_engine_settings { * Default value is @ref LSQUIC_DF_DELAYED_ACKS */ int es_delayed_acks; + + /** + * Enable timestamps extension. Allowed values are 0 and 1. + * + * Default value is @ref LSQUIC_DF_TIMESTAMPS + */ + int es_timestamps; }; /* Initialize `settings' to default values */ @@ -1312,7 +1325,7 @@ lsquic_stream_send_headers (lsquic_stream_t *s, /** * Get header set associated with the stream. The header set is created by * @ref hsi_create_header_set() callback. After this call, the ownership of - * the header set is trasnferred to the caller. + * the header set is transferred to the caller. * * This call must precede calls to @ref lsquic_stream_read() and * @ref lsquic_stream_readv(). diff --git a/src/liblsquic/lsquic_enc_sess_ietf.c b/src/liblsquic/lsquic_enc_sess_ietf.c index a632bc3..f3ed5cb 100644 --- a/src/liblsquic/lsquic_enc_sess_ietf.c +++ b/src/liblsquic/lsquic_enc_sess_ietf.c @@ -558,6 +558,8 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf, params.tp_numerics[TPI_MIN_ACK_DELAY] = 10000; /* TODO: make into a constant? make configurable? */ params.tp_set |= 1 << TPI_MIN_ACK_DELAY; } + if (settings->es_timestamps) + params.tp_set |= 1 << TPI_TIMESTAMPS; len = (enc_sess->esi_conn->cn_version == LSQVER_ID25 ? lsquic_tp_encode_id25 : lsquic_tp_encode)(¶ms, enc_sess->esi_flags & ESI_SERVER, buf, bufsz); @@ -1035,8 +1037,10 @@ iquic_lookup_cert (SSL *ssl, void *arg) #endif if (!server_name) { - LSQ_DEBUG("cert lookup: server name is not set, skip"); - return 1; + LSQ_DEBUG("cert lookup: server name is not set"); + /* SNI is required in HTTP/3 */ + if (enc_sess->esi_enpub->enp_flags & ENPUB_HTTP) + return 1; } path = enc_sess->esi_conn->cn_if->ci_get_path(enc_sess->esi_conn, NULL); @@ -1049,7 +1053,8 @@ iquic_lookup_cert (SSL *ssl, void *arg) { if (SSL_set_SSL_CTX(enc_sess->esi_ssl, ssl_ctx)) { - LSQ_DEBUG("looked up cert for %s", server_name); + LSQ_DEBUG("looked up cert for %s", server_name + ? server_name : ""); if (enc_sess->esi_enpub->enp_kli) SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback); SSL_set_verify(enc_sess->esi_ssl, @@ -1070,7 +1075,8 @@ iquic_lookup_cert (SSL *ssl, void *arg) } else { - LSQ_DEBUG("could not look up cert for %s", server_name); + LSQ_DEBUG("could not look up cert for %s", server_name + ? server_name : ""); return 0; } } diff --git a/src/liblsquic/lsquic_engine.c b/src/liblsquic/lsquic_engine.c index 49edaf3..eabc925 100644 --- a/src/liblsquic/lsquic_engine.c +++ b/src/liblsquic/lsquic_engine.c @@ -335,6 +335,7 @@ lsquic_engine_init_settings (struct lsquic_engine_settings *settings, settings->es_ql_bits = LSQUIC_DF_QL_BITS; settings->es_spin = LSQUIC_DF_SPIN; settings->es_delayed_acks = LSQUIC_DF_DELAYED_ACKS; + settings->es_timestamps = LSQUIC_DF_TIMESTAMPS; } @@ -1636,7 +1637,7 @@ remove_conn_from_hash (lsquic_engine_t *engine, lsquic_conn_t *conn) static void -refflags2str (enum lsquic_conn_flags flags, char s[6]) +refflags2str (enum lsquic_conn_flags flags, char s[7]) { *s = 'C'; s += !!(flags & LSCONN_CLOSING); *s = 'H'; s += !!(flags & LSCONN_HASHED); diff --git a/src/liblsquic/lsquic_full_conn_ietf.c b/src/liblsquic/lsquic_full_conn_ietf.c index 47cae70..f53925b 100644 --- a/src/liblsquic/lsquic_full_conn_ietf.c +++ b/src/liblsquic/lsquic_full_conn_ietf.c @@ -133,6 +133,7 @@ enum ifull_conn_flags IFC_MIGRA = 1 << 27, IFC_SPIN = 1 << 28, /* Spin bits are enabled */ IFC_DELAYED_ACKS = 1 << 29, /* Delayed ACKs are enabled */ + IFC_TIMESTAMPS = 1 << 30, /* Timestamps are enabled */ }; @@ -334,6 +335,7 @@ struct ietf_full_conn struct transport_params ifc_peer_param; STAILQ_HEAD(, stream_id_to_ss) ifc_stream_ids_to_ss; + lsquic_time_t ifc_created; lsquic_time_t ifc_saved_ack_received; lsquic_packno_t ifc_max_ack_packno[N_PNS]; lsquic_packno_t ifc_max_non_probing; @@ -1215,6 +1217,7 @@ lsquic_ietf_full_conn_client_new (struct lsquic_engine_public *enpub, LSQ_DEBUG("negotiating version %s", lsquic_ver2str[conn->ifc_u.cli.ifcli_ver_neg.vn_ver]); conn->ifc_process_incoming_packet = process_incoming_packet_verneg; + conn->ifc_created = now; LSQ_DEBUG("logging using %s SCID", LSQUIC_LOG_CONN_ID == CN_SCID(&conn->ifc_conn) ? "client" : "server"); return &conn->ifc_conn; @@ -1431,6 +1434,7 @@ lsquic_ietf_full_conn_server_new (struct lsquic_engine_public *enpub, if (0 != handshake_ok(&conn->ifc_conn)) goto err3; + conn->ifc_created = imc->imc_created; if (conn->ifc_idle_to) lsquic_alarmset_set(&conn->ifc_alset, AL_IDLE, imc->imc_created + conn->ifc_idle_to); @@ -1506,6 +1510,33 @@ ietf_full_conn_ci_cancel_pending_streams (struct lsquic_conn *lconn, unsigned n) } +/* Best effort. If timestamp frame does not fit, oh well */ +static void +generate_timestamp_frame (struct ietf_full_conn *conn, + struct lsquic_packet_out *packet_out, lsquic_time_t now) +{ + uint64_t timestamp; + int w; + + timestamp = (now - conn->ifc_created) >> TP_DEF_ACK_DELAY_EXP; + w = conn->ifc_conn.cn_pf->pf_gen_timestamp_frame( + packet_out->po_data + packet_out->po_data_sz, + lsquic_packet_out_avail(packet_out), timestamp); + if (w < 0) + { + LSQ_DEBUG("could not generate TIMESTAMP frame"); + return; + } + LSQ_DEBUG("generated TIMESTAMP(%"PRIu64" us) frame", + timestamp << TP_DEF_ACK_DELAY_EXP); + EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "generated TIMESTAMP(%" + PRIu64" us) frame", timestamp << TP_DEF_ACK_DELAY_EXP); + packet_out->po_frame_types |= 1 << QUIC_FRAME_TIMESTAMP; + lsquic_send_ctl_incr_pack_sz(&conn->ifc_send_ctl, packet_out, w); + packet_out->po_regen_sz += w; +} + + static int generate_ack_frame_for_pns (struct ietf_full_conn *conn, struct lsquic_packet_out *packet_out, enum packnum_space pns, @@ -1561,6 +1592,9 @@ generate_ack_frame_for_pns (struct ietf_full_conn *conn, lsquic_send_ctl_sanity_check(&conn->ifc_send_ctl); LSQ_DEBUG("%s ACK state reset", lsquic_pns2str[pns]); + if (pns == PNS_APP && (conn->ifc_flags & IFC_TIMESTAMPS)) + generate_timestamp_frame(conn, packet_out, now); + return 0; } @@ -3013,6 +3047,12 @@ handshake_ok (struct lsquic_conn *lconn) LSQ_DEBUG("delayed ACKs enabled"); conn->ifc_flags |= IFC_DELAYED_ACKS; } + if (conn->ifc_settings->es_timestamps + && (params->tp_set & (1 << TPI_TIMESTAMPS))) + { + LSQ_DEBUG("timestamps enabled"); + conn->ifc_flags |= IFC_TIMESTAMPS; + } conn->ifc_max_peer_ack_usec = params->tp_max_ack_delay * 1000; @@ -5583,6 +5623,36 @@ process_ack_frequency_frame (struct ietf_full_conn *conn, } +static unsigned +process_timestamp_frame (struct ietf_full_conn *conn, + struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len) +{ + uint64_t timestamp; + int parsed_len; + + if (!(conn->ifc_flags & IFC_TIMESTAMPS)) + { + ABORT_QUIETLY(0, TEC_PROTOCOL_VIOLATION, + "Received unexpected TIMESTAMP frame (not negotiated)"); + return 0; + } + + parsed_len = conn->ifc_conn.cn_pf->pf_parse_timestamp_frame(p, len, + ×tamp); + if (parsed_len < 0) + return 0; + + timestamp <<= conn->ifc_cfg.ack_exp; + EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "TIMESTAMP(%"PRIu64" us)", timestamp); + LSQ_DEBUG("TIMESTAMP(%"PRIu64" us) (%"PRIu64" << %"PRIu8")", timestamp, + timestamp >> conn->ifc_cfg.ack_exp, conn->ifc_cfg.ack_exp); + + /* We don't do anything with the timestamp */ + + return parsed_len; +} + + typedef unsigned (*process_frame_f)( struct ietf_full_conn *, struct lsquic_packet_in *, const unsigned char *p, size_t); @@ -5611,6 +5681,7 @@ static process_frame_f const process_frames[N_QUIC_FRAMES] = [QUIC_FRAME_CRYPTO] = process_crypto_frame, [QUIC_FRAME_HANDSHAKE_DONE] = process_handshake_done_frame, [QUIC_FRAME_ACK_FREQUENCY] = process_ack_frequency_frame, + [QUIC_FRAME_TIMESTAMP] = process_timestamp_frame, }; diff --git a/src/liblsquic/lsquic_mini_conn_ietf.c b/src/liblsquic/lsquic_mini_conn_ietf.c index 207fe0e..b27152f 100644 --- a/src/liblsquic/lsquic_mini_conn_ietf.c +++ b/src/liblsquic/lsquic_mini_conn_ietf.c @@ -1049,6 +1049,8 @@ static unsigned (*const imico_process_frames[N_QUIC_FRAMES]) /* STREAM frame can only come in the App PNS and we delay those packets: */ [QUIC_FRAME_STREAM] = imico_process_invalid_frame, [QUIC_FRAME_HANDSHAKE_DONE] = imico_process_invalid_frame, + [QUIC_FRAME_ACK_FREQUENCY] = imico_process_invalid_frame, + [QUIC_FRAME_TIMESTAMP] = imico_process_invalid_frame, }; diff --git a/src/liblsquic/lsquic_mm.c b/src/liblsquic/lsquic_mm.c index ff8f483..de87ca6 100644 --- a/src/liblsquic/lsquic_mm.c +++ b/src/liblsquic/lsquic_mm.c @@ -384,8 +384,6 @@ lsquic_mm_put_packet_out (struct lsquic_mm *mm, poolst_freed(&mm->packet_out_bstats[idx]); if (poolst_has_new_sample(&mm->packet_out_bstats[idx])) maybe_shrink_packet_out_bufs(mm, idx); - if (packet_out->po_bwp_state) - lsquic_malo_put(packet_out->po_bwp_state); #else free(packet_out->po_data); #endif diff --git a/src/liblsquic/lsquic_packet_common.h b/src/liblsquic/lsquic_packet_common.h index 119aed1..5f2bd1b 100644 --- a/src/liblsquic/lsquic_packet_common.h +++ b/src/liblsquic/lsquic_packet_common.h @@ -35,6 +35,7 @@ enum quic_frame_type QUIC_FRAME_NEW_TOKEN, /* I */ QUIC_FRAME_HANDSHAKE_DONE, /* I */ QUIC_FRAME_ACK_FREQUENCY, /* I */ + QUIC_FRAME_TIMESTAMP, /* I */ N_QUIC_FRAMES }; @@ -64,6 +65,7 @@ enum quic_ft_bit { QUIC_FTBIT_RETIRE_CONNECTION_ID = 1 << QUIC_FRAME_RETIRE_CONNECTION_ID, QUIC_FTBIT_HANDSHAKE_DONE = 1 << QUIC_FRAME_HANDSHAKE_DONE, QUIC_FTBIT_ACK_FREQUENCY = 1 << QUIC_FRAME_ACK_FREQUENCY, + QUIC_FTBIT_TIMESTAMP = 1 << QUIC_FRAME_TIMESTAMP, }; static const char * const frame_type_2_str[N_QUIC_FRAMES] = { @@ -92,6 +94,7 @@ static const char * const frame_type_2_str[N_QUIC_FRAMES] = { [QUIC_FRAME_RETIRE_CONNECTION_ID] = "QUIC_FRAME_RETIRE_CONNECTION_ID", [QUIC_FRAME_HANDSHAKE_DONE] = "QUIC_FRAME_HANDSHAKE_DONE", [QUIC_FRAME_ACK_FREQUENCY] = "QUIC_FRAME_ACK_FREQUENCY", + [QUIC_FRAME_TIMESTAMP] = "QUIC_FRAME_TIMESTAMP", }; #define QUIC_FRAME_PRELEN (sizeof("QUIC_FRAME_")) @@ -128,6 +131,7 @@ static const char * const frame_type_2_str[N_QUIC_FRAMES] = { QUIC_FRAME_SLEN(QUIC_FRAME_NEW_TOKEN) + 1 + \ QUIC_FRAME_SLEN(QUIC_FRAME_HANDSHAKE_DONE) + 1 + \ QUIC_FRAME_SLEN(QUIC_FRAME_ACK_FREQUENCY) + 1 + \ + QUIC_FRAME_SLEN(QUIC_FRAME_TIMESTAMP) + 1 + \ 0 @@ -217,6 +221,7 @@ extern const char *const lsquic_pns2str[]; | QUIC_FTBIT_NEW_TOKEN \ | QUIC_FTBIT_HANDSHAKE_DONE \ | QUIC_FTBIT_ACK_FREQUENCY \ + | QUIC_FTBIT_TIMESTAMP \ | QUIC_FTBIT_CRYPTO ) /* [draft-ietf-quic-transport-24] Section 1.2 */ @@ -231,7 +236,7 @@ extern const char *const lsquic_pns2str[]; */ #define IQUIC_FRAME_RETX_MASK ( \ ALL_IQUIC_FRAMES & ~(QUIC_FTBIT_PADDING|QUIC_FTBIT_PATH_RESPONSE \ - |QUIC_FTBIT_PATH_CHALLENGE|QUIC_FTBIT_ACK)) + |QUIC_FTBIT_PATH_CHALLENGE|QUIC_FTBIT_ACK|QUIC_FTBIT_TIMESTAMP)) extern const enum quic_ft_bit lsquic_legal_frames_by_level[]; diff --git a/src/liblsquic/lsquic_packet_gquic.h b/src/liblsquic/lsquic_packet_gquic.h index 02a75cd..54ded33 100644 --- a/src/liblsquic/lsquic_packet_gquic.h +++ b/src/liblsquic/lsquic_packet_gquic.h @@ -18,7 +18,7 @@ enum PACKET_PUBLIC_FLAGS #define GQUIC_FRAME_REGEN_MASK ((1 << QUIC_FRAME_ACK) \ | (1 << QUIC_FRAME_PATH_CHALLENGE) | (1 << QUIC_FRAME_PATH_RESPONSE) \ - | (1 << QUIC_FRAME_STOP_WAITING)) + | (1 << QUIC_FRAME_STOP_WAITING) | (1 << QUIC_FRAME_TIMESTAMP)) #define GQUIC_FRAME_REGENERATE(frame_type) ((1 << (frame_type)) & GQUIC_FRAME_REGEN_MASK) diff --git a/src/liblsquic/lsquic_parse.h b/src/liblsquic/lsquic_parse.h index 0bccef0..b807e31 100644 --- a/src/liblsquic/lsquic_parse.h +++ b/src/liblsquic/lsquic_parse.h @@ -310,6 +310,10 @@ struct parse_funcs unsigned (*pf_ack_frequency_frame_size) (uint64_t seqno, uint64_t pack_tol, uint64_t upd_mad); + int + (*pf_gen_timestamp_frame) (unsigned char *buf, size_t buf_len, uint64_t); + int + (*pf_parse_timestamp_frame) (const unsigned char *buf, size_t, uint64_t *); }; diff --git a/src/liblsquic/lsquic_parse_common.c b/src/liblsquic/lsquic_parse_common.c index ffc7b7a..4fc6347 100644 --- a/src/liblsquic/lsquic_parse_common.c +++ b/src/liblsquic/lsquic_parse_common.c @@ -243,5 +243,7 @@ const enum quic_ft_bit lsquic_legal_frames_by_level[N_ENC_LEVS] = | QUIC_FTBIT_NEW_CONNECTION_ID | QUIC_FTBIT_STOP_SENDING | QUIC_FTBIT_PATH_CHALLENGE | QUIC_FTBIT_PATH_RESPONSE | QUIC_FTBIT_HANDSHAKE_DONE | QUIC_FTBIT_ACK_FREQUENCY - | QUIC_FTBIT_RETIRE_CONNECTION_ID | QUIC_FTBIT_NEW_TOKEN, + | QUIC_FTBIT_RETIRE_CONNECTION_ID | QUIC_FTBIT_NEW_TOKEN + | QUIC_FTBIT_TIMESTAMP + , }; diff --git a/src/liblsquic/lsquic_parse_ietf_v1.c b/src/liblsquic/lsquic_parse_ietf_v1.c index 5d86658..8759091 100644 --- a/src/liblsquic/lsquic_parse_ietf_v1.c +++ b/src/liblsquic/lsquic_parse_ietf_v1.c @@ -46,6 +46,9 @@ #define CHECK_SPACE(need, pstart, pend) \ do { if ((intptr_t) (need) > ((pend) - (pstart))) { return -1; } } while (0) +#define FRAME_TYPE_ACK_FREQUENCY 0xAF +#define FRAME_TYPE_TIMESTAMP 0x2F5 + static int ietf_v1_gen_one_varint (unsigned char *, size_t, unsigned char, uint64_t); @@ -1109,7 +1112,8 @@ ietf_v1_parse_frame_type (const unsigned char *buf, size_t len) if (s > 0 && (unsigned) s == (1u << vint_val2bits(val))) switch (val) { - case 0xAF: return QUIC_FRAME_ACK_FREQUENCY; + case FRAME_TYPE_ACK_FREQUENCY: return QUIC_FRAME_ACK_FREQUENCY; + case FRAME_TYPE_TIMESTAMP: return QUIC_FRAME_TIMESTAMP; default: break; } @@ -2059,7 +2063,7 @@ ietf_v1_gen_ack_frequency_frame (unsigned char *buf, size_t buf_len, uint64_t seqno, uint64_t pack_tol, uint64_t upd_mad) { return ietf_v1_gen_frame_with_varints(buf, buf_len, 4, - (uint64_t[]){ 0xAF, seqno, pack_tol, upd_mad }); + (uint64_t[]){ FRAME_TYPE_ACK_FREQUENCY, seqno, pack_tol, upd_mad }); } @@ -2068,7 +2072,8 @@ ietf_v1_parse_ack_frequency_frame (const unsigned char *buf, size_t buf_len, uint64_t *seqno, uint64_t *pack_tol, uint64_t *upd_mad) { return ietf_v1_parse_frame_with_varints(buf, buf_len, - 0xAF, 3, (uint64_t *[]) { seqno, pack_tol, upd_mad }); + FRAME_TYPE_ACK_FREQUENCY, + 3, (uint64_t *[]) { seqno, pack_tol, upd_mad }); } @@ -2077,7 +2082,7 @@ ietf_v1_ack_frequency_frame_size (uint64_t seqno, uint64_t pack_tol, uint64_t upd_mad) { return ietf_v1_frame_with_varints_size(4, - (uint64_t[]){ 0xAF, seqno, pack_tol, upd_mad }); + (uint64_t[]){ FRAME_TYPE_ACK_FREQUENCY, seqno, pack_tol, upd_mad }); } @@ -2088,6 +2093,24 @@ ietf_v1_handshake_done_frame_size (void) } +static int +ietf_v1_gen_timestamp_frame (unsigned char *buf, size_t buf_len, + uint64_t timestamp) +{ + return ietf_v1_gen_frame_with_varints(buf, buf_len, 2, + (uint64_t[]){ FRAME_TYPE_TIMESTAMP, timestamp }); +} + + +static int +ietf_v1_parse_timestamp_frame (const unsigned char *buf, size_t buf_len, + uint64_t *timestamp) +{ + return ietf_v1_parse_frame_with_varints(buf, buf_len, + FRAME_TYPE_TIMESTAMP, 1, (uint64_t *[]) { timestamp }); +} + + const struct parse_funcs lsquic_parse_funcs_ietf_v1 = { .pf_gen_reg_pkt_header = ietf_v1_gen_reg_pkt_header, @@ -2156,4 +2179,6 @@ const struct parse_funcs lsquic_parse_funcs_ietf_v1 = .pf_gen_ack_frequency_frame = ietf_v1_gen_ack_frequency_frame, .pf_parse_ack_frequency_frame = ietf_v1_parse_ack_frequency_frame, .pf_ack_frequency_frame_size = ietf_v1_ack_frequency_frame_size, + .pf_gen_timestamp_frame = ietf_v1_gen_timestamp_frame, + .pf_parse_timestamp_frame = ietf_v1_parse_timestamp_frame, }; diff --git a/src/liblsquic/lsquic_trans_params.c b/src/liblsquic/lsquic_trans_params.c index ae5b428..e5dcaec 100644 --- a/src/liblsquic/lsquic_trans_params.c +++ b/src/liblsquic/lsquic_trans_params.c @@ -52,6 +52,7 @@ tpi_val_2_enum (uint64_t tpi_val) #endif case 0x1057: return TPI_LOSS_BITS; case 0xDE1A: return TPI_MIN_ACK_DELAY; + case 0x7157: return TPI_TIMESTAMPS; default: return INT_MAX; } } @@ -79,6 +80,7 @@ static const unsigned enum_2_tpi_val[LAST_TPI + 1] = #endif [TPI_LOSS_BITS] = 0x1057, [TPI_MIN_ACK_DELAY] = 0xDE1A, + [TPI_TIMESTAMPS] = 0x7157, }; @@ -104,6 +106,7 @@ static const char * const tpi2str[LAST_TPI + 1] = #endif [TPI_LOSS_BITS] = "loss_bits", [TPI_MIN_ACK_DELAY] = "min_ack_delay", + [TPI_TIMESTAMPS] = "timestamps", }; @@ -378,6 +381,7 @@ lsquic_tp_encode (const struct transport_params *params, int is_server, sizeof(params->tp_preferred_address.srst)); break; case TPI_DISABLE_ACTIVE_MIGRATION: + case TPI_TIMESTAMPS: *p++ = 0; break; #if LSQUIC_TEST_QUANTUM_READINESS @@ -500,6 +504,7 @@ lsquic_tp_decode (const unsigned char *const buf, size_t bufsz, } break; case TPI_DISABLE_ACTIVE_MIGRATION: + case TPI_TIMESTAMPS: EXPECT_LEN(0); break; case TPI_STATELESS_RESET_TOKEN: @@ -615,7 +620,7 @@ lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz) return; } for (; tpi <= MAX_EMPTY_TPI; ++tpi) - if (params->tp_set & (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL)) + if (params->tp_set & (1 << tpi)) { nw = snprintf(buf, end - buf, "%.*s%s", (buf + sz > end) << 1, "; ", tpi2str[tpi]); @@ -825,6 +830,7 @@ lsquic_tp_encode_id25 (const struct transport_params *params, int is_server, sizeof(params->tp_preferred_address.srst)); break; case TPI_DISABLE_ACTIVE_MIGRATION: + case TPI_TIMESTAMPS: WRITE_UINT_TO_P(0, 16); break; #if LSQUIC_TEST_QUANTUM_READINESS @@ -948,6 +954,7 @@ lsquic_tp_decode_id25 (const unsigned char *const buf, size_t bufsz, } break; case TPI_DISABLE_ACTIVE_MIGRATION: + case TPI_TIMESTAMPS: EXPECT_LEN(0); break; case TPI_STATELESS_RESET_TOKEN: diff --git a/src/liblsquic/lsquic_trans_params.h b/src/liblsquic/lsquic_trans_params.h index 1769a35..d170144 100644 --- a/src/liblsquic/lsquic_trans_params.h +++ b/src/liblsquic/lsquic_trans_params.h @@ -38,6 +38,7 @@ enum transport_param_id /* * Empty transport parameters: */ + TPI_TIMESTAMPS, TPI_DISABLE_ACTIVE_MIGRATION, MAX_EMPTY_TPI = TPI_DISABLE_ACTIVE_MIGRATION, /* diff --git a/test/prog.c b/test/prog.c index 24df4dd..93ab35e 100644 --- a/test/prog.c +++ b/test/prog.c @@ -371,7 +371,10 @@ prog_connect (struct prog *prog, unsigned char *zero_rtt, size_t zero_rtt_len) if (NULL == lsquic_engine_connect(prog->prog_engine, N_LSQVER, (struct sockaddr *) &sport->sp_local_addr, (struct sockaddr *) &sport->sas, sport, NULL, - prog->prog_hostname ? prog->prog_hostname : sport->host, + prog->prog_hostname ? prog->prog_hostname + /* SNI is required for HTTP */ + : prog->prog_engine_flags & LSENG_HTTP ? sport->host + : NULL, prog->prog_max_packet_size, zero_rtt, zero_rtt_len, sport->sp_token_buf, sport->sp_token_sz)) return -1; diff --git a/test/test_cert.c b/test/test_cert.c index 90cc279..7eed240 100644 --- a/test/test_cert.c +++ b/test/test_cert.c @@ -134,21 +134,27 @@ struct ssl_ctx_st * lookup_cert (void *cert_lu_ctx, const struct sockaddr *sa_UNUSED, const char *sni) { + struct lsquic_hash_elem *el; + struct server_cert *server_cert; + if (!cert_lu_ctx) return NULL; - if (!sni) + + if (sni) + el = lsquic_hash_find(cert_lu_ctx, sni, strlen(sni)); + else { LSQ_INFO("SNI is not set"); - return NULL; + el = lsquic_hash_first(cert_lu_ctx); } - struct lsquic_hash_elem *el = lsquic_hash_find(cert_lu_ctx, sni, strlen(sni)); - struct server_cert *server_cert = NULL; + if (el) { server_cert = lsquic_hashelem_getdata(el); if (server_cert) return server_cert->ce_ssl_ctx; } + return NULL; } diff --git a/test/test_common.c b/test/test_common.c index 37313ac..cff4584 100644 --- a/test/test_common.c +++ b/test/test_common.c @@ -1802,6 +1802,11 @@ set_engine_option (struct lsquic_engine_settings *settings, settings->es_honor_prst = atoi(val); return 0; } + if (0 == strncmp(name, "timestamps", 10)) + { + settings->es_timestamps = atoi(val); + return 0; + } break; case 11: if (0 == strncmp(name, "ping_period", 11))