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))