Release 2.10.5

- [BUGFIX] BBR: call cci_sent() with correct arguments and at correct time.
- Refactor transport parameters module.
- Minor code cleanup.
This commit is contained in:
Dmitri Tikhonov 2020-02-13 09:36:04 -05:00
parent e68b045258
commit 1bdb91d191
12 changed files with 460 additions and 458 deletions

View File

@ -1,3 +1,10 @@
2020-02-13
- 2.10.5
- [BUGFIX] BBR: call cci_sent() with correct arguments and at correct
time.
- Refactor transport parameters module.
- Minor code cleanup.
2020-02-11
- 2.10.4
- [BUGFIX] Send HANDSHAKE_DONE only after Finished is received.

View File

@ -25,7 +25,7 @@ extern "C" {
#define LSQUIC_MAJOR_VERSION 2
#define LSQUIC_MINOR_VERSION 10
#define LSQUIC_PATCH_VERSION 4
#define LSQUIC_PATCH_VERSION 5
/**
* Engine flags:
@ -757,7 +757,6 @@ struct lsquic_engine_settings {
* 0: Do not use loss bits
* 1: Allow loss bits
* 2: Allow and send loss bits
* -1: Allow and send loss bits, sending old-style boolean loss_bits TP
*
* Default value is @ref LSQUIC_DF_QL_BITS
*/

View File

@ -436,15 +436,14 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
{
const struct lsquic_conn *const lconn = enc_sess->esi_conn;
params.tp_flags |= TRAPA_SERVER|TRAPA_RESET_TOKEN;
params.tp_set |= 1 << TPI_STATELESS_RESET_TOKEN;
lsquic_tg_generate_sreset(enc_sess->esi_enpub->enp_tokgen,
CN_SCID(lconn), params.tp_stateless_reset_token);
if (enc_sess->esi_flags & ESI_ODCID)
{
params.tp_original_cid = enc_sess->esi_odcid;
params.tp_flags |= TRAPA_ORIGINAL_CID;
params.tp_set |= 1 << TPI_ORIGINAL_CONNECTION_ID;
}
#if LSQUIC_PREFERRED_ADDR
char addr_buf[INET6_ADDRSTRLEN + 6 /* port */ + 1];
@ -459,7 +458,7 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
addr_buf[colon - s] = '\0';
inet_pton(AF_INET, addr_buf, params.tp_preferred_address.ipv4_addr);
params.tp_preferred_address.ipv4_port = atoi(colon + 1);
params.tp_flags |= TRAPA_PREFADDR_IPv4;
params.tp_set |= 1 << TPI_PREFERRED_ADDRESS;
}
s = getenv("LSQUIC_PREFERRED_ADDR6");
if (s && strlen(s) < sizeof(addr_buf) && (colon = strrchr(s, ':')))
@ -469,10 +468,10 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
inet_pton(AF_INET6, addr_buf,
params.tp_preferred_address.ipv6_addr);
params.tp_preferred_address.ipv6_port = atoi(colon + 1);
params.tp_flags |= TRAPA_PREFADDR_IPv6;
params.tp_set |= 1 << TPI_PREFERRED_ADDRESS;
}
conn = enc_sess->esi_conn;
if ((params.tp_flags & (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6))
if ((params.tp_set & (1 << TPI_PREFERRED_ADDRESS))
&& (1 << conn->cn_n_cces) - 1 != conn->cn_cces_mask)
{
seqno = 0;
@ -506,7 +505,7 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
else
{
cant_use_prefaddr:
params.tp_flags &= ~(TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6);
params.tp_set &= ~(1 << TPI_PREFERRED_ADDRESS);
}
#endif
}
@ -515,7 +514,7 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
{
const char *s = getenv("LSQUIC_TEST_QUANTUM_READINESS");
if (s && atoi(s))
params.tp_flags |= TRAPA_QUANTUM_READY;
params.tp_set |= 1 << TPI_QUANTUM_READINESS;
}
#endif
params.tp_init_max_data = settings->es_init_max_data;
@ -535,23 +534,33 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
params.tp_max_ack_delay = TP_DEF_MAX_ACK_DELAY;
params.tp_max_packet_size = 1370 /* XXX: based on socket */;
params.tp_active_connection_id_limit = MAX_IETF_CONN_DCIDS;
params.tp_set |= (1 << TPI_INIT_MAX_DATA)
| (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL)
| (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE)
| (1 << TPI_INIT_MAX_STREAM_DATA_UNI)
| (1 << TPI_INIT_MAX_STREAMS_UNI)
| (1 << TPI_INIT_MAX_STREAMS_BIDI)
| (1 << TPI_ACK_DELAY_EXPONENT)
| (1 << TPI_MAX_IDLE_TIMEOUT)
| (1 << TPI_MAX_ACK_DELAY)
| (1 << TPI_MAX_PACKET_SIZE)
| (1 << TPI_ACTIVE_CONNECTION_ID_LIMIT)
;
if (enc_sess->esi_conn->cn_version == LSQVER_ID24)
{
params.tp_active_connection_id_limit = params.tp_active_connection_id_limit
- 1 /* One slot is used by peer's SCID */
- !!(params.tp_flags & (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6));
- !!(params.tp_set & (1 << TPI_PREFERRED_ADDRESS));
}
if (!settings->es_allow_migration)
params.tp_disable_active_migration = 1;
if (settings->es_ql_bits == -1)
params.tp_flags |= TRAPA_QL_BITS_OLD;
else if (settings->es_ql_bits)
params.tp_set |= 1 << TPI_DISABLE_ACTIVE_MIGRATION;
if (settings->es_ql_bits)
{
params.tp_loss_bits = settings->es_ql_bits - 1;
params.tp_flags |= TRAPA_QL_BITS;
params.tp_set |= 1 << TPI_LOSS_BITS;
}
len = lsquic_tp_encode(&params, buf, bufsz);
len = lsquic_tp_encode(&params, enc_sess->esi_flags & ESI_SERVER, buf, bufsz);
if (len >= 0)
LSQ_DEBUG("generated transport parameters buffer of %d bytes", len);
else
@ -1458,7 +1467,7 @@ get_peer_transport_params (struct enc_sess_iquic *enc_sess)
if ((enc_sess->esi_flags & (ESI_ODCID|ESI_SERVER)) == ESI_ODCID)
{
if (!(trans_params->tp_flags & TRAPA_ORIGINAL_CID))
if (!(trans_params->tp_set & (1 << TPI_ORIGINAL_CONNECTION_ID)))
{
LSQ_DEBUG("server did not produce original DCID (ODCID)");
return -1;
@ -1480,15 +1489,11 @@ get_peer_transport_params (struct enc_sess_iquic *enc_sess)
}
}
if ((trans_params->tp_flags & TRAPA_QL_BITS)
if ((trans_params->tp_set & (1 << TPI_LOSS_BITS))
&& enc_sess->esi_enpub->enp_settings.es_ql_bits)
{
unsigned our_loss_bits;
if (enc_sess->esi_enpub->enp_settings.es_ql_bits == -1)
our_loss_bits = 1;
else
our_loss_bits = enc_sess->esi_enpub->enp_settings.es_ql_bits - 1;
const unsigned our_loss_bits
= enc_sess->esi_enpub->enp_settings.es_ql_bits - 1;
switch ((our_loss_bits << 1) | trans_params->tp_loss_bits)
{
case (0 << 1) | 0:

View File

@ -403,7 +403,7 @@ lsquic_engine_check_settings (const struct lsquic_engine_settings *settings,
return -1;
}
if (!(settings->es_ql_bits >= -1 && settings->es_ql_bits <= 2))
if (!(settings->es_ql_bits >= 0 && settings->es_ql_bits <= 2))
{
if (err_buf)
snprintf(err_buf, err_buf_sz, "Invalid QL bits value %d ",

View File

@ -2592,10 +2592,10 @@ begin_migra_or_retire_cid (struct id24_full_conn *conn,
struct sockaddr_in6 v6;
} sockaddr;
if (params->tp_disable_active_migration
if ((params->tp_set & (1 << TPI_DISABLE_ACTIVE_MIGRATION))
|| !conn->ifc_settings->es_allow_migration)
{
if (params->tp_disable_active_migration)
if (params->tp_set & (1 << TPI_DISABLE_ACTIVE_MIGRATION))
LSQ_DEBUG("TP disables migration: retire PreferredAddress CID");
else
LSQ_DEBUG("Migration not allowed: retire PreferredAddress CID");
@ -2604,8 +2604,8 @@ begin_migra_or_retire_cid (struct id24_full_conn *conn,
}
is_ipv6 = NP_IS_IPv6(CUR_NPATH(conn));
if ((is_ipv6 && !(params->tp_flags & TRAPA_PREFADDR_IPv6))
|| (!is_ipv6 && !(params->tp_flags & TRAPA_PREFADDR_IPv4)))
if ((is_ipv6 && !lsquic_tp_has_pref_ipv6(params))
|| (!is_ipv6 && !lsquic_tp_has_pref_ipv4(params)))
{
/* XXX This is a limitation in the client code outside of the library.
* To support cross-IP-version migration, we need to add some callbacks
@ -2683,7 +2683,7 @@ maybe_start_migration (struct id24_full_conn *conn)
params = lconn->cn_esf.i->esfi_get_peer_transport_params(
lconn->cn_enc_session);
if (params->tp_flags & (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6))
if (params->tp_set & (1 << TPI_PREFERRED_ADDRESS))
{
if (0 != begin_migra_or_retire_cid(conn, params))
ABORT_QUIETLY(0, TEC_INTERNAL_ERROR, "error initiating migration");
@ -2721,9 +2721,8 @@ handshake_ok (struct lsquic_conn *lconn)
LSQ_DEBUG("peer transport parameters: %s",
(lsquic_tp_to_str(params, buf, sizeof(buf)), buf));
if ((params->tp_flags & TRAPA_QL_BITS)
&& (conn->ifc_settings->es_ql_bits == 2
|| conn->ifc_settings->es_ql_bits == -1))
if ((params->tp_set & (1 << TPI_LOSS_BITS))
&& conn->ifc_settings->es_ql_bits == 2)
{
LSQ_DEBUG("turn on QL loss bits");
lsquic_send_ctl_do_ql_bits(&conn->ifc_send_ctl);
@ -2797,7 +2796,7 @@ handshake_ok (struct lsquic_conn *lconn)
memset(dce, 0, sizeof(*dce));
dce->de_cid = *CUR_DCID(conn);
dce->de_seqno = 0;
if (params->tp_flags & TRAPA_RESET_TOKEN)
if (params->tp_set & (1 << TPI_STATELESS_RESET_TOKEN))
{
memcpy(dce->de_srst, params->tp_stateless_reset_token,
sizeof(dce->de_srst));
@ -4795,7 +4794,7 @@ must_reserve_one_dce_slot (struct id24_full_conn *conn)
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));
return !!(params->tp_set & (1 << TPI_PREFERRED_ADDRESS));
else
return 0;
}

View File

@ -2765,10 +2765,10 @@ begin_migra_or_retire_cid (struct ietf_full_conn *conn,
struct sockaddr_in6 v6;
} sockaddr;
if (params->tp_disable_active_migration
if ((params->tp_set & (1 << TPI_DISABLE_ACTIVE_MIGRATION))
|| !conn->ifc_settings->es_allow_migration)
{
if (params->tp_disable_active_migration)
if (params->tp_set & (1 << TPI_DISABLE_ACTIVE_MIGRATION))
LSQ_DEBUG("TP disables migration: retire PreferredAddress CID");
else
LSQ_DEBUG("Migration not allowed: retire PreferredAddress CID");
@ -2777,8 +2777,8 @@ begin_migra_or_retire_cid (struct ietf_full_conn *conn,
}
is_ipv6 = NP_IS_IPv6(CUR_NPATH(conn));
if ((is_ipv6 && !(params->tp_flags & TRAPA_PREFADDR_IPv6))
|| (!is_ipv6 && !(params->tp_flags & TRAPA_PREFADDR_IPv4)))
if ((is_ipv6 && !lsquic_tp_has_pref_ipv6(params))
|| (!is_ipv6 && !lsquic_tp_has_pref_ipv4(params)))
{
/* XXX This is a limitation in the client code outside of the library.
* To support cross-IP-version migration, we need to add some callbacks
@ -2856,7 +2856,7 @@ maybe_start_migration (struct ietf_full_conn *conn)
params = lconn->cn_esf.i->esfi_get_peer_transport_params(
lconn->cn_enc_session);
if (params->tp_flags & (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6))
if (params->tp_set & (1 << TPI_PREFERRED_ADDRESS))
{
if (0 != begin_migra_or_retire_cid(conn, params))
ABORT_QUIETLY(0, TEC_INTERNAL_ERROR, "error initiating migration");
@ -2894,9 +2894,8 @@ handshake_ok (struct lsquic_conn *lconn)
LSQ_DEBUG("peer transport parameters: %s",
(lsquic_tp_to_str(params, buf, sizeof(buf)), buf));
if ((params->tp_flags & TRAPA_QL_BITS)
&& (conn->ifc_settings->es_ql_bits == 2
|| conn->ifc_settings->es_ql_bits == -1))
if ((params->tp_set & (1 << TPI_LOSS_BITS))
&& conn->ifc_settings->es_ql_bits == 2)
{
LSQ_DEBUG("turn on QL loss bits");
lsquic_send_ctl_do_ql_bits(&conn->ifc_send_ctl);
@ -3005,7 +3004,7 @@ handshake_ok (struct lsquic_conn *lconn)
memset(dce, 0, sizeof(*dce));
dce->de_cid = *CUR_DCID(conn);
dce->de_seqno = 0;
if (params->tp_flags & TRAPA_RESET_TOKEN)
if (params->tp_set & (1 << TPI_STATELESS_RESET_TOKEN))
{
memcpy(dce->de_srst, params->tp_stateless_reset_token,
sizeof(dce->de_srst));

View File

@ -887,9 +887,10 @@ gquic_be_gen_ack_frame (unsigned char *outbuf, size_t outbuf_sz,
*type |= bits;
CHECKOUT(largest_acked_len);
tmp_packno = maxno;
#if __BYTE_ORDER == __LITTLE_ENDIAN
tmp_packno = bswap_64(maxno);
#else
tmp_packno = maxno;
#endif
memcpy(p, (unsigned char *) &tmp_packno + 8 - largest_acked_len,
largest_acked_len);

View File

@ -655,6 +655,9 @@ lsquic_send_ctl_sent_packet (lsquic_send_ctl_t *ctl,
packet_out->po_packno, lsquic_frame_types_to_str(frames,
sizeof(frames), packet_out->po_frame_types));
lsquic_senhist_add(&ctl->sc_senhist, packet_out->po_packno);
if (ctl->sc_ci->cci_sent)
ctl->sc_ci->cci_sent(CGP(ctl), packet_out, ctl->sc_bytes_unacked_all,
ctl->sc_flags & SC_APP_LIMITED);
send_ctl_unacked_append(ctl, packet_out);
if (packet_out->po_frame_types & ctl->sc_retx_frames)
{
@ -670,9 +673,6 @@ lsquic_send_ctl_sent_packet (lsquic_send_ctl_t *ctl,
#if LSQUIC_SEND_STATS
++ctl->sc_stats.n_total_sent;
#endif
if (ctl->sc_ci->cci_sent)
ctl->sc_ci->cci_sent(CGP(ctl), packet_out, ctl->sc_n_in_flight_all,
ctl->sc_flags & SC_APP_LIMITED);
lsquic_send_ctl_sanity_check(ctl);
return 0;
}

View File

@ -3407,10 +3407,10 @@ lsquic_stream_writef (lsquic_stream_t *stream, struct lsquic_reader *reader)
static ssize_t
stream_write_buf (struct lsquic_stream *stream, const void *buf, size_t sz)
{
struct iovec iov = { (void *) buf, sz, };
const struct iovec iov[1] = {{ (void *) buf, sz, }};
struct inner_reader_iovec iro = {
.iov = &iov,
.end = &iov + 1,
.iov = iov,
.end = iov + 1,
.cur_iovec_off = 0,
};
struct lsquic_reader reader = {

View File

@ -6,6 +6,7 @@
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
@ -26,7 +27,84 @@
#include "lsquic_logger.h"
static const uint64_t def_vals[MAX_TPI + 1] =
static enum transport_param_id
tpi_val_2_enum (uint64_t tpi_val)
{
switch (tpi_val)
{
case 0: return TPI_ORIGINAL_CONNECTION_ID;
case 1: return TPI_MAX_IDLE_TIMEOUT;
case 2: return TPI_STATELESS_RESET_TOKEN;
case 3: return TPI_MAX_PACKET_SIZE;
case 4: return TPI_INIT_MAX_DATA;
case 5: return TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL;
case 6: return TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE;
case 7: return TPI_INIT_MAX_STREAM_DATA_UNI;
case 8: return TPI_INIT_MAX_STREAMS_BIDI;
case 9: return TPI_INIT_MAX_STREAMS_UNI;
case 10: return TPI_ACK_DELAY_EXPONENT;
case 11: return TPI_MAX_ACK_DELAY;
case 12: return TPI_DISABLE_ACTIVE_MIGRATION;
case 13: return TPI_PREFERRED_ADDRESS;
case 14: return TPI_ACTIVE_CONNECTION_ID_LIMIT;
#if LSQUIC_TEST_QUANTUM_READINESS
case 0xC37: return TPI_QUANTUM_READINESS;
#endif
case 0x1057: return TPI_LOSS_BITS;
default: return INT_MAX;
}
}
static const unsigned short enum_2_tpi_val[LAST_TPI + 1] =
{
[TPI_ORIGINAL_CONNECTION_ID] = 0x0,
[TPI_MAX_IDLE_TIMEOUT] = 0x1,
[TPI_STATELESS_RESET_TOKEN] = 0x2,
[TPI_MAX_PACKET_SIZE] = 0x3,
[TPI_INIT_MAX_DATA] = 0x4,
[TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL] = 0x5,
[TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE] = 0x6,
[TPI_INIT_MAX_STREAM_DATA_UNI] = 0x7,
[TPI_INIT_MAX_STREAMS_BIDI] = 0x8,
[TPI_INIT_MAX_STREAMS_UNI] = 0x9,
[TPI_ACK_DELAY_EXPONENT] = 0xA,
[TPI_MAX_ACK_DELAY] = 0xB,
[TPI_DISABLE_ACTIVE_MIGRATION] = 0xC,
[TPI_PREFERRED_ADDRESS] = 0xD,
[TPI_ACTIVE_CONNECTION_ID_LIMIT] = 0xE,
#if LSQUIC_TEST_QUANTUM_READINESS
[TPI_QUANTUM_READINESS] = 0xC37,
#endif
[TPI_LOSS_BITS] = 0x1057,
};
static const char * const tpi2str[LAST_TPI + 1] =
{
[TPI_ORIGINAL_CONNECTION_ID] = "original_connection_id",
[TPI_MAX_IDLE_TIMEOUT] = "max_idle_timeout",
[TPI_STATELESS_RESET_TOKEN] = "stateless_reset_token",
[TPI_MAX_PACKET_SIZE] = "max_packet_size",
[TPI_INIT_MAX_DATA] = "init_max_data",
[TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL] = "init_max_stream_data_bidi_local",
[TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE] = "init_max_stream_data_bidi_remote",
[TPI_INIT_MAX_STREAM_DATA_UNI] = "init_max_stream_data_uni",
[TPI_INIT_MAX_STREAMS_BIDI] = "init_max_streams_bidi",
[TPI_INIT_MAX_STREAMS_UNI] = "init_max_streams_uni",
[TPI_ACK_DELAY_EXPONENT] = "ack_delay_exponent",
[TPI_MAX_ACK_DELAY] = "max_ack_delay",
[TPI_DISABLE_ACTIVE_MIGRATION] = "disable_active_migration",
[TPI_PREFERRED_ADDRESS] = "preferred_address",
[TPI_ACTIVE_CONNECTION_ID_LIMIT] = "active_connection_id_limit",
#if LSQUIC_TEST_QUANTUM_READINESS
[TPI_QUANTUM_READINESS] = "quantum_readiness",
#endif
[TPI_LOSS_BITS] = "loss_bits",
};
static const uint64_t def_vals[MAX_NUM_WITH_DEF_TPI + 1] =
{
[TPI_MAX_PACKET_SIZE] = TP_DEF_MAX_PACKET_SIZE,
[TPI_ACK_DELAY_EXPONENT] = TP_DEF_ACK_DELAY_EXP,
@ -42,7 +120,7 @@ static const uint64_t def_vals[MAX_TPI + 1] =
};
static const uint64_t max_vals[MAX_TPI + 1] =
static const uint64_t max_vals[MAX_NUMERIC_TPI + 1] =
{
[TPI_MAX_PACKET_SIZE] = VINT_MAX_VALUE,
[TPI_ACK_DELAY_EXPONENT] = VINT_MAX_VALUE,
@ -55,27 +133,7 @@ static const uint64_t max_vals[MAX_TPI + 1] =
[TPI_MAX_IDLE_TIMEOUT] = VINT_MAX_VALUE,
[TPI_MAX_ACK_DELAY] = TP_MAX_MAX_ACK_DELAY,
[TPI_ACTIVE_CONNECTION_ID_LIMIT] = VINT_MAX_VALUE,
};
#define TP_OFF(name_) ((uint64_t *) &((struct transport_params *) 0 \
)->tp_numerics_u.s.name_ - (uint64_t *) &((struct transport_params *) \
0)->tp_numerics_u.s)
/* Map enum transport_params to index of tp_numerics_u.a; for numeric values only */
static const unsigned tpi2idx[MAX_TPI + 1] =
{
[TPI_MAX_PACKET_SIZE] = TP_OFF(max_packet_size),
[TPI_ACK_DELAY_EXPONENT] = TP_OFF(ack_delay_exponent),
[TPI_INIT_MAX_STREAMS_UNI] = TP_OFF(init_max_streams_uni),
[TPI_INIT_MAX_STREAMS_BIDI] = TP_OFF(init_max_streams_bidi),
[TPI_INIT_MAX_DATA] = TP_OFF(init_max_data),
[TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL] = TP_OFF(init_max_stream_data_bidi_local),
[TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE] = TP_OFF(init_max_stream_data_bidi_remote),
[TPI_INIT_MAX_STREAM_DATA_UNI] = TP_OFF(init_max_stream_data_uni),
[TPI_MAX_IDLE_TIMEOUT] = TP_OFF(max_idle_timeout),
[TPI_MAX_ACK_DELAY] = TP_OFF(max_ack_delay),
[TPI_ACTIVE_CONNECTION_ID_LIMIT] = TP_OFF(active_connection_id_limit),
[TPI_LOSS_BITS] = 1,
};
@ -93,54 +151,78 @@ preferred_address_size (const struct transport_params *params)
int
lsquic_tp_encode (const struct transport_params *params,
lsquic_tp_has_pref_ipv4 (const struct transport_params *params)
{
return (params->tp_set & (1 << TPI_PREFERRED_ADDRESS))
&& params->tp_preferred_address.ipv4_port
&& !lsquic_is_zero(params->tp_preferred_address.ipv4_addr,
sizeof(params->tp_preferred_address.ipv4_addr));
}
int
lsquic_tp_has_pref_ipv6 (const struct transport_params *params)
{
return (params->tp_set & (1 << TPI_PREFERRED_ADDRESS))
&& params->tp_preferred_address.ipv6_port
&& !lsquic_is_zero(params->tp_preferred_address.ipv6_addr,
sizeof(params->tp_preferred_address.ipv6_addr));
}
int
lsquic_tp_encode (const struct transport_params *params, int is_server,
unsigned char *const buf, size_t bufsz)
{
unsigned char *p;
size_t need = 2;
uint16_t u16;
enum transport_param_id tpi;
unsigned bits[MAX_TPI + 1];
unsigned set;
unsigned bits[MAX_NUMERIC_TPI + 1];
if (params->tp_flags & TRAPA_SERVER)
set = params->tp_set; /* Will turn bits off for default values */
if (is_server)
{
if (params->tp_flags & TRAPA_ORIGINAL_CID)
if (set & (1 << TPI_ORIGINAL_CONNECTION_ID))
need += 4 + params->tp_original_cid.len;
if (params->tp_flags & TRAPA_RESET_TOKEN)
if (set & (1 << TPI_STATELESS_RESET_TOKEN))
need += 4 + sizeof(params->tp_stateless_reset_token);
if (params->tp_flags & (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6))
if (set & (1 << TPI_PREFERRED_ADDRESS))
need += 4 + preferred_address_size(params);
}
#if LSQUIC_TEST_QUANTUM_READINESS
else if (params->tp_flags & TRAPA_QUANTUM_READY)
else if (set & (1 << TPI_QUANTUM_READINESS))
need += 4 + QUANTUM_READY_SZ;
#endif
for (tpi = 0; tpi <= MAX_TPI; ++tpi)
if ((NUMERIC_TRANS_PARAMS & (1 << tpi))
&& params->tp_numerics_u.a[tpi2idx[tpi]] != def_vals[tpi])
for (tpi = 0; tpi <= MAX_NUMERIC_TPI; ++tpi)
if (set & (1 << tpi))
{
if (params->tp_numerics_u.a[tpi2idx[tpi]] < max_vals[tpi])
if (tpi > MAX_NUM_WITH_DEF_TPI
|| params->tp_numerics[tpi] != def_vals[tpi])
{
bits[tpi] = vint_val2bits(params->tp_numerics_u.a[tpi2idx[tpi]]);
need += 4 + (1 << bits[tpi]);
if (params->tp_numerics[tpi] <= max_vals[tpi])
{
bits[tpi] = vint_val2bits(params->tp_numerics[tpi]);
need += 4 + (1 << bits[tpi]);
}
else
{
LSQ_DEBUG("numeric value is too large (%"PRIu64" vs maximum "
"of %"PRIu64")", params->tp_numerics[tpi],
max_vals[tpi]);
return -1;
}
}
else
{
LSQ_DEBUG("numeric value is too large (%"PRIu64" vs maximum "
"of %"PRIu64")", params->tp_numerics_u.a[tpi2idx[tpi]],
max_vals[tpi]);
return -1;
}
set &= ~(1 << tpi); /* Don't write default value */
}
if (params->tp_disable_active_migration != TP_DEF_DISABLE_ACTIVE_MIGRATION)
need += 4 + 0;
if (params->tp_flags & TRAPA_QL_BITS_OLD)
need += 4 + 0;
else if (params->tp_flags & TRAPA_QL_BITS)
need += 4 + 1;
for (; tpi <= MAX_EMPTY_TPI; ++tpi)
if (set & (1 << tpi))
need += 4 + 0;
if (need > bufsz || need > UINT16_MAX)
{
@ -178,110 +260,65 @@ lsquic_tp_encode (const struct transport_params *params,
WRITE_UINT_TO_P(need - 2 + buf - p, 16);
for (tpi = 0; tpi <= MAX_TPI; ++tpi)
if (NUMERIC_TRANS_PARAMS & (1 << tpi))
for (tpi = 0; tpi <= LAST_TPI; ++tpi)
if (set & (1 << tpi))
{
if (params->tp_numerics_u.a[tpi2idx[tpi]] != def_vals[tpi])
{
WRITE_UINT_TO_P(tpi, 16);
WRITE_UINT_TO_P(1 << bits[tpi], 16);
vint_write(p, params->tp_numerics_u.a[tpi2idx[tpi]], bits[tpi],
1 << bits[tpi]);
p += 1 << bits[tpi];
}
}
else
WRITE_UINT_TO_P(enum_2_tpi_val[tpi], 16);
switch (tpi)
{
case TPI_MAX_IDLE_TIMEOUT:
case TPI_MAX_PACKET_SIZE:
case TPI_INIT_MAX_DATA:
case TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL:
case TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE:
case TPI_INIT_MAX_STREAM_DATA_UNI:
case TPI_INIT_MAX_STREAMS_BIDI:
case TPI_INIT_MAX_STREAMS_UNI:
case TPI_ACK_DELAY_EXPONENT:
case TPI_MAX_ACK_DELAY:
case TPI_ACTIVE_CONNECTION_ID_LIMIT:
case TPI_LOSS_BITS:
WRITE_UINT_TO_P(1 << bits[tpi], 16);
vint_write(p, params->tp_numerics[tpi], bits[tpi],
1 << bits[tpi]);
p += 1 << bits[tpi];
break;
case TPI_ORIGINAL_CONNECTION_ID:
if (params->tp_flags & TRAPA_ORIGINAL_CID)
{
WRITE_UINT_TO_P(TPI_ORIGINAL_CONNECTION_ID, 16);
WRITE_UINT_TO_P(params->tp_original_cid.len, 16);
WRITE_TO_P(params->tp_original_cid.idbuf,
params->tp_original_cid.len);
}
WRITE_UINT_TO_P(params->tp_original_cid.len, 16);
WRITE_TO_P(params->tp_original_cid.idbuf,
params->tp_original_cid.len);
break;
case TPI_STATELESS_RESET_TOKEN:
if (params->tp_flags & TRAPA_RESET_TOKEN)
{
WRITE_UINT_TO_P(TPI_STATELESS_RESET_TOKEN, 16);
WRITE_UINT_TO_P(sizeof(params->tp_stateless_reset_token),
16);
WRITE_TO_P(params->tp_stateless_reset_token,
sizeof(params->tp_stateless_reset_token));
}
WRITE_UINT_TO_P(sizeof(params->tp_stateless_reset_token), 16);
WRITE_TO_P(params->tp_stateless_reset_token,
sizeof(params->tp_stateless_reset_token));
break;
case TPI_PREFERRED_ADDRESS:
if (params->tp_flags
& (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6))
{
WRITE_UINT_TO_P(TPI_PREFERRED_ADDRESS, 16);
WRITE_UINT_TO_P(preferred_address_size(params), 16);
if (params->tp_flags & TRAPA_PREFADDR_IPv4)
{
WRITE_TO_P(&params->tp_preferred_address.ipv4_addr,
sizeof(params->tp_preferred_address.ipv4_addr));
WRITE_UINT_TO_P(params->tp_preferred_address.ipv4_port,
16);
}
else
{
memset(p, 0, 6);
p += 6;
}
if (params->tp_flags & TRAPA_PREFADDR_IPv6)
{
WRITE_TO_P(&params->tp_preferred_address.ipv6_addr,
sizeof(params->tp_preferred_address.ipv6_addr));
WRITE_UINT_TO_P(params->tp_preferred_address.ipv6_port,
16);
}
else
{
memset(p, 0, 18);
p += 18;
}
*p++ = params->tp_preferred_address.cid.len;
WRITE_TO_P(params->tp_preferred_address.cid.idbuf,
params->tp_preferred_address.cid.len);
WRITE_TO_P(params->tp_preferred_address.srst,
sizeof(params->tp_preferred_address.srst));
}
WRITE_UINT_TO_P(preferred_address_size(params), 16);
WRITE_TO_P(&params->tp_preferred_address.ipv4_addr,
sizeof(params->tp_preferred_address.ipv4_addr));
WRITE_UINT_TO_P(params->tp_preferred_address.ipv4_port, 16);
WRITE_TO_P(&params->tp_preferred_address.ipv6_addr,
sizeof(params->tp_preferred_address.ipv6_addr));
WRITE_UINT_TO_P(params->tp_preferred_address.ipv6_port, 16);
*p++ = params->tp_preferred_address.cid.len;
WRITE_TO_P(params->tp_preferred_address.cid.idbuf,
params->tp_preferred_address.cid.len);
WRITE_TO_P(params->tp_preferred_address.srst,
sizeof(params->tp_preferred_address.srst));
break;
case TPI_DISABLE_ACTIVE_MIGRATION:
if (params->tp_disable_active_migration != TP_DEF_DISABLE_ACTIVE_MIGRATION)
{
WRITE_UINT_TO_P(TPI_DISABLE_ACTIVE_MIGRATION, 16);
WRITE_UINT_TO_P(0, 16);
}
WRITE_UINT_TO_P(0, 16);
break;
default:
assert(0);
return -1;
}
if (params->tp_flags & TRAPA_QL_BITS_OLD)
{
WRITE_UINT_TO_P(TPI_QL_BITS, 16);
WRITE_UINT_TO_P(0, 16);
}
else if (params->tp_flags & TRAPA_QL_BITS)
{
WRITE_UINT_TO_P(TPI_QL_BITS, 16);
WRITE_UINT_TO_P(1, 16);
*p++ = !!params->tp_loss_bits;
}
#if LSQUIC_TEST_QUANTUM_READINESS
if (params->tp_flags & TRAPA_QUANTUM_READY)
{
WRITE_UINT_TO_P(TPI_QUANTUM_READINESS, 16);
WRITE_UINT_TO_P(QUANTUM_READY_SZ, 16);
memset(p, 'Q', QUANTUM_READY_SZ);
p += QUANTUM_READY_SZ;
}
case TPI_QUANTUM_READINESS:
WRITE_UINT_TO_P(QUANTUM_READY_SZ, 16);
memset(p, 'Q', QUANTUM_READY_SZ);
p += QUANTUM_READY_SZ;
break;
#endif
}
}
assert(buf + need == p);
return (int) (p - buf);
@ -298,18 +335,15 @@ lsquic_tp_decode (const unsigned char *const buf, size_t bufsz,
{
const unsigned char *p, *end, *q;
uint16_t len, param_id, tlen;
enum transport_param_id tpi;
unsigned set_of_ids;
int s;
uint64_t tmp64;
p = buf;
end = buf + bufsz;
*params = TP_INITIALIZER();
if (is_server)
params->tp_flags |= TRAPA_SERVER;
if (end - p < 2)
return -1;
READ_UINT(len, 16, p, 2);
@ -337,43 +371,43 @@ lsquic_tp_decode (const unsigned char *const buf, size_t bufsz,
p += 2;
if (len > end - p)
return -1;
/* If we need to support parameter IDs 31 and up, we will need to
* change this code:
*/
if (param_id < sizeof(set_of_ids) * 8)
tpi = tpi_val_2_enum(param_id);
if (tpi <= LAST_TPI)
{
/* Only check duplicates for IDs <= 31: all standard parameters
* fit in a bitmask 32 bits wide.
*/
if (set_of_ids & (1 << param_id))
if (set_of_ids & (1 << tpi))
return -1;
set_of_ids |= 1 << param_id;
set_of_ids |= 1 << tpi;
}
else
goto gt32;
if (NUMERIC_TRANS_PARAMS & (1u << param_id))
switch (tpi)
{
case TPI_MAX_IDLE_TIMEOUT:
case TPI_MAX_PACKET_SIZE:
case TPI_INIT_MAX_DATA:
case TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL:
case TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE:
case TPI_INIT_MAX_STREAM_DATA_UNI:
case TPI_INIT_MAX_STREAMS_BIDI:
case TPI_INIT_MAX_STREAMS_UNI:
case TPI_ACK_DELAY_EXPONENT:
case TPI_MAX_ACK_DELAY:
case TPI_ACTIVE_CONNECTION_ID_LIMIT:
case TPI_LOSS_BITS:
switch (len)
{
case 1:
case 2:
case 4:
case 8:
s = vint_read(p, p + len,
&params->tp_numerics_u.a[tpi2idx[param_id]]);
s = vint_read(p, p + len, &params->tp_numerics[tpi]);
if (s == len)
{
if (params->tp_numerics_u.a[tpi2idx[param_id]]
> max_vals[param_id])
if (params->tp_numerics[tpi] > max_vals[tpi])
{
LSQ_DEBUG("numeric value of parameter 0x%X is too "
"large (%"PRIu64" vs maximum of %"PRIu64,
param_id,
params->tp_numerics_u.a[tpi2idx[param_id]],
max_vals[param_id]);
param_id, params->tp_numerics[tpi], max_vals[tpi]);
return -1;
}
p += s;
break;
}
else
@ -383,125 +417,85 @@ lsquic_tp_decode (const unsigned char *const buf, size_t bufsz,
return -1;
}
default:
LSQ_DEBUG("invalid length=%u for numeric transport parameter",
len);
LSQ_DEBUG("invalid length=%u for numeric transport "
"parameter 0x%X", len, param_id);
return -1;
}
}
else
{
gt32: switch (param_id)
break;
case TPI_DISABLE_ACTIVE_MIGRATION:
EXPECT_LEN(0);
break;
case TPI_STATELESS_RESET_TOKEN:
/* Client MUST not include reset token,
* see [draft-ietf-quic-transport-11], Section 6.4.1
*/
if (!is_server)
return -1;
EXPECT_LEN(sizeof(params->tp_stateless_reset_token));
memcpy(params->tp_stateless_reset_token, p,
sizeof(params->tp_stateless_reset_token));
break;
case TPI_ORIGINAL_CONNECTION_ID:
/* Client MUST not original connecti ID,
* see [draft-ietf-quic-transport-15], Section 6.6.1
*/
if (!is_server)
return -1;
if (len > MAX_CID_LEN)
return -1;
memcpy(params->tp_original_cid.idbuf, p, len);
params->tp_original_cid.len = len;
break;
case TPI_PREFERRED_ADDRESS:
/* Client MUST not include preferred address,
* see [draft-ietf-quic-transport-12], Section 6.4.1
*/
if (!is_server)
return -1;
q = p;
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv4_addr));
memcpy(params->tp_preferred_address.ipv4_addr, q,
sizeof(params->tp_preferred_address.ipv4_addr));
q += sizeof(params->tp_preferred_address.ipv4_addr);
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv4_port));
READ_UINT(params->tp_preferred_address.ipv4_port, 16, q, 2);
q += 2;
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv6_addr));
memcpy(params->tp_preferred_address.ipv6_addr, q,
sizeof(params->tp_preferred_address.ipv6_addr));
q += sizeof(params->tp_preferred_address.ipv6_addr);
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv6_port));
READ_UINT(params->tp_preferred_address.ipv6_port, 16, q, 2);
q += 2;
EXPECT_AT_LEAST(1);
tlen = *q;
q += 1;
if (tlen < 4 || tlen > MAX_CID_LEN)
{
case TPI_DISABLE_ACTIVE_MIGRATION:
EXPECT_LEN(0);
params->tp_disable_active_migration = 1;
break;
case TPI_STATELESS_RESET_TOKEN:
/* Client MUST not include reset token,
* see [draft-ietf-quic-transport-11], Section 6.4.1
*/
if (!is_server)
return -1;
EXPECT_LEN(sizeof(params->tp_stateless_reset_token));
memcpy(params->tp_stateless_reset_token, p,
sizeof(params->tp_stateless_reset_token));
params->tp_flags |= TRAPA_RESET_TOKEN;
break;
case TPI_ORIGINAL_CONNECTION_ID:
/* Client MUST not original connecti ID,
* see [draft-ietf-quic-transport-15], Section 6.6.1
*/
if (!is_server)
return -1;
if (len > MAX_CID_LEN)
return -1;
memcpy(params->tp_original_cid.idbuf, p, len);
params->tp_original_cid.len = len;
params->tp_flags |= TRAPA_ORIGINAL_CID;
break;
case TPI_PREFERRED_ADDRESS:
/* Client MUST not include preferred address,
* see [draft-ietf-quic-transport-12], Section 6.4.1
*/
if (!is_server)
return -1;
q = p;
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv4_addr));
memcpy(params->tp_preferred_address.ipv4_addr, q,
sizeof(params->tp_preferred_address.ipv4_addr));
q += sizeof(params->tp_preferred_address.ipv4_addr);
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv4_port));
READ_UINT(params->tp_preferred_address.ipv4_port, 16, q, 2);
q += 2;
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv6_addr));
memcpy(params->tp_preferred_address.ipv6_addr, q,
sizeof(params->tp_preferred_address.ipv6_addr));
q += sizeof(params->tp_preferred_address.ipv6_addr);
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv6_port));
READ_UINT(params->tp_preferred_address.ipv6_port, 16, q, 2);
q += 2;
EXPECT_AT_LEAST(1);
tlen = *q;
q += 1;
if (tlen < 4 || tlen > MAX_CID_LEN)
{
LSQ_DEBUG("preferred server address contains invalid "
"CID length of %"PRIu16" bytes", tlen);
return -1;
}
EXPECT_AT_LEAST(tlen);
memcpy(params->tp_preferred_address.cid.idbuf, q, tlen);
params->tp_preferred_address.cid.len = tlen;
q += tlen;
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.srst));
memcpy(params->tp_preferred_address.srst, q,
sizeof(params->tp_preferred_address.srst));
q += sizeof(params->tp_preferred_address.srst);
if (q != p + len)
return -1;
if (params->tp_preferred_address.ipv4_port
&& !lsquic_is_zero(params->tp_preferred_address.ipv4_addr,
sizeof(params->tp_preferred_address.ipv4_addr)))
params->tp_flags |= TRAPA_PREFADDR_IPv4;
if (params->tp_preferred_address.ipv6_port
&& !lsquic_is_zero(params->tp_preferred_address.ipv6_addr,
sizeof(params->tp_preferred_address.ipv6_addr)))
params->tp_flags |= TRAPA_PREFADDR_IPv6;
break;
case TPI_QL_BITS:
switch (len)
{
case 0:
/* Old-school boolean */
params->tp_flags |= TRAPA_QL_BITS;
params->tp_loss_bits = 1;
break;
case 1:
case 2:
case 4:
case 8:
s = vint_read(p, p + len, &tmp64);
if (s != len)
{
LSQ_DEBUG("cannot read the value of numeric transport "
"param loss_bits of length %u", len);
return -1;
}
if (!(tmp64 == 0 || tmp64 == 1))
{
LSQ_DEBUG("unexpected value of loss_bits TP: %"PRIu64,
tmp64);
return -1;
}
params->tp_loss_bits = tmp64;
params->tp_flags |= TRAPA_QL_BITS;
break;
default:
return -1;
}
break;
LSQ_DEBUG("preferred server address contains invalid "
"CID length of %"PRIu16" bytes", tlen);
return -1;
}
p += len;
EXPECT_AT_LEAST(tlen);
memcpy(params->tp_preferred_address.cid.idbuf, q, tlen);
params->tp_preferred_address.cid.len = tlen;
q += tlen;
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.srst));
memcpy(params->tp_preferred_address.srst, q,
sizeof(params->tp_preferred_address.srst));
q += sizeof(params->tp_preferred_address.srst);
if (q != p + len)
return -1;
break;
default:
/* Do nothing: skip this transport parameter */
break;
}
p += len;
if (tpi <= LAST_TPI)
{
params->tp_set |= 1 << tpi;
params->tp_decoded |= 1 << tpi;
}
}
@ -518,32 +512,40 @@ lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz)
{
char *const end = buf + sz;
int nw;
enum transport_param_id tpi;
char tok_str[sizeof(params->tp_stateless_reset_token) * 2 + 1];
char addr_str[INET6_ADDRSTRLEN];
#define SEMICOLON "; "
#define WRITE_ONE_PARAM(name, fmt) do { \
nw = snprintf(buf, end - buf, #name ": " fmt SEMICOLON, params->tp_##name); \
buf += nw; \
if (buf >= end) \
return; \
} while (0)
WRITE_ONE_PARAM(init_max_stream_data_bidi_local, "%"PRIu64);
WRITE_ONE_PARAM(init_max_stream_data_bidi_remote, "%"PRIu64);
WRITE_ONE_PARAM(init_max_stream_data_uni, "%"PRIu64);
WRITE_ONE_PARAM(init_max_data, "%"PRIu64);
WRITE_ONE_PARAM(max_idle_timeout, "%"PRIu64);
WRITE_ONE_PARAM(init_max_streams_bidi, "%"PRIu64);
WRITE_ONE_PARAM(init_max_streams_uni, "%"PRIu64);
WRITE_ONE_PARAM(max_packet_size, "%"PRIu64);
WRITE_ONE_PARAM(ack_delay_exponent, "%"PRIu64);
WRITE_ONE_PARAM(active_connection_id_limit, "%"PRIu64);
WRITE_ONE_PARAM(disable_active_migration, "%hhd");
#undef SEMICOLON
#define SEMICOLON ""
WRITE_ONE_PARAM(max_ack_delay, "%"PRIu64);
if (params->tp_flags & TRAPA_RESET_TOKEN)
for (tpi = 0; tpi <= MAX_NUMERIC_TPI; ++tpi)
if (params->tp_set & (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL))
{
nw = snprintf(buf, end - buf, "%.*s%s: %"PRIu64,
(buf + sz > end) << 1, "; ", tpi2str[tpi],
params->tp_numerics[tpi]);
buf += nw;
if (buf >= end)
return;
}
for (; tpi <= MAX_EMPTY_TPI; ++tpi)
if (params->tp_set & (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL))
{
nw = snprintf(buf, end - buf, "%.*s%s",
(buf + sz > end) << 1, "; ", tpi2str[tpi]);
buf += nw;
if (buf >= end)
return;
}
#if LSQUIC_TEST_QUANTUM_READINESS
if (params->tp_set & (1 << TPI_QUANTUM_READINESS))
{
nw = snprintf(buf, end - buf, "%.*s%s",
(buf + sz > end) << 1, "; ", tpi2str[TPI_QUANTUM_READINESS]);
buf += nw;
if (buf >= end)
return;
}
#endif
if (params->tp_set & (1 << TPI_STATELESS_RESET_TOKEN))
{
lsquic_hexstr(params->tp_stateless_reset_token,
sizeof(params->tp_stateless_reset_token), tok_str, sizeof(tok_str));
@ -552,7 +554,7 @@ lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz)
if (buf >= end)
return;
}
if (params->tp_flags & TRAPA_RESET_TOKEN)
if (params->tp_set & (1 << TPI_ORIGINAL_CONNECTION_ID))
{
char cidbuf_[MAX_CID_LEN * 2 + 1];
nw = snprintf(buf, end - buf, "; original DCID (ODCID): %"CID_FMT,
@ -561,7 +563,7 @@ lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz)
if (buf >= end)
return;
}
if (params->tp_flags & TRAPA_PREFADDR_IPv4)
if (lsquic_tp_has_pref_ipv4(params))
{
if (inet_ntop(AF_INET, params->tp_preferred_address.ipv4_addr,
addr_str, sizeof(addr_str)))
@ -573,7 +575,7 @@ lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz)
return;
}
}
if (params->tp_flags & TRAPA_PREFADDR_IPv6)
if (lsquic_tp_has_pref_ipv6(params))
{
if (inet_ntop(AF_INET6, params->tp_preferred_address.ipv6_addr,
addr_str, sizeof(addr_str)))
@ -585,15 +587,4 @@ lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz)
return;
}
}
if (params->tp_flags & TRAPA_QL_BITS)
{
nw = snprintf(buf, end - buf, "; QL loss bits: %hhu",
params->tp_loss_bits);
buf += nw;
if (buf >= end)
return;
}
#undef SEMICOLON
#undef WRITE_ONE_PARAM
}

View File

@ -6,98 +6,76 @@
#ifndef LSQUIC_TRANS_PARAMS_H
#define LSQUIC_TRANS_PARAMS_H 1
/* [draft-ietf-quic-transport-17], Section 18 */
/* Transport parameters are grouped by the type of their values: numeric,
* empty, and custom.
*
* The enum values are arbitrary. The literal transport parameter ID
* *values* (e.g. 0x1057 for loss bits) are not exposed by the API.
*/
enum transport_param_id
{
TPI_ORIGINAL_CONNECTION_ID = 0,
TPI_MAX_IDLE_TIMEOUT = 1,
TPI_STATELESS_RESET_TOKEN = 2,
TPI_MAX_PACKET_SIZE = 3,
TPI_INIT_MAX_DATA = 4,
TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL = 5,
TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE = 6,
TPI_INIT_MAX_STREAM_DATA_UNI = 7,
TPI_INIT_MAX_STREAMS_BIDI = 8,
TPI_INIT_MAX_STREAMS_UNI = 9,
TPI_ACK_DELAY_EXPONENT = 10,
TPI_MAX_ACK_DELAY = 11,
TPI_DISABLE_ACTIVE_MIGRATION = 12,
TPI_PREFERRED_ADDRESS = 13,
TPI_ACTIVE_CONNECTION_ID_LIMIT = 14,
#define MAX_TPI TPI_ACTIVE_CONNECTION_ID_LIMIT
};
/*
* Numeric transport parameters that have default values:
*/
TPI_MAX_IDLE_TIMEOUT,
TPI_MAX_PACKET_SIZE,
TPI_INIT_MAX_DATA,
TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL,
TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE,
TPI_INIT_MAX_STREAM_DATA_UNI,
TPI_INIT_MAX_STREAMS_BIDI,
TPI_INIT_MAX_STREAMS_UNI,
TPI_ACK_DELAY_EXPONENT,
TPI_MAX_ACK_DELAY,
TPI_ACTIVE_CONNECTION_ID_LIMIT, MAX_NUM_WITH_DEF_TPI = TPI_ACTIVE_CONNECTION_ID_LIMIT,
#define NUMERIC_TRANS_PARAMS (\
(1 << TPI_MAX_PACKET_SIZE) \
|(1 << TPI_INIT_MAX_STREAMS_UNI) \
|(1 << TPI_INIT_MAX_STREAMS_UNI) \
|(1 << TPI_INIT_MAX_STREAMS_BIDI) \
|(1 << TPI_INIT_MAX_DATA) \
|(1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL) \
|(1 << TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE) \
|(1 << TPI_INIT_MAX_STREAM_DATA_UNI) \
|(1 << TPI_MAX_IDLE_TIMEOUT) \
|(1 << TPI_MAX_ACK_DELAY) \
|(1 << TPI_ACK_DELAY_EXPONENT) \
|(1 << TPI_ACTIVE_CONNECTION_ID_LIMIT) \
)
/*
* Numeric transport parameters without default values:
*/
TPI_LOSS_BITS, MAX_NUMERIC_TPI = TPI_LOSS_BITS,
#define IQUIC_MAX_SUPP_VERS ((2<<7) - 4)/sizeof(uint32_t)
/*
* Empty transport parameters:
*/
TPI_DISABLE_ACTIVE_MIGRATION, MAX_EMPTY_TPI = TPI_DISABLE_ACTIVE_MIGRATION,
enum trapa_flags
{
TRAPA_RESET_TOKEN = 1 << 0, /* Reset token is set */
TRAPA_SERVER = 1 << 1, /* Server transport parameters */
TRAPA_PREFADDR_IPv4 = 1 << 2, /* Preferred IPv4 address is set */
TRAPA_PREFADDR_IPv6 = 1 << 3, /* Preferred IPv6 address is set */
TRAPA_ORIGINAL_CID = 1 << 4, /* Original CID is set */
/*
* Custom handlers:
*/
TPI_PREFERRED_ADDRESS,
TPI_ORIGINAL_CONNECTION_ID,
#if LSQUIC_TEST_QUANTUM_READINESS
#define QUANTUM_READY_SZ 1200
/* https://github.com/quicwg/base-drafts/wiki/Quantum-Readiness-test */
#define TPI_QUANTUM_READINESS 3127
TRAPA_QUANTUM_READY = 1 << 5, /* Include "Quantum Readiness" TP */
#define QUANTUM_READY_SZ 1200
TPI_QUANTUM_READINESS,
#endif
#define TPI_QL_BITS 0x1057 /* 1057 is 133t for "lost" */
TRAPA_QL_BITS = 1 << 6, /* tp_loss_bits contains valid value */
TRAPA_QL_BITS_OLD = 1 << 7, /* Send old-school boolean loss_bits TP.
* Not set on decoded transport parameters.
*/
TPI_STATELESS_RESET_TOKEN, LAST_TPI = TPI_STATELESS_RESET_TOKEN
};
struct transport_params
{
enum trapa_flags tp_flags;
/* Which transport parameters values are set: */
unsigned tp_set;
union {
struct {
uint64_t init_max_stream_data_bidi_local;
uint64_t init_max_stream_data_bidi_remote;
uint64_t init_max_stream_data_uni;
uint64_t init_max_data;
uint64_t max_idle_timeout;
uint64_t init_max_streams_bidi;
uint64_t init_max_streams_uni;
uint64_t max_packet_size;
uint64_t ack_delay_exponent;
uint64_t max_ack_delay;
uint64_t active_connection_id_limit;
} s;
uint64_t a[11];
} tp_numerics_u;
#define tp_init_max_stream_data_bidi_local tp_numerics_u.s.init_max_stream_data_bidi_local
#define tp_init_max_stream_data_bidi_remote tp_numerics_u.s.init_max_stream_data_bidi_remote
#define tp_init_max_stream_data_uni tp_numerics_u.s.init_max_stream_data_uni
#define tp_init_max_data tp_numerics_u.s.init_max_data
#define tp_max_idle_timeout tp_numerics_u.s.max_idle_timeout
#define tp_init_max_streams_bidi tp_numerics_u.s.init_max_streams_bidi
#define tp_init_max_streams_uni tp_numerics_u.s.init_max_streams_uni
#define tp_max_packet_size tp_numerics_u.s.max_packet_size
#define tp_ack_delay_exponent tp_numerics_u.s.ack_delay_exponent
#define tp_max_ack_delay tp_numerics_u.s.max_ack_delay
#define tp_active_connection_id_limit tp_numerics_u.s.active_connection_id_limit
/* Which transport parameters were present (set by the decoder): */
unsigned tp_decoded;
uint64_t tp_numerics[MAX_NUMERIC_TPI + 1];
#define tp_init_max_stream_data_bidi_local tp_numerics[TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL]
#define tp_init_max_stream_data_bidi_remote tp_numerics[TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE]
#define tp_init_max_stream_data_uni tp_numerics[TPI_INIT_MAX_STREAM_DATA_UNI]
#define tp_init_max_data tp_numerics[TPI_INIT_MAX_DATA]
#define tp_max_idle_timeout tp_numerics[TPI_MAX_IDLE_TIMEOUT]
#define tp_init_max_streams_bidi tp_numerics[TPI_INIT_MAX_STREAMS_BIDI]
#define tp_init_max_streams_uni tp_numerics[TPI_INIT_MAX_STREAMS_UNI]
#define tp_max_packet_size tp_numerics[TPI_MAX_PACKET_SIZE]
#define tp_ack_delay_exponent tp_numerics[TPI_ACK_DELAY_EXPONENT]
#define tp_max_ack_delay tp_numerics[TPI_MAX_ACK_DELAY]
#define tp_active_connection_id_limit tp_numerics[TPI_ACTIVE_CONNECTION_ID_LIMIT]
#define tp_loss_bits tp_numerics[TPI_LOSS_BITS]
unsigned char tp_loss_bits; /* Valid values 0, 1. Set if TRAPA_QL_BITS is set. */
signed char tp_disable_active_migration;
uint8_t tp_stateless_reset_token[IQUIC_SRESET_TOKEN_SZ];
struct {
uint8_t ipv4_addr[4];
@ -127,6 +105,7 @@ struct transport_params
#define TP_MAX_MAX_ACK_DELAY ((1u << 14) - 1)
#define TP_DEFAULT_VALUES \
.tp_set = ((1 << (MAX_NUM_WITH_DEF_TPI + 1)) - 1), \
.tp_active_connection_id_limit = TP_DEF_ACTIVE_CONNECTION_ID_LIMIT, \
.tp_max_idle_timeout = TP_DEF_MAX_IDLE_TIMEOUT, \
.tp_max_ack_delay = TP_DEF_MAX_ACK_DELAY, \
@ -135,7 +114,6 @@ struct transport_params
.tp_init_max_streams_bidi = TP_DEF_INIT_MAX_STREAMS_BIDI, \
.tp_init_max_streams_uni = TP_DEF_INIT_MAX_STREAMS_UNI, \
.tp_init_max_data = TP_DEF_INIT_MAX_DATA, \
.tp_disable_active_migration = TP_DEF_DISABLE_ACTIVE_MIGRATION, \
.tp_init_max_stream_data_bidi_local = TP_DEF_INIT_MAX_STREAM_DATA_BIDI_LOCAL, \
.tp_init_max_stream_data_bidi_remote = TP_DEF_INIT_MAX_STREAM_DATA_BIDI_REMOTE, \
.tp_init_max_stream_data_uni = TP_DEF_INIT_MAX_STREAM_DATA_UNI
@ -143,7 +121,7 @@ struct transport_params
#define TP_INITIALIZER() (struct transport_params) { TP_DEFAULT_VALUES }
int
lsquic_tp_encode (const struct transport_params *,
lsquic_tp_encode (const struct transport_params *, int is_server,
unsigned char *buf, size_t bufsz);
int
@ -158,4 +136,10 @@ lsquic_tp_decode (const unsigned char *buf, size_t bufsz,
void
lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz);
int
lsquic_tp_has_pref_ipv4 (const struct transport_params *);
int
lsquic_tp_has_pref_ipv6 (const struct transport_params *);
#endif

View File

@ -29,6 +29,8 @@ struct trapa_test
} flags;
struct transport_params params;
size_t enc_len, dec_len;
unsigned addl_set;
int is_server;
int expect_decode_err;
unsigned char encoded[ENC_BUF_SZ];
};
@ -53,13 +55,20 @@ static const struct trapa_test tests[] =
.line = __LINE__,
.flags = TEST_ENCODE | TEST_DECODE,
.params = {
.tp_flags = 0,
.tp_set = (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL)
| (1 << TPI_INIT_MAX_DATA)
| (1 << TPI_MAX_IDLE_TIMEOUT)
| (1 << TPI_MAX_ACK_DELAY)
| (1 << TPI_MAX_PACKET_SIZE)
| (1 << TPI_ACK_DELAY_EXPONENT)
| (1 << TPI_ACTIVE_CONNECTION_ID_LIMIT),
.tp_init_max_stream_data_bidi_local = 0x12348877,
.tp_init_max_data = 0xAABB,
.tp_max_idle_timeout = 10 * 1000,
.tp_max_ack_delay = TP_DEF_MAX_ACK_DELAY,
.tp_active_connection_id_limit = 7,
},
.is_server = 0,
.enc_len = 39,
.encoded =
/* Overall length */ "\x00\x25"
@ -94,12 +103,12 @@ static const struct trapa_test tests[] =
.flags = TEST_ENCODE | TEST_DECODE,
.params = {
TP_DEFAULT_VALUES,
.tp_flags = TRAPA_SERVER,
.tp_init_max_data = 0x123456,
.tp_init_max_stream_data_bidi_local = 0xABCDEF88,
.tp_disable_active_migration = 1,
.tp_max_packet_size = 0x333,
},
.is_server = 1,
.addl_set = 1 << TPI_DISABLE_ACTIVE_MIGRATION,
.enc_len = 32,
.encoded =
/* Overall length */ "\x00\x1E"
@ -117,7 +126,6 @@ static const struct trapa_test tests[] =
.flags = TEST_DECODE,
.params = {
TP_DEFAULT_VALUES,
.tp_flags = TRAPA_SERVER | TRAPA_PREFADDR_IPv4 | TRAPA_PREFADDR_IPv6,
.tp_max_ack_delay = 25,
.tp_max_packet_size = 0x333,
.tp_preferred_address = {
@ -129,6 +137,8 @@ static const struct trapa_test tests[] =
.srst = "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F",
},
},
.is_server = 1,
.addl_set = 1 << TPI_PREFERRED_ADDRESS,
.enc_len = 0x3E + 2,
.encoded =
/* Overall length */ "\x00\x3E"
@ -154,9 +164,8 @@ params_are_equal (const struct transport_params *a,
const struct transport_params *b)
{
#define MCMP(f) 0 == memcmp(&a->f, &b->f, sizeof(a->f))
return a->tp_flags == b->tp_flags
&& MCMP(tp_numerics_u)
&& a->tp_disable_active_migration == b->tp_disable_active_migration
return MCMP(tp_numerics)
&& MCMP(tp_set)
&& MCMP(tp_stateless_reset_token)
&& MCMP(tp_preferred_address.ipv4_addr)
&& MCMP(tp_preferred_address.ipv6_addr)
@ -175,14 +184,18 @@ params_are_equal (const struct transport_params *a,
static void
run_test (const struct trapa_test *test)
{
struct transport_params source_params;
struct transport_params decoded_params;
size_t dec_len;
int s;
unsigned char buf[ENC_BUF_SZ];
source_params = test->params;
source_params.tp_set |= test->addl_set;
if (test->flags & TEST_ENCODE)
{
s = lsquic_tp_encode(&test->params, buf, sizeof(buf));
s = lsquic_tp_encode(&source_params, test->is_server, buf, sizeof(buf));
assert(s > 0);
assert((size_t) s == test->enc_len);
assert(0 == memcmp(test->encoded, buf, s));
@ -195,12 +208,16 @@ run_test (const struct trapa_test *test)
else
dec_len = sizeof(buf);
s = lsquic_tp_decode(test->encoded, dec_len,
test->params.tp_flags & TRAPA_SERVER, &decoded_params);
test->is_server, &decoded_params);
if (!test->expect_decode_err)
{
assert(s > 0);
assert((size_t) s == test->enc_len);
s = params_are_equal(&test->params, &decoded_params);
/* The decoder initializes all default values, so set the flag
* accordingly:
*/
source_params.tp_set |= ((1 << (MAX_NUM_WITH_DEF_TPI + 1)) - 1);
s = params_are_equal(&source_params, &decoded_params);
assert(s);
}
else