Release 2.8.0

- [FEATURE] Add support for Q050.
- [OPTIMIZATION] Reduce mallocs in gQUIC handshake.
- [BUGFIX] Disable redo of failed STREAM frame insertion with debug
  logging.
This commit is contained in:
Dmitri Tikhonov 2019-12-23 16:14:20 -05:00
parent ff892190dd
commit 7a8b2ece3a
36 changed files with 2477 additions and 573 deletions

View file

@ -5,7 +5,6 @@ SET(lsquic_STAT_SRCS
lsquic_arr.c
lsquic_attq.c
lsquic_bbr.c
lsquic_buf.c
lsquic_bw_sampler.c
lsquic_cfcw.c
lsquic_chsk_stream.c
@ -50,6 +49,7 @@ SET(lsquic_STAT_SRCS
lsquic_packet_out.c
lsquic_packints.c
lsquic_parse_Q046.c
lsquic_parse_Q050.c
lsquic_parse_common.c
lsquic_parse_gquic_be.c
lsquic_parse_gquic_common.c

View file

@ -1,92 +0,0 @@
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
/*
* lsquic_buf.c
*/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#include <vc_compat.h>
#endif
#include "lsquic_buf.h"
static int
lsquic_buf_reserve (struct lsquic_buf *buf, int size)
{
char *new_buf;
if (buf->bufend - buf->buf == size)
return 0;
new_buf = realloc(buf->buf, size);
if (new_buf != 0 || size == 0)
{
buf->end = new_buf + (buf->end - buf->buf);
buf->buf = new_buf;
buf->bufend = new_buf + size;
if (buf->end > buf->bufend)
buf->end = buf->bufend;
return 0;
}
else
return -1;
}
static int
lsquic_buf_grow (struct lsquic_buf *buf, int size)
{
size = ((size + 511) >> 9) << 9;
return lsquic_buf_reserve(buf, lsquic_buf_capacity(buf) + size);
}
struct lsquic_buf *
lsquic_buf_create (int size)
{
struct lsquic_buf *buf;
buf = calloc(1, sizeof(*buf));
if (!buf)
return NULL;
if (0 != lsquic_buf_reserve(buf, size))
{
free(buf);
return NULL;
}
return buf;
}
int
lsquic_buf_append (struct lsquic_buf *buf, const char *str, int size)
{
if (buf == NULL || size < 0)
{
errno = EINVAL;
return -1;
}
if (size == 0)
return 0;
if (size > lsquic_buf_avail(buf))
{
if (lsquic_buf_grow(buf, size - lsquic_buf_avail(buf)) != 0)
return -1;
}
memmove(buf->end, str, size);
buf->end += size;
return size;
}
void
lsquic_buf_destroy (struct lsquic_buf *buf)
{
free(buf->buf);
free(buf);
}

View file

@ -1,35 +0,0 @@
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
/*
* lsquic_buf.h
*/
#ifndef LSQUIC_BUF_H
#define LSQUIC_BUF_H 1
struct lsquic_buf
{
char *buf, *end, *bufend;
};
struct lsquic_buf *
lsquic_buf_create (int);
int
lsquic_buf_append (struct lsquic_buf *, const char *, int);
#define lsquic_buf_begin(buf_) ((buf_)->buf)
#define lsquic_buf_size(buf_) ((buf_)->end - (buf_)->buf)
#define lsquic_buf_avail(buf_) ((buf_)->bufend - (buf_)->end)
#define lsquic_buf_capacity(buf_) ((buf_)->bufend - (buf_)->buf)
#define lsquic_buf_clear(buf_) do { \
(buf_)->end = (buf_)->buf; \
} while (0)
void
lsquic_buf_destroy (struct lsquic_buf *);
#endif

View file

@ -8,6 +8,7 @@
#include <openssl/x509.h>
#include <openssl/rand.h>
#include <openssl/curve25519.h>
#include <openssl/hkdf.h>
#include <openssl/hmac.h>
#include <zlib.h>
@ -208,58 +209,30 @@ int lshkdf_expand(const unsigned char *prk, const unsigned char *info, int info_
uint16_t s_key_len, uint8_t *s_key,
uint16_t c_key_iv_len, uint8_t *c_key_iv,
uint16_t s_key_iv_len, uint8_t *s_key_iv,
uint16_t sub_key_len, uint8_t *sub_key)
uint16_t sub_key_len, uint8_t *sub_key,
uint8_t *c_hp, uint8_t *s_hp)
{
int L = c_key_len + s_key_len + c_key_iv_len + s_key_iv_len + sub_key_len;
int N = (L + SHA256LEN - 1) / SHA256LEN;
unsigned char *p_org;
uint8_t *buf;
const unsigned L = c_key_len + s_key_len + c_key_iv_len + s_key_iv_len
+ sub_key_len
+ (c_hp ? c_key_len : 0)
+ (s_hp ? s_key_len : 0)
;
unsigned char *p;
unsigned char T[SHA256LEN + 1];
int T_len = 0;
int i;
uint8_t *pb;
unsigned char output[
EVP_MAX_KEY_LENGTH * 2 /* Keys */
+ EVP_MAX_IV_LENGTH * 2 /* IVs */
+ 32 /* Subkey */
+ EVP_MAX_KEY_LENGTH * 2 /* Header protection */
];
p_org = malloc(N * SHA256LEN);
if (!p_org)
return -1;
assert((size_t) L <= sizeof(output));
buf = malloc(SHA256LEN + info_len + 13);
if (!buf)
{
free(p_org);
return -1;
}
p = p_org;
for (i = 1; i <= N; ++i)
{
pb = buf;
if (T_len > 0)
{
memcpy(pb, T, T_len);
pb += T_len;
}
memcpy(pb, info, info_len);
pb += info_len;
*pb = i;
++pb;
HMAC(EVP_sha256(), prk, SHA256LEN, buf, pb - buf, T, NULL);
if (i != N)
T_len = SHA256LEN;
else
T_len = L - (N - 1) * SHA256LEN;
memcpy(p, T, T_len);
p += T_len;
}
free(buf);
p = p_org;
#ifndef NDEBUG
const int s =
#endif
HKDF_expand(output, L, EVP_sha256(), prk, 32, info, info_len);
assert(s);
p = output;
if (c_key_len)
{
memcpy(c_key, p, c_key_len);
@ -285,8 +258,16 @@ int lshkdf_expand(const unsigned char *prk, const unsigned char *info, int info_
memcpy(sub_key, p, sub_key_len);
p += sub_key_len;
}
free(p_org);
if (c_key_len && c_hp)
{
memcpy(c_hp, p, c_key_len);
p += c_key_len;
}
if (s_key_len && s_hp)
{
memcpy(s_hp, p, s_key_len);
p += s_key_len;
}
return 0;
}
@ -313,20 +294,21 @@ int export_key_material_simple(unsigned char *ikm, uint32_t ikm_len,
memcpy(info + info_len, context, context_len);
info_len += context_len;
lshkdf_expand(prk, info, info_len, key_len, key,
0, NULL, 0, NULL,0, NULL, 0, NULL);
0, NULL, 0, NULL,0, NULL, 0, NULL, NULL, NULL);
free(info);
return 0;
}
int export_key_material(const unsigned char *ikm, uint32_t ikm_len,
int
lsquic_export_key_material(const unsigned char *ikm, uint32_t ikm_len,
const unsigned char *salt, int salt_len,
const unsigned char *context, uint32_t context_len,
uint16_t c_key_len, uint8_t *c_key,
uint16_t s_key_len, uint8_t *s_key,
uint16_t c_key_iv_len, uint8_t *c_key_iv,
uint16_t s_key_iv_len, uint8_t *s_key_iv,
uint8_t *sub_key)
uint8_t *sub_key, uint8_t *c_hp, uint8_t *s_hp)
{
unsigned char prk[32];
uint16_t sub_key_len = ikm_len;
@ -334,7 +316,7 @@ int export_key_material(const unsigned char *ikm, uint32_t ikm_len,
lshkdf_extract(ikm, ikm_len, salt, salt_len, prk);
lshkdf_expand(prk, context, context_len, c_key_len, c_key,
s_key_len, s_key, c_key_iv_len, c_key_iv, s_key_iv_len,
s_key_iv, sub_key_len, sub_key);
s_key_iv, sub_key_len, sub_key, c_hp, s_hp);
return 0;
}

View file

@ -40,14 +40,15 @@ int export_key_material_simple(unsigned char *ikm, uint32_t ikm_len,
const uint8_t *context, uint32_t context_len,
uint8_t *key, uint16_t key_len);
int export_key_material(const unsigned char *ikm, uint32_t ikm_len,
int lsquic_export_key_material(const unsigned char *ikm, uint32_t ikm_len,
const unsigned char *salt, int salt_len,
const unsigned char *context, uint32_t context_len,
uint16_t c_key_len, uint8_t *c_key,
uint16_t s_key_len, uint8_t *s_key,
uint16_t c_key_iv_len, uint8_t *c_key_iv,
uint16_t s_key_iv_len, uint8_t *s_key_iv,
uint8_t *sub_key);
uint8_t *sub_key,
uint8_t *c_hp, uint8_t *s_hp);
void c255_get_pub_key(unsigned char *priv_key, unsigned char pub_key[32]);
int c255_gen_share_key(unsigned char *priv_key, unsigned char *peer_pub_key, unsigned char *shared_key);
@ -88,7 +89,8 @@ int lshkdf_expand(const unsigned char *prk, const unsigned char *info, int info_
uint16_t s_key_len, uint8_t *s_key,
uint16_t c_key_iv_len, uint8_t *c_key_iv,
uint16_t s_key_iv_len, uint8_t *s_key_iv,
uint16_t sub_key_len, uint8_t *sub_key);
uint16_t sub_key_len, uint8_t *sub_key,
uint8_t *c_hp, uint8_t *s_hp);
void lshkdf_extract(const unsigned char *ikm, int ikm_len, const unsigned char *salt,
int salt_len, unsigned char *prk);

View file

@ -169,7 +169,7 @@ struct enc_session_funcs_gquic
#ifndef NDEBUG
/* Need to expose this function for testing */
int (*esf_determine_diversification_key) (enc_session_t *,
uint8_t *diversification_nonce, int is_client);
uint8_t *diversification_nonce);
#endif
const char *
@ -310,6 +310,13 @@ extern
const
#endif
struct enc_session_funcs_common lsquic_enc_session_common_gquic_1;
extern
#ifdef NDEBUG
const
#endif
struct enc_session_funcs_common lsquic_enc_session_common_gquic_2;
extern const struct enc_session_funcs_common lsquic_enc_session_common_ietf_v1;
extern
@ -324,6 +331,7 @@ extern const struct enc_session_funcs_iquic lsquic_enc_session_iquic_ietf_v1;
ver == LSQVER_ID23 ? &lsquic_enc_session_common_ietf_v1 : \
ver == LSQVER_ID24 ? &lsquic_enc_session_common_ietf_v1 : \
ver == LSQVER_VERNEG ? &lsquic_enc_session_common_ietf_v1 : \
ver == LSQVER_050 ? &lsquic_enc_session_common_gquic_2 : \
&lsquic_enc_session_common_gquic_1 )
#define select_esf_gquic_by_ver(ver) ( \

View file

@ -2616,6 +2616,8 @@ lsquic_engine_packet_in (lsquic_engine_t *engine,
parse_packet_in_begin = lsquic_gquic_parse_packet_in_begin;
else if ((1 << conn->cn_version) & LSQUIC_IETF_VERSIONS)
parse_packet_in_begin = lsquic_ietf_v1_parse_packet_in_begin;
else if (conn->cn_version == LSQVER_050)
parse_packet_in_begin = lsquic_Q050_parse_packet_in_begin;
else
{
assert(conn->cn_version == LSQVER_046

View file

@ -75,7 +75,7 @@
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(&conn->fc_conn)
#include "lsquic_logger.h"
enum { STREAM_IF_STD, STREAM_IF_HSK, STREAM_IF_HDR, N_STREAM_IFS };
enum stream_if { STREAM_IF_STD, STREAM_IF_HSK, STREAM_IF_HDR, N_STREAM_IFS };
#define MAX_RETR_PACKETS_SINCE_LAST_ACK 2
#define ACK_TIMEOUT 25000
@ -220,6 +220,7 @@ struct full_conn
lsquic_time_t fc_saved_ack_received;
struct network_path fc_path;
unsigned fc_orig_versions; /* Client only */
enum enc_level fc_crypto_enc_level;
};
static const struct ver_neg server_ver_neg;
@ -262,6 +263,10 @@ static lsquic_stream_t *
new_stream (struct full_conn *conn, lsquic_stream_id_t stream_id,
enum stream_ctor_flags);
static struct lsquic_stream *
new_stream_ext (struct full_conn *, lsquic_stream_id_t, enum stream_if,
enum stream_ctor_flags);
static void
reset_ack_state (struct full_conn *conn);
@ -550,9 +555,59 @@ apply_peer_settings (struct full_conn *conn)
static const struct conn_iface *full_conn_iface_ptr;
/* gQUIC up to version Q046 has handshake stream 1 and headers stream 3.
* Q050 and later have "crypto streams" -- meaning CRYPTO frames, not
* STREAM frames and no stream IDs -- and headers stream 1.
*/
static lsquic_stream_id_t
headers_stream_id_by_ver (enum lsquic_version version)
{
if (version < LSQVER_050)
return 3;
else
return 1;
}
static lsquic_stream_id_t
headers_stream_id_by_conn (const struct full_conn *conn)
{
return headers_stream_id_by_ver(conn->fc_conn.cn_version);
}
static lsquic_stream_id_t
hsk_stream_id (const struct full_conn *conn)
{
if (conn->fc_conn.cn_version < LSQVER_050)
return 1;
else
/* Use this otherwise invalid stream ID as ID for the gQUIC crypto
* stream.
*/
return (uint64_t) -1;
}
static int
has_handshake_stream (const struct full_conn *conn)
{
return conn->fc_conn.cn_version < LSQVER_050;
}
static int
is_handshake_stream_id (const struct full_conn *conn,
lsquic_stream_id_t stream_id)
{
return conn->fc_conn.cn_version < LSQVER_050 && stream_id == 1;
}
static struct full_conn *
new_conn_common (lsquic_cid_t cid, struct lsquic_engine_public *enpub,
unsigned flags)
unsigned flags, enum lsquic_version version)
{
struct full_conn *conn;
lsquic_stream_t *headers_stream;
@ -635,8 +690,9 @@ new_conn_common (lsquic_cid_t cid, struct lsquic_engine_public *enpub,
goto cleanup_on_error;
conn->fc_stream_ifs[STREAM_IF_HDR].stream_if = lsquic_headers_stream_if;
conn->fc_stream_ifs[STREAM_IF_HDR].stream_if_ctx = conn->fc_pub.u.gquic.hs;
headers_stream = new_stream(conn, LSQUIC_GQUIC_STREAM_HEADERS,
SCF_CALL_ON_NEW);
headers_stream = new_stream_ext(conn, headers_stream_id_by_ver(version),
STREAM_IF_HDR,
SCF_CALL_ON_NEW|SCF_DI_AUTOSWITCH|SCF_CRITICAL|SCF_HEADERS);
if (!headers_stream)
goto cleanup_on_error;
}
@ -701,9 +757,10 @@ lsquic_gquic_full_conn_client_new (struct lsquic_engine_public *enpub,
else
max_packet_size = GQUIC_MAX_IPv6_PACKET_SZ;
}
conn = new_conn_common(cid, enpub, flags);
conn = new_conn_common(cid, enpub, flags, version);
if (!conn)
return NULL;
init_ver_neg(conn, versions, &version);
conn->fc_path.np_pack_size = max_packet_size;
conn->fc_conn.cn_esf_c = select_esf_common_by_ver(version);
conn->fc_conn.cn_esf.g = esf_g;
@ -718,9 +775,11 @@ lsquic_gquic_full_conn_client_new (struct lsquic_engine_public *enpub,
}
if (conn->fc_flags & FC_HTTP)
conn->fc_last_stream_id = LSQUIC_GQUIC_STREAM_HEADERS; /* Client goes 5, 7, 9.... */
conn->fc_last_stream_id = headers_stream_id_by_conn(conn); /* Client goes (3?), 5, 7, 9.... */
else if (has_handshake_stream(conn))
conn->fc_last_stream_id = 1;
else
conn->fc_last_stream_id = LSQUIC_GQUIC_STREAM_HANDSHAKE;
conn->fc_last_stream_id = (uint64_t) -1; /* +2 will get us to 1 */
conn->fc_hsk_ctx.client.lconn = &conn->fc_conn;
conn->fc_hsk_ctx.client.mm = &enpub->enp_mm;
conn->fc_hsk_ctx.client.ver_neg = &conn->fc_ver_neg;
@ -728,11 +787,12 @@ lsquic_gquic_full_conn_client_new (struct lsquic_engine_public *enpub,
.stream_if = &lsquic_client_hsk_stream_if;
conn->fc_stream_ifs[STREAM_IF_HSK].stream_if_ctx = &conn->fc_hsk_ctx.client;
conn->fc_orig_versions = versions;
init_ver_neg(conn, versions, &version);
if (conn->fc_settings->es_handshake_to)
lsquic_alarmset_set(&conn->fc_alset, AL_HANDSHAKE,
lsquic_time_now() + conn->fc_settings->es_handshake_to);
if (!new_stream(conn, LSQUIC_GQUIC_STREAM_HANDSHAKE, SCF_CALL_ON_NEW))
if (!new_stream_ext(conn, hsk_stream_id(conn), STREAM_IF_HSK,
SCF_CALL_ON_NEW|SCF_DI_AUTOSWITCH|SCF_CRITICAL|SCF_CRYPTO
|(conn->fc_conn.cn_version >= LSQVER_050 ? SCF_CRYPTO_FRAMES : 0)))
{
LSQ_WARN("could not create handshake stream: %s", strerror(errno));
conn->fc_conn.cn_if->ci_destroy(&conn->fc_conn);
@ -776,15 +836,18 @@ lsquic_gquic_full_conn_server_new (struct lsquic_engine_public *enpub,
int have_outgoing_ack = 0;
mc = (struct mini_conn *) lconn_mini;
conn = new_conn_common(lconn_mini->cn_cid, enpub, flags);
conn = new_conn_common(lconn_mini->cn_cid, enpub, flags,
lconn_mini->cn_version);
if (!conn)
return NULL;
lconn_full = &conn->fc_conn;
conn->fc_last_stream_id = 0; /* Server goes 2, 4, 6.... */
if (conn->fc_flags & FC_HTTP)
conn->fc_max_peer_stream_id = LSQUIC_GQUIC_STREAM_HEADERS;
conn->fc_max_peer_stream_id = headers_stream_id_by_conn(conn);
else if (has_handshake_stream(conn))
conn->fc_max_peer_stream_id = 1;
else
conn->fc_max_peer_stream_id = LSQUIC_GQUIC_STREAM_HANDSHAKE;
conn->fc_max_peer_stream_id = (uint64_t) -1;
conn->fc_stream_ifs[STREAM_IF_HSK]
.stream_if = &lsquic_server_hsk_stream_if;
conn->fc_stream_ifs[STREAM_IF_HSK].stream_if_ctx = &conn->fc_hsk_ctx.server;
@ -799,8 +862,15 @@ lsquic_gquic_full_conn_server_new (struct lsquic_engine_public *enpub,
conn->fc_hsk_ctx.server.lconn = lconn_full;
conn->fc_hsk_ctx.server.enpub = enpub;
/* TODO Optimize: we don't need an actual crypto stream and handler
* on the server side, as we don't do anything with it. We can
* throw out appropriate frames earlier.
*/
/* Adjust offsets in the HANDSHAKE stream: */
hsk_stream = new_stream(conn, LSQUIC_GQUIC_STREAM_HANDSHAKE, SCF_CALL_ON_NEW);
hsk_stream = new_stream_ext(conn, hsk_stream_id(conn), STREAM_IF_HSK,
SCF_CALL_ON_NEW|SCF_DI_AUTOSWITCH|SCF_CRITICAL|SCF_CRYPTO
|(conn->fc_conn.cn_version >= LSQVER_050 ? SCF_CRYPTO_FRAMES : 0));
if (!hsk_stream)
{
LSQ_DEBUG("could not create handshake stream: %s", strerror(errno));
@ -1236,15 +1306,15 @@ full_conn_ci_write_ack (struct lsquic_conn *lconn,
static lsquic_stream_t *
new_stream_ext (struct full_conn *conn, lsquic_stream_id_t stream_id, int if_idx,
enum stream_ctor_flags stream_ctor_flags)
new_stream_ext (struct full_conn *conn, lsquic_stream_id_t stream_id,
enum stream_if if_idx, enum stream_ctor_flags stream_ctor_flags)
{
struct lsquic_stream *stream;
stream = lsquic_stream_new(stream_id, &conn->fc_pub,
conn->fc_stream_ifs[if_idx].stream_if,
conn->fc_stream_ifs[if_idx].stream_if_ctx, conn->fc_settings->es_sfcw,
stream_id == LSQUIC_GQUIC_STREAM_HANDSHAKE
stream_ctor_flags & SCF_CRYPTO
? 16 * 1024 : conn->fc_cfg.max_stream_send,
stream_ctor_flags);
if (stream)
@ -1258,30 +1328,13 @@ static lsquic_stream_t *
new_stream (struct full_conn *conn, lsquic_stream_id_t stream_id,
enum stream_ctor_flags flags)
{
int idx;
switch (stream_id)
{
case LSQUIC_GQUIC_STREAM_HANDSHAKE:
idx = STREAM_IF_HSK;
flags |= SCF_DI_AUTOSWITCH|SCF_CRITICAL;
break;
case LSQUIC_GQUIC_STREAM_HEADERS:
idx = STREAM_IF_HDR;
flags |= SCF_DI_AUTOSWITCH|SCF_CRITICAL;
if (!(conn->fc_flags & FC_HTTP) &&
conn->fc_enpub->enp_settings.es_rw_once)
flags |= SCF_DISP_RW_ONCE;
break;
default:
idx = STREAM_IF_STD;
flags |= SCF_DI_AUTOSWITCH;
if (conn->fc_pub.u.gquic.hs)
flags |= SCF_HTTP;
if (conn->fc_enpub->enp_settings.es_rw_once)
flags |= SCF_DISP_RW_ONCE;
break;
}
return new_stream_ext(conn, stream_id, idx, flags);
flags |= SCF_DI_AUTOSWITCH;
if (conn->fc_pub.u.gquic.hs)
flags |= SCF_HTTP;
if (conn->fc_enpub->enp_settings.es_rw_once)
flags |= SCF_DISP_RW_ONCE;
return new_stream_ext(conn, stream_id, STREAM_IF_STD, flags);
}
@ -1492,7 +1545,7 @@ process_stream_frame (struct full_conn *conn, lsquic_packet_in_t *packet_in,
int parsed_len;
#ifndef LSQUIC_REDO_FAILED_INSERTION
#define LSQUIC_REDO_FAILED_INSERTION 1
#define LSQUIC_REDO_FAILED_INSERTION 0
#endif
#if LSQUIC_REDO_FAILED_INSERTION
enum lsq_log_level saved_levels[3];
@ -1526,12 +1579,11 @@ process_stream_frame (struct full_conn *conn, lsquic_packet_in_t *packet_in,
#endif
enc_level = lsquic_packet_in_enc_level(packet_in);
if (stream_frame->stream_id != LSQUIC_GQUIC_STREAM_HANDSHAKE
if (!is_handshake_stream_id(conn, stream_frame->stream_id)
#if LSQUIC_ENABLE_HANDSHAKE_DISABLE
&& !(conn->fc_conn.cn_flags & LSCONN_NO_CRYPTO)
#endif
&& enc_level != ENC_LEV_FORW
&& enc_level != ENC_LEV_INIT)
&& enc_level == ENC_LEV_CLEAR)
{
lsquic_malo_put(stream_frame);
ABORT_ERROR("received unencrypted data for stream %"PRIu64,
@ -1641,7 +1693,7 @@ process_stream_frame (struct full_conn *conn, lsquic_packet_in_t *packet_in,
return 0;
}
if (stream->id == LSQUIC_GQUIC_STREAM_HANDSHAKE
if (lsquic_stream_is_crypto(stream)
&& (stream->sm_qflags & SMQF_WANT_READ)
&& !(conn->fc_flags & FC_SERVER)
&& !(conn->fc_conn.cn_flags & LSCONN_HANDSHAKE_DONE))
@ -1660,6 +1712,83 @@ process_stream_frame (struct full_conn *conn, lsquic_packet_in_t *packet_in,
}
static unsigned
process_crypto_frame (struct full_conn *conn, lsquic_packet_in_t *packet_in,
const unsigned char *p, size_t len)
{
struct lsquic_stream *stream;
stream_frame_t *stream_frame;
enum enc_level enc_level;
int parsed_len;
stream_frame = lsquic_malo_get(conn->fc_pub.mm->malo.stream_frame);
if (!stream_frame)
{
LSQ_WARN("could not allocate stream frame: %s", strerror(errno));
return 0;
}
parsed_len = conn->fc_conn.cn_pf->pf_parse_crypto_frame(p, len,
stream_frame);
if (parsed_len < 0)
{
lsquic_malo_put(stream_frame);
return 0;
}
enc_level = lsquic_packet_in_enc_level(packet_in);
EV_LOG_CRYPTO_FRAME_IN(LSQUIC_LOG_CONN_ID, stream_frame, enc_level);
LSQ_DEBUG("Got CRYPTO frame on enc level %s", lsquic_enclev2str[enc_level]);
if (enc_level < conn->fc_crypto_enc_level)
{
LSQ_DEBUG("Old enc level: ignore frame");
lsquic_malo_put(stream_frame);
return parsed_len;
}
if (conn->fc_flags & FC_CLOSING)
{
LSQ_DEBUG("Connection closing: ignore frame");
lsquic_malo_put(stream_frame);
return parsed_len;
}
stream = find_stream_by_id(conn, hsk_stream_id(conn));
if (!stream)
{
LSQ_WARN("cannot find handshake stream for CRYPTO frame");
lsquic_malo_put(stream_frame);
return 0;
}
if (enc_level > conn->fc_crypto_enc_level)
{
stream->read_offset = 0;
stream->tosend_off = 0;
conn->fc_crypto_enc_level = enc_level;
LSQ_DEBUG("reset handshake stream offsets, new enc level %u",
(unsigned) enc_level);
}
stream_frame->packet_in = lsquic_packet_in_get(packet_in);
if (0 != lsquic_stream_frame_in(stream, stream_frame))
{
ABORT_ERROR("cannot insert stream frame");
return 0;
}
if ((stream->sm_qflags & SMQF_WANT_READ)
&& !(conn->fc_flags & FC_SERVER)
&& !(conn->fc_conn.cn_flags & LSCONN_HANDSHAKE_DONE))
{
/* XXX what happens for server? */
lsquic_stream_dispatch_read_events(stream);
}
return parsed_len;
}
static unsigned
process_invalid_frame (struct full_conn *conn, lsquic_packet_in_t *packet_in,
const unsigned char *p, size_t len)
@ -2134,13 +2263,12 @@ process_rst_stream_frame (struct full_conn *conn, lsquic_packet_in_t *packet_in,
return parsed_len;
}
if (lsquic_stream_id_is_critical(conn->fc_flags & FC_HTTP, stream_id))
stream = find_stream_by_id(conn, stream_id);
if (stream && lsquic_stream_is_critical(stream))
{
ABORT_ERROR("received reset on static stream %"PRIu64, stream_id);
return 0;
}
stream = find_stream_by_id(conn, stream_id);
if (!stream)
{
if (conn_is_stream_closed(conn, stream_id))
@ -2218,6 +2346,7 @@ static process_frame_f const process_frames[N_QUIC_FRAMES] =
[QUIC_FRAME_ACK] = process_ack_frame,
[QUIC_FRAME_BLOCKED] = process_blocked_frame,
[QUIC_FRAME_CONNECTION_CLOSE] = process_connection_close_frame,
[QUIC_FRAME_CRYPTO] = process_crypto_frame,
[QUIC_FRAME_GOAWAY] = process_goaway_frame,
[QUIC_FRAME_INVALID] = process_invalid_frame,
[QUIC_FRAME_PADDING] = process_padding_frame,
@ -2368,8 +2497,11 @@ process_regular_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in)
enum quic_ft_bit frame_types;
int was_missing;
reconstruct_packet_number(conn, packet_in);
EV_LOG_PACKET_IN(LSQUIC_LOG_CONN_ID, packet_in);
if (conn->fc_conn.cn_version < LSQVER_050)
{
reconstruct_packet_number(conn, packet_in);
EV_LOG_PACKET_IN(LSQUIC_LOG_CONN_ID, packet_in);
}
#if LSQUIC_CONN_STATS
++conn->fc_stats.in.packets;
@ -2398,6 +2530,9 @@ process_regular_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in)
}
}
if (conn->fc_conn.cn_version >= LSQVER_050)
EV_LOG_PACKET_IN(LSQUIC_LOG_CONN_ID, packet_in);
st = lsquic_rechist_received(&conn->fc_rechist, packet_in->pi_packno,
packet_in->pi_received);
switch (st) {
@ -2618,8 +2753,7 @@ maybe_close_conn (struct full_conn *conn)
el = lsquic_hash_next(conn->fc_pub.all_streams))
{
stream = lsquic_hashelem_getdata(el);
assert(LSQUIC_GQUIC_STREAM_HANDSHAKE == stream->id
|| LSQUIC_GQUIC_STREAM_HEADERS == stream->id);
assert(stream->sm_bflags & (SMBF_CRYPTO|SMBF_HEADERS));
}
#endif
conn->fc_flags |= FC_RECV_CLOSE; /* Fake -- trigger "ok to close" */
@ -3124,7 +3258,7 @@ process_hsk_stream_read_events (struct full_conn *conn)
{
lsquic_stream_t *stream;
TAILQ_FOREACH(stream, &conn->fc_pub.read_streams, next_read_stream)
if (LSQUIC_GQUIC_STREAM_HANDSHAKE == stream->id)
if (lsquic_stream_is_crypto(stream))
{
lsquic_stream_dispatch_read_events(stream);
break;
@ -3137,7 +3271,7 @@ process_hsk_stream_write_events (struct full_conn *conn)
{
lsquic_stream_t *stream;
TAILQ_FOREACH(stream, &conn->fc_pub.write_streams, next_write_stream)
if (LSQUIC_GQUIC_STREAM_HANDSHAKE == stream->id)
if (lsquic_stream_is_crypto(stream))
{
lsquic_stream_dispatch_write_events(stream);
break;
@ -4270,7 +4404,7 @@ full_conn_ci_is_tickable (lsquic_conn_t *lconn)
{
TAILQ_FOREACH(stream, &conn->fc_pub.write_streams,
next_write_stream)
if (LSQUIC_GQUIC_STREAM_HANDSHAKE == stream->id
if (lsquic_stream_is_crypto(stream)
&& lsquic_stream_write_avail(stream))
{
LSQ_DEBUG("tickable: stream %"PRIu64" can be written to",
@ -4398,7 +4532,7 @@ lsquic_gquic_full_conn_srej (struct lsquic_conn *lconn)
&conn->fc_ver_neg, &conn->fc_pub, 0);
/* Reset handshake stream state */
stream = find_stream_by_id(conn, LSQUIC_GQUIC_STREAM_HANDSHAKE);
stream = find_stream_by_id(conn, hsk_stream_id(conn));
if (!stream)
return -1;
stream->n_unacked = 0;

File diff suppressed because it is too large Load diff

View file

@ -121,7 +121,8 @@ lsquic_is_valid_hs_packet (struct lsquic_engine *engine,
case 0x80|0x00|0x20|0x00|0x08:
case 0x80|0x40|0x20|0x00|0x00:
case 0x80|0x00|0x20|0x00|0x00:
is_valid = lsquic_is_valid_ietf_v1_or_Q046_hs_packet(buf, bufsz, &tag);
is_valid = lsquic_is_valid_ietf_v1_or_Q046plus_hs_packet(buf, bufsz,
&tag);
break;
/* 01XX XGGG: ID-22 short header */
case 0x00|0x40|0x00|0x00|0x00:

View file

@ -59,6 +59,7 @@
static const struct conn_iface mini_conn_iface_standard;
static const struct conn_iface mini_conn_iface_standard_Q050;
#if LSQUIC_ENABLE_HANDSHAKE_DISABLE
static const struct conn_iface mini_conn_iface_disable_handshake;
#endif
@ -138,6 +139,14 @@ lowest_bit_set (unsigned v)
}
static int
is_handshake_stream_id (const struct mini_conn *conn,
lsquic_stream_id_t stream_id)
{
return conn->mc_conn.cn_version < LSQVER_050 && stream_id == 1;
}
static void
mini_destroy_packet (struct mini_conn *mc, struct lsquic_packet_out *packet_out)
{
@ -183,7 +192,15 @@ mini_conn_new (struct lsquic_engine_public *enp,
{
if (!packet_in_is_ok(packet_in))
return NULL;
conn_iface = &mini_conn_iface_standard;
switch (version)
{
case LSQVER_050:
conn_iface = &mini_conn_iface_standard_Q050;
break;
default:
conn_iface = &mini_conn_iface_standard;
break;
}
}
mc = lsquic_malo_get(enp->enp_mm.malo.mini_conn);
@ -469,7 +486,7 @@ process_rst_stream_frame (struct mini_conn *mc, lsquic_packet_in_t *packet_in,
error_code);
LSQ_DEBUG("Got RST_STREAM; stream: %"PRIu64"; offset: 0x%"PRIX64, stream_id,
offset);
if (LSQUIC_GQUIC_STREAM_HANDSHAKE == stream_id)
if (is_handshake_stream_id(mc, stream_id))
{
LSQ_INFO("handshake stream reset, closing connection");
return 0;
@ -513,7 +530,7 @@ process_stream_frame (struct mini_conn *mc, lsquic_packet_in_t *packet_in,
return 0;
EV_LOG_STREAM_FRAME_IN(LSQUIC_LOG_CONN_ID, &stream_frame);
LSQ_DEBUG("Got stream frame for stream #%"PRIu64, stream_frame.stream_id);
if (LSQUIC_GQUIC_STREAM_HANDSHAKE == stream_frame.stream_id)
if (is_handshake_stream_id(mc, stream_frame.stream_id))
{
if (packet_in->pi_flags & PI_HSK_STREAM)
{ /* This is not supported for simplicity. The spec recommends
@ -545,6 +562,47 @@ process_stream_frame (struct mini_conn *mc, lsquic_packet_in_t *packet_in,
}
static unsigned
process_crypto_frame (struct mini_conn *mc, struct lsquic_packet_in *packet_in,
const unsigned char *p, size_t len)
{
stream_frame_t stream_frame;
int parsed_len;
parsed_len = mc->mc_conn.cn_pf->pf_parse_crypto_frame(p, len,
&stream_frame);
if (parsed_len < 0)
return 0;
EV_LOG_CRYPTO_FRAME_IN(LSQUIC_LOG_CONN_ID, &stream_frame,
lsquic_packet_in_enc_level(packet_in));
LSQ_DEBUG("Got CRYPTO frame at encryption level %s",
lsquic_enclev2str[lsquic_packet_in_enc_level(packet_in)]);
if (packet_in->pi_flags & PI_HSK_STREAM)
{ /* This is not supported for simplicity: assume a single CRYPTO frame
* per packet. If this changes, we can revisit this code.
*/
LSQ_INFO("two handshake stream frames in single incoming packet");
MCHIST_APPEND(mc, MCHE_2HSK_1STREAM);
return 0;
}
if (stream_frame.data_frame.df_offset >= mc->mc_read_off)
{
packet_in->pi_flags |= PI_HSK_STREAM;
packet_in->pi_hsk_stream = p - packet_in->pi_data;
mc->mc_flags |= MC_HAVE_NEW_HSK;
MCHIST_APPEND(mc, MCHE_NEW_HSK);
if (0 == stream_frame.data_frame.df_offset)
/* First CHLO message: update maximum packet size */
mc->mc_path.np_pack_size = packet_in->pi_data_sz;
}
else
{
LSQ_DEBUG("drop duplicate frame");
MCHIST_APPEND(mc, MCHE_DUP_HSK);
}
return parsed_len;
}
static unsigned
process_window_update_frame (struct mini_conn *mc,
lsquic_packet_in_t *packet_in, const unsigned char *p, size_t len)
@ -556,7 +614,7 @@ process_window_update_frame (struct mini_conn *mc,
if (parsed_len < 0)
return 0;
EV_LOG_WINDOW_UPDATE_FRAME_IN(LSQUIC_LOG_CONN_ID, stream_id, offset);
if (LSQUIC_GQUIC_STREAM_HANDSHAKE == stream_id)
if (is_handshake_stream_id(mc, stream_id))
/* This should not happen: why would the client send us WINDOW_UPDATE
* on stream 1?
*/
@ -575,6 +633,7 @@ static process_frame_f const process_frames[N_QUIC_FRAMES] =
[QUIC_FRAME_ACK] = process_ack_frame,
[QUIC_FRAME_BLOCKED] = process_blocked_frame,
[QUIC_FRAME_CONNECTION_CLOSE] = process_connection_close_frame,
[QUIC_FRAME_CRYPTO] = process_crypto_frame,
[QUIC_FRAME_GOAWAY] = process_goaway_frame,
[QUIC_FRAME_INVALID] = process_invalid_frame,
[QUIC_FRAME_PADDING] = process_padding_frame,
@ -632,40 +691,58 @@ conn_decrypt_packet (struct mini_conn *conn, lsquic_packet_in_t *packet_in)
}
static enum { PRP_KEEP, PRP_DEFER, PRP_DROP, PRP_ERROR }
/* PRP: Process Regular Packet */
enum proc_rp { PRP_KEEP, PRP_DEFER, PRP_DROP, PRP_ERROR, };
static enum proc_rp
conn_decrypt_packet_or (struct mini_conn *mc,
struct lsquic_packet_in *packet_in)
{
if (DECPI_OK == conn_decrypt_packet(mc, packet_in))
{
MCHIST_APPEND(mc, MCHE_DECRYPTED);
return PRP_KEEP;
}
else if (mc->mc_conn.cn_esf.g->esf_have_key_gt_one(
mc->mc_conn.cn_enc_session))
{
LSQ_INFO("could not decrypt packet: drop");
mc->mc_dropped_packnos |= MCONN_PACKET_MASK(packet_in->pi_packno);
MCHIST_APPEND(mc, MCHE_UNDECR_DROP);
return PRP_DROP;
}
else if ((packet_in->pi_flags & PI_OWN_DATA) ||
0 == lsquic_conn_copy_and_release_pi_data(&mc->mc_conn,
mc->mc_enpub, packet_in))
{
assert(packet_in->pi_flags & PI_OWN_DATA);
LSQ_INFO("could not decrypt packet: defer");
mc->mc_deferred_packnos |= MCONN_PACKET_MASK(packet_in->pi_packno);
MCHIST_APPEND(mc, MCHE_UNDECR_DEFER);
return PRP_DEFER;
}
else
{
MCHIST_APPEND(mc, MCHE_ENOMEM);
return PRP_ERROR; /* Memory allocation must have failed */
}
}
static enum proc_rp
process_regular_packet (struct mini_conn *mc, lsquic_packet_in_t *packet_in)
{
const unsigned char *p, *pend;
enum proc_rp prp;
unsigned len;
/* Decrypt packet if necessary */
if (0 == (packet_in->pi_flags & PI_DECRYPTED))
{
if (DECPI_OK == conn_decrypt_packet(mc, packet_in))
MCHIST_APPEND(mc, MCHE_DECRYPTED);
else if (mc->mc_conn.cn_esf.g->esf_have_key_gt_one(
mc->mc_conn.cn_enc_session))
{
LSQ_INFO("could not decrypt packet: drop");
mc->mc_dropped_packnos |= MCONN_PACKET_MASK(packet_in->pi_packno);
MCHIST_APPEND(mc, MCHE_UNDECR_DROP);
return PRP_DROP;
}
else if ((packet_in->pi_flags & PI_OWN_DATA) ||
0 == lsquic_conn_copy_and_release_pi_data(&mc->mc_conn,
mc->mc_enpub, packet_in))
{
assert(packet_in->pi_flags & PI_OWN_DATA);
LSQ_INFO("could not decrypt packet: defer");
mc->mc_deferred_packnos |= MCONN_PACKET_MASK(packet_in->pi_packno);
MCHIST_APPEND(mc, MCHE_UNDECR_DEFER);
return PRP_DEFER;
}
else
{
MCHIST_APPEND(mc, MCHE_ENOMEM);
return PRP_ERROR; /* Memory allocation must have failed */
}
prp = conn_decrypt_packet_or(mc, packet_in);
if (prp != PRP_KEEP)
return prp;
}
/* Update receive history before processing the packet: if there is an
@ -749,6 +826,18 @@ mini_stream_read (void *stream, void *buf, size_t len, int *reached_fin)
}
/* Wrapper to throw out reached_fin */
static size_t
mini_stream_read_for_crypto (void *stream, void *buf, size_t len)
{
size_t retval;
int reached_fin;
retval = mini_stream_read(stream, buf, len, &reached_fin);
return retval;
}
static size_t
mini_stream_size (void *stream)
{
@ -811,6 +900,13 @@ allocate_packet_out (struct mini_conn *mc, const unsigned char *nonce)
packet_out->po_flags |= PO_HELLO;
packet_out->po_header_type = HETY_0RTT;
}
if (mc->mc_conn.cn_version >= LSQVER_050)
{
if (nonce)
packet_out->po_header_type = HETY_0RTT;
else
packet_out->po_header_type = HETY_INITIAL;
}
lsquic_packet_out_set_pns(packet_out, PNS_APP);
TAILQ_INSERT_TAIL(&mc->mc_packets_out, packet_out, po_next);
LSQ_DEBUG("allocated packet #%"PRIu64", nonce: %d", packno, !!nonce);
@ -820,14 +916,89 @@ allocate_packet_out (struct mini_conn *mc, const unsigned char *nonce)
}
static struct lsquic_packet_out *
to_packet_pre_Q050 (struct mini_conn *mc, struct mini_stream_ctx *ms_ctx,
const unsigned char *nonce)
{
struct lsquic_packet_out *packet_out;
size_t cur_off;
int len;
packet_out = allocate_packet_out(mc, nonce);
if (!packet_out)
return NULL;
cur_off = ms_ctx->off;
len = mc->mc_conn.cn_pf->pf_gen_stream_frame(
packet_out->po_data + packet_out->po_data_sz,
lsquic_packet_out_avail(packet_out),
1, mc->mc_write_off, mini_stream_fin(ms_ctx),
mini_stream_size(ms_ctx), mini_stream_read, ms_ctx);
if (len < 0)
{
LSQ_WARN("cannot generate STREAM frame (avail: %u)",
lsquic_packet_out_avail(packet_out));
return NULL;
}
mc->mc_write_off += ms_ctx->off - cur_off;
EV_LOG_GENERATED_STREAM_FRAME(LSQUIC_LOG_CONN_ID, mc->mc_conn.cn_pf,
packet_out->po_data + packet_out->po_data_sz, len);
packet_out->po_data_sz += len;
packet_out->po_frame_types |= 1 << QUIC_FRAME_STREAM;
if (0 == lsquic_packet_out_avail(packet_out))
packet_out->po_flags |= PO_STREAM_END;
return packet_out;
}
static struct lsquic_packet_out *
to_packet_Q050plus (struct mini_conn *mc, struct mini_stream_ctx *ms_ctx,
const unsigned char *nonce)
{
struct lsquic_packet_out *packet_out;
size_t cur_off;
int len;
if (nonce && !(mc->mc_flags & MC_WR_OFF_RESET))
{
mc->mc_write_off = 0;
mc->mc_flags |= MC_WR_OFF_RESET;
}
packet_out = allocate_packet_out(mc, nonce);
if (!packet_out)
return NULL;
cur_off = ms_ctx->off;
len = mc->mc_conn.cn_pf->pf_gen_crypto_frame(
packet_out->po_data + packet_out->po_data_sz,
lsquic_packet_out_avail(packet_out), mc->mc_write_off,
mini_stream_size(ms_ctx), mini_stream_read_for_crypto, ms_ctx);
if (len < 0)
{
LSQ_WARN("cannot generate CRYPTO frame (avail: %u)",
lsquic_packet_out_avail(packet_out));
return NULL;
}
mc->mc_write_off += ms_ctx->off - cur_off;
EV_LOG_GENERATED_CRYPTO_FRAME(LSQUIC_LOG_CONN_ID, mc->mc_conn.cn_pf,
packet_out->po_data + packet_out->po_data_sz, len);
packet_out->po_data_sz += len;
packet_out->po_frame_types |= 1 << QUIC_FRAME_CRYPTO;
return packet_out;
}
static int
packetize_response (struct mini_conn *mc, const unsigned char *buf,
size_t bufsz, const unsigned char *nonce)
{
struct mini_stream_ctx ms_ctx;
lsquic_packet_out_t *packet_out;
size_t cur_off;
int len;
struct lsquic_packet_out * (*const to_packet) (struct mini_conn *,
struct mini_stream_ctx *, const unsigned char *)
= mc->mc_conn.cn_version < LSQVER_050
? to_packet_pre_Q050 : to_packet_Q050plus;
LSQ_DEBUG("Packetizing %zd bytes of handshake response", bufsz);
@ -837,27 +1008,9 @@ packetize_response (struct mini_conn *mc, const unsigned char *buf,
do
{
packet_out = allocate_packet_out(mc, nonce);
packet_out = to_packet(mc, &ms_ctx, nonce);
if (!packet_out)
return -1;
cur_off = ms_ctx.off;
len = mc->mc_conn.cn_pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
lsquic_packet_out_avail(packet_out),
LSQUIC_GQUIC_STREAM_HANDSHAKE, mc->mc_write_off, mini_stream_fin(&ms_ctx),
mini_stream_size(&ms_ctx), mini_stream_read, &ms_ctx);
if (len < 0)
{
LSQ_WARN("cannot generate stream frame (avail: %u)",
lsquic_packet_out_avail(packet_out));
return -1;
}
mc->mc_write_off += ms_ctx.off - cur_off;
EV_LOG_GENERATED_STREAM_FRAME(LSQUIC_LOG_CONN_ID, mc->mc_conn.cn_pf,
packet_out->po_data + packet_out->po_data_sz, len);
packet_out->po_data_sz += len;
packet_out->po_frame_types |= 1 << QUIC_FRAME_STREAM;
if (0 == lsquic_packet_out_avail(packet_out))
packet_out->po_flags |= PO_STREAM_END;
}
while (mini_stream_has_data(&ms_ctx));
@ -893,6 +1046,10 @@ continue_handshake (struct mini_conn *mc)
struct hsk_chunk hsk_chunks[MINICONN_MAX_PACKETS], *hsk_chunk;
unsigned char nonce_buf[32];
int nonce_set = 0;
int (*parse_frame)(const unsigned char *, size_t, struct stream_frame *)
= mc->mc_conn.cn_version < LSQVER_050
? mc->mc_conn.cn_pf->pf_parse_stream_frame
: mc->mc_conn.cn_pf->pf_parse_crypto_frame;
/* Get handshake stream data from each packet that contains a handshake
* stream frame and place them into `hsk_chunks' array.
@ -902,7 +1059,7 @@ continue_handshake (struct mini_conn *mc)
assert(n_hsk_chunks < sizeof(hsk_chunks) / sizeof(hsk_chunks[0]));
if (0 == (packet_in->pi_flags & PI_HSK_STREAM))
continue;
s = mc->mc_conn.cn_pf->pf_parse_stream_frame(packet_in->pi_data + packet_in->pi_hsk_stream,
s = parse_frame(packet_in->pi_data + packet_in->pi_hsk_stream,
packet_in->pi_data_sz - packet_in->pi_hsk_stream, &frame);
if (-1 == s)
{
@ -1485,7 +1642,14 @@ process_packet (struct mini_conn *mc, struct lsquic_packet_in *packet_in)
case PRP_DEFER:
assert(packet_in->pi_flags & PI_OWN_DATA);
lsquic_packet_in_upref(packet_in);
TAILQ_INSERT_TAIL(&mc->mc_deferred, packet_in, pi_next);
if (mc->mc_n_deferred < MINI_CONN_MAX_DEFERRED)
{
TAILQ_INSERT_TAIL(&mc->mc_deferred, packet_in, pi_next);
++mc->mc_n_deferred;
}
else
LSQ_DEBUG("won't defer more than %u packets: drop",
MINI_CONN_MAX_DEFERRED);
break;
case PRP_ERROR:
mc->mc_flags |= MC_ERROR;
@ -1514,6 +1678,7 @@ insert_into_deferred (struct mini_conn *mc, lsquic_packet_in_t *new_packet)
TAILQ_INSERT_BEFORE(packet_in, new_packet, pi_next);
else
TAILQ_INSERT_TAIL(&mc->mc_deferred, new_packet, pi_next);
++mc->mc_n_deferred;
}
@ -1528,6 +1693,7 @@ process_deferred_packets (struct mini_conn *mc)
{
packet_in = TAILQ_FIRST(&mc->mc_deferred);
TAILQ_REMOVE(&mc->mc_deferred, packet_in, pi_next);
--mc->mc_n_deferred;
process_packet(mc, packet_in);
reached_last = packet_in == last;
lsquic_packet_in_put(&mc->mc_enpub->enp_mm, packet_in);
@ -1662,11 +1828,75 @@ mini_conn_ci_packet_in (struct lsquic_conn *lconn,
if (TAILQ_EMPTY(&mc->mc_deferred))
process_packet(mc, packet_in);
else
else if (mc->mc_n_deferred < MINI_CONN_MAX_DEFERRED)
{
insert_into_deferred(mc, packet_in);
process_deferred_packets(mc);
}
else
LSQ_DEBUG("won't defer more than %u packets: drop",
MINI_CONN_MAX_DEFERRED);
}
/* Q050 is different is that packet numbers are not known until after the
* packet is decrypted, so we have to follow different logic here.
*/
static void
mini_conn_ci_Q050_packet_in (struct lsquic_conn *lconn,
struct lsquic_packet_in *packet_in)
{
struct mini_conn *mc = (struct mini_conn *) lconn;
enum proc_rp prp;
if (mc->mc_flags & MC_ERROR)
{
LSQ_DEBUG("error state: ignore packet");
return;
}
if (!mc->mc_conn.cn_enc_session)
{
mc->mc_conn.cn_enc_session =
mc->mc_conn.cn_esf.g->esf_create_server(&mc->mc_conn,
mc->mc_conn.cn_cid, mc->mc_enpub);
if (!mc->mc_conn.cn_enc_session)
{
LSQ_WARN("cannot create new enc session");
mc->mc_flags |= MC_ERROR;
return;
}
MCHIST_APPEND(mc, MCHE_NEW_ENC_SESS);
}
assert(!(packet_in->pi_flags & PI_DECRYPTED));
prp = conn_decrypt_packet_or(mc, packet_in);
switch (prp)
{
case PRP_KEEP:
break;
case PRP_DROP:
return;
case PRP_ERROR:
mc->mc_flags |= MC_ERROR;
return;
default:
if (mc->mc_n_deferred >= MINI_CONN_MAX_DEFERRED)
{
LSQ_DEBUG("won't defer more than %u packets: drop",
MINI_CONN_MAX_DEFERRED);
return;
}
assert(prp == PRP_DEFER);
assert(packet_in->pi_flags & PI_OWN_DATA);
lsquic_packet_in_upref(packet_in);
TAILQ_INSERT_TAIL(&mc->mc_deferred, packet_in, pi_next);
++mc->mc_n_deferred;
return;
}
assert(prp == PRP_KEEP);
process_packet(mc, packet_in);
}
@ -1735,6 +1965,7 @@ mini_conn_ci_destroy (struct lsquic_conn *lconn)
while ((packet_in = TAILQ_FIRST(&mc->mc_deferred)))
{
TAILQ_REMOVE(&mc->mc_deferred, packet_in, pi_next);
--mc->mc_n_deferred;
still_deferred |= MCONN_PACKET_MASK(packet_in->pi_packno);
lsquic_packet_in_put(&mc->mc_enpub->enp_mm, packet_in);
}
@ -2012,6 +2243,26 @@ static const struct conn_iface mini_conn_iface_standard = {
};
static const struct conn_iface mini_conn_iface_standard_Q050 = {
.ci_abort_error = mini_conn_ci_abort_error,
.ci_client_call_on_new = mini_conn_ci_client_call_on_new,
.ci_destroy = mini_conn_ci_destroy,
.ci_get_engine = mini_conn_ci_get_engine,
.ci_get_path = mini_conn_ci_get_path,
.ci_hsk_done = mini_conn_ci_hsk_done,
.ci_internal_error = mini_conn_ci_internal_error,
.ci_is_tickable = mini_conn_ci_is_tickable,
.ci_next_packet_to_send = mini_conn_ci_next_packet_to_send,
.ci_next_tick_time = mini_conn_ci_next_tick_time,
.ci_packet_in = mini_conn_ci_Q050_packet_in,
.ci_packet_not_sent = mini_conn_ci_packet_not_sent,
.ci_packet_sent = mini_conn_ci_packet_sent,
.ci_record_addrs = mini_conn_ci_record_addrs,
.ci_tick = mini_conn_ci_tick,
.ci_tls_alert = mini_conn_ci_tls_alert,
};
#if LSQUIC_ENABLE_HANDSHAKE_DISABLE
static const struct conn_iface mini_conn_iface_disable_handshake = {
.ci_abort_error = mini_conn_ci_abort_error,

View file

@ -116,6 +116,8 @@ struct mini_conn {
mc_cutoff,
mc_cur_packno;
unsigned char mc_hsk_count;
#define MINI_CONN_MAX_DEFERRED 10
unsigned char mc_n_deferred;
#if LSQUIC_RECORD_INORD_HIST
unsigned char mc_inord_idx;
#endif
@ -131,7 +133,7 @@ struct mini_conn {
MC_HAVE_NEW_HSK = (1 << 0),
MC_PROMOTE = (1 << 1),
MC_HAVE_SHLO = (1 << 2),
MC_UNUSED_3 = (1 << 3),
MC_WR_OFF_RESET = (1 << 3),
MC_ERROR = (1 << 4),
MC_UNSENT_ACK = (1 << 5),
MC_GEN_ACK = (1 << 6),

View file

@ -185,7 +185,7 @@ imico_stream_write (void *stream, const void *bufp, size_t bufsz)
while (msg_ctx.buf < msg_ctx.end)
{
header_sz = lconn->cn_pf->pf_calc_crypto_frame_header_sz(
cryst->mcs_write_off);
cryst->mcs_write_off, msg_ctx.end - msg_ctx.buf);
need = header_sz + 1;
packet_out = imico_get_packet_out(conn,
el2hety[ cryst->mcs_enc_level ], need);

View file

@ -30,7 +30,7 @@ enum quic_frame_type
QUIC_FRAME_STOP_SENDING, /* I */
QUIC_FRAME_PATH_CHALLENGE, /* I */
QUIC_FRAME_PATH_RESPONSE, /* I */
QUIC_FRAME_CRYPTO, /* I */
QUIC_FRAME_CRYPTO, /* B */
QUIC_FRAME_RETIRE_CONNECTION_ID,/* I */
QUIC_FRAME_NEW_TOKEN, /* I */
N_QUIC_FRAMES

View file

@ -241,7 +241,17 @@ lsquic_packet_out_new (struct lsquic_mm *mm, struct malo *malo, int use_cid,
memcpy(packet_out->po_nonce, nonce, 32);
}
if (flags & PO_LONGHEAD)
packet_out->po_header_type = HETY_HANDSHAKE;
{
if (lconn->cn_version == LSQVER_050)
{
if (lconn->cn_flags & (LSCONN_SERVER|LSCONN_HANDSHAKE_DONE))
packet_out->po_header_type = HETY_0RTT;
else
packet_out->po_header_type = HETY_INITIAL;
}
else
packet_out->po_header_type = HETY_HANDSHAKE;
}
packet_out->po_path = path;
return packet_out;

View file

@ -99,7 +99,7 @@ typedef struct lsquic_packet_out
*/
PO_SCHED = (1 <<14), /* On scheduled queue */
PO_SENT_SZ = (1 <<15),
PO_LONGHEAD = (1 <<16), /* Only used for Q044 */
PO_LONGHEAD = (1 <<16),
#define POIPv6_SHIFT 20
PO_IPv6 = (1 <<20), /* Set if pmi_allocate was passed is_ipv6=1,
* otherwise unset.

View file

@ -212,7 +212,7 @@ struct parse_funcs
(*pf_calc_stream_frame_header_sz) (lsquic_stream_id_t stream_id,
uint64_t offset, unsigned data_sz);
size_t
(*pf_calc_crypto_frame_header_sz) (uint64_t offset);
(*pf_calc_crypto_frame_header_sz) (uint64_t offset, unsigned data_sz);
void
(*pf_turn_on_fin) (unsigned char *);
@ -234,7 +234,7 @@ struct parse_funcs
unsigned
(*pf_packno_bits2len) (enum packno_bits);
/* Only used by IETF QUIC: */
/* Used by IETF QUIC and gQUIC >= Q050 */
void
(*pf_packno_info) (const struct lsquic_conn *,
const struct lsquic_packet_out *, unsigned *packno_off,
@ -318,13 +318,16 @@ struct parse_funcs
extern const struct parse_funcs lsquic_parse_funcs_gquic_Q039;
extern const struct parse_funcs lsquic_parse_funcs_gquic_Q046;
extern const struct parse_funcs lsquic_parse_funcs_gquic_Q050;
extern const struct parse_funcs lsquic_parse_funcs_ietf_v1;
#define select_pf_by_ver(ver) ( \
(1 << (ver)) & ((1 << LSQVER_039)|(1 << LSQVER_043)) ? \
&lsquic_parse_funcs_gquic_Q039 : \
(1 << (ver)) & ((1 << LSQVER_046)|LSQUIC_EXPERIMENTAL_Q098) ? \
(1 << (ver)) & (1 << LSQVER_046) ? \
&lsquic_parse_funcs_gquic_Q046 : \
(1 << (ver)) & ((1 << LSQVER_050)|LSQUIC_EXPERIMENTAL_Q098) ? \
&lsquic_parse_funcs_gquic_Q050 : \
&lsquic_parse_funcs_ietf_v1)
/* This function is gQUIC-version independent */
@ -340,8 +343,12 @@ int
lsquic_Q046_parse_packet_in_long_begin (struct lsquic_packet_in *, size_t length,
int is_server, unsigned, struct packin_parse_state *);
int
lsquic_Q050_parse_packet_in_long_begin (struct lsquic_packet_in *, size_t length,
int is_server, unsigned, struct packin_parse_state *);
enum quic_frame_type
parse_frame_type_gquic_Q035_thru_Q039 (unsigned char first_byte);
lsquic_parse_frame_type_gquic_Q035_thru_Q046 (unsigned char first_byte);
extern const enum quic_frame_type lsquic_iquic_byte2type[0x100];
@ -391,7 +398,7 @@ char *
acki2str (const struct ack_info *acki, size_t *sz);
void
lsquic_turn_on_fin_Q035_thru_Q039 (unsigned char *);
lsquic_turn_on_fin_Q035_thru_Q046 (unsigned char *);
enum packno_bits
lsquic_gquic_calc_packno_bits (lsquic_packno_t packno,

View file

@ -262,6 +262,33 @@ gquic_Q046_parse_packet_in_finish (struct lsquic_packet_in *packet_in,
}
static int
gquic_Q046_gen_crypto_frame (unsigned char *buf, size_t buf_len,
uint64_t offset, size_t size, gcf_read_f gcf_read, void *stream)
{
assert(0);
return -1;
}
static int
gquic_Q046_parse_crypto_frame (const unsigned char *buf, size_t rem_packet_sz,
struct stream_frame *stream_frame)
{
assert(0);
return -1;
}
static void
gquic_Q046_packno_info (const struct lsquic_conn *lconn,
const struct lsquic_packet_out *packet_out, unsigned *packno_off,
unsigned *packno_len)
{
assert(0);
}
const struct parse_funcs lsquic_parse_funcs_gquic_Q046 =
{
.pf_gen_reg_pkt_header = gquic_Q046_gen_reg_pkt_header,
@ -290,10 +317,13 @@ const struct parse_funcs lsquic_parse_funcs_gquic_Q046 =
.pf_read_float_time16 = gquic_be_read_float_time16,
#endif
.pf_generate_simple_prst = lsquic_generate_iquic_reset,
.pf_parse_frame_type = parse_frame_type_gquic_Q035_thru_Q039,
.pf_turn_on_fin = lsquic_turn_on_fin_Q035_thru_Q039,
.pf_parse_frame_type = lsquic_parse_frame_type_gquic_Q035_thru_Q046,
.pf_turn_on_fin = lsquic_turn_on_fin_Q035_thru_Q046,
.pf_packout_size = gquic_Q046_packout_size,
.pf_packout_max_header_size = gquic_Q046_packout_header_size,
.pf_calc_packno_bits = gquic_Q046_calc_packno_bits,
.pf_packno_bits2len = gquic_Q046_packno_bits2len,
.pf_gen_crypto_frame = gquic_Q046_gen_crypto_frame,
.pf_parse_crypto_frame = gquic_Q046_parse_crypto_frame,
.pf_packno_info = gquic_Q046_packno_info,
};

View file

@ -0,0 +1,866 @@
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
/*
* lsquic_parse_Q050.c -- Parsing functions specific to GQUIC Q050
*/
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <string.h>
#include <sys/queue.h>
#ifndef WIN32
#include <sys/types.h>
#else
#include <vc_compat.h>
#endif
#include "lsquic_types.h"
#include "lsquic_int_types.h"
#include "lsquic_packet_common.h"
#include "lsquic_packet_in.h"
#include "lsquic_packet_out.h"
#include "lsquic_parse.h"
#include "lsquic_parse_common.h"
#include "lsquic_version.h"
#include "lsquic.h"
#include "lsquic_parse_gquic_be.h"
#include "lsquic_parse_ietf.h"
#include "lsquic_byteswap.h"
#include "lsquic_hash.h"
#include "lsquic_conn.h"
#include "lsquic_varint.h"
#include "lsquic_enc_sess.h"
#define LSQUIC_LOGGER_MODULE LSQLM_PARSE
#include "lsquic_logger.h"
/* [draft-ietf-quic-transport-24] Section-17.2 */
static const enum header_type bits2ht[4] =
{
[0] = HETY_INITIAL,
[1] = HETY_0RTT,
[2] = HETY_HANDSHAKE,
[3] = HETY_RETRY,
};
int
lsquic_Q050_parse_packet_in_long_begin (struct lsquic_packet_in *packet_in,
size_t length, int is_server, unsigned cid_len,
struct packin_parse_state *state)
{
const unsigned char *p = packet_in->pi_data;
const unsigned char *const end = p + length;
lsquic_ver_tag_t tag;
enum header_type header_type;
unsigned dcil, scil, odcil;
int verneg, r;
unsigned char first_byte;
uint64_t payload_len, token_len;
if (length < 6)
return -1;
first_byte = *p++;
memcpy(&tag, p, 4);
p += 4;
verneg = 0 == tag;
if (!verneg)
header_type = bits2ht[ (first_byte >> 4) & 3 ];
else
header_type = HETY_VERNEG;
packet_in->pi_header_type = header_type;
dcil = *p++;
if (p + dcil >= end || dcil > MAX_CID_LEN)
return -1;
if (dcil)
{
memcpy(packet_in->pi_dcid.idbuf, p, dcil);
packet_in->pi_flags |= PI_CONN_ID;
p += dcil;
packet_in->pi_dcid.len = dcil;
}
scil = *p++;
if (p + scil > end || scil > MAX_CID_LEN)
return -1;
if (scil)
{
memcpy(packet_in->pi_dcid.idbuf, p, scil);
packet_in->pi_flags |= PI_CONN_ID;
p += scil;
packet_in->pi_dcid.len = scil;
}
if (is_server)
{
if (scil)
return -1;
}
else
if (dcil)
return -1;
switch (header_type)
{
case HETY_INITIAL:
r = vint_read(p, end, &token_len);
if (r < 0)
return -1;
if (token_len && !is_server)
{
/* From [draft-ietf-quic-transport-14]:
*
* Token Length: A variable-length integer specifying the
* length of the Token field, in bytes. This value is zero
* if no token is present. Initial packets sent by the
* server MUST set the Token Length field to zero; clients
* that receive an Initial packet with a non-zero Token
* Length field MUST either discard the packet or generate
* a connection error of type PROTOCOL_VIOLATION.
*/
return -1;
}
p += r;
if (token_len)
{
if (token_len >=
1ull << (sizeof(packet_in->pi_token_size) * 8))
return -1;
if (p + token_len > end)
return -1;
packet_in->pi_token = p - packet_in->pi_data;
packet_in->pi_token_size = token_len;
p += token_len;
}
/* fall-through */
case HETY_HANDSHAKE:
case HETY_0RTT:
if (p >= end)
return -1;
r = vint_read(p, end, &payload_len);
if (r < 0)
return -1;
p += r;
if (p - packet_in->pi_data + payload_len > length)
return -1;
length = p - packet_in->pi_data + payload_len;
if (end - p < 4)
return -1;
state->pps_p = p - r;
state->pps_nbytes = r;
packet_in->pi_quic_ver = 1;
break;
case HETY_RETRY:
if (p >= end)
return -1;
odcil = *p++;
if (p + odcil > end || odcil > MAX_CID_LEN)
return -1;
packet_in->pi_odcid_len = odcil;
packet_in->pi_odcid = p - packet_in->pi_data;
p += odcil;
packet_in->pi_token = p - packet_in->pi_data;
packet_in->pi_token_size = end - p;
p = end;
length = end - packet_in->pi_data;
state->pps_p = NULL;
state->pps_nbytes = 0;
packet_in->pi_quic_ver = 1;
break;
default:
assert(header_type == HETY_VERNEG);
if (p >= end || (3 & (uintptr_t) (end - p)))
return -1;
packet_in->pi_quic_ver = p - packet_in->pi_data;
p = end;
state->pps_p = NULL;
state->pps_nbytes = 0;
break;
}
packet_in->pi_header_sz = p - packet_in->pi_data;
packet_in->pi_data_sz = length;
packet_in->pi_nonce = 0;
packet_in->pi_refcnt = 0;
packet_in->pi_frame_types = 0;
memset(&packet_in->pi_next, 0, sizeof(packet_in->pi_next));
packet_in->pi_refcnt = 0;
packet_in->pi_received = 0;
/* Packet number is set to an invalid value. The packet number must
* be decrypted, which happens later.
*/
packet_in->pi_packno = 1ULL << 62;
return 0;
}
static unsigned
gquic_Q050_packno_bits2len (enum packno_bits bits)
{
return bits + 1;
}
#define iquic_packno_bits2len gquic_Q050_packno_bits2len
static enum packno_bits
gquic_Q050_calc_packno_bits (lsquic_packno_t packno,
lsquic_packno_t least_unacked, uint64_t n_in_flight)
{
uint64_t delta;
unsigned bits;
delta = packno - least_unacked;
if (n_in_flight > delta)
delta = n_in_flight;
delta *= 4;
bits = (delta >= (1ULL << 8))
+ (delta >= (1ULL << 16))
+ (delta >= (1ULL << 24))
;
return bits;
}
static unsigned
write_packno (unsigned char *p, lsquic_packno_t packno, enum packno_bits bits)
{
unsigned char *const begin = p;
switch (bits)
{
case IQUIC_PACKNO_LEN_4:
*p++ = packno >> 24;
/* fall-through */
case IQUIC_PACKNO_LEN_3:
*p++ = packno >> 16;
/* fall-through */
case IQUIC_PACKNO_LEN_2:
*p++ = packno >> 8;
/* fall-through */
default:
*p++ = packno;
}
return p - begin;
}
static int
gen_short_pkt_header (const struct lsquic_conn *lconn,
const struct lsquic_packet_out *packet_out, unsigned char *buf,
size_t bufsz)
{
unsigned packno_len, need;
enum packno_bits bits;
bits = lsquic_packet_out_packno_bits(packet_out);
packno_len = iquic_packno_bits2len(bits);
if (lconn->cn_flags & LSCONN_SERVER)
need = 1 + packno_len;
else
need = 1 + 8 /* CID */ + packno_len;
if (need > bufsz)
return -1;
*buf++ = 0x40 | bits;
if (0 == (lconn->cn_flags & LSCONN_SERVER))
{
memcpy(buf, lconn->cn_cid.idbuf, 8);
buf += 8;
}
(void) write_packno(buf, packet_out->po_packno, bits);
return need;
}
static size_t
gquic_Q050_packout_header_size_long_by_flags (const struct lsquic_conn *lconn,
enum packet_out_flags flags)
{
size_t sz;
enum packno_bits packno_bits;
packno_bits = (flags >> POBIT_SHIFT) & 0x3;
sz = 1 /* Type */
+ 4 /* Version */
+ 1 /* DCIL */
+ 1 /* SCIL */
+ lconn->cn_cid.len
+ 1 /* Token length: only use for Initial packets, while token is never
* set in this version.
*/
+ (flags & PO_NONCE ? DNONC_LENGTH : 0)
+ 2 /* Always use two bytes to encode payload length */
+ iquic_packno_bits2len(packno_bits)
;
return sz;
}
/* [draft-ietf-quic-transport-17] Section-17.2 */
static const unsigned char header_type_to_bin[] = {
[HETY_INITIAL] = 0x0,
[HETY_0RTT] = 0x1,
[HETY_HANDSHAKE] = 0x2,
[HETY_RETRY] = 0x3,
};
static size_t
gquic_Q050_packout_header_size_long_by_packet (const struct lsquic_conn *lconn,
const struct lsquic_packet_out *packet_out)
{
size_t sz;
enum packno_bits packno_bits;
packno_bits = lsquic_packet_out_packno_bits(packet_out);
sz = 1 /* Type */
+ 4 /* Version */
+ 1 /* DCIL */
+ 1 /* SCIL */
+ lconn->cn_cid.len
/* Token is never sent, but token length byte is used */
+ (packet_out->po_header_type == HETY_INITIAL)
+ 2 /* Always use two bytes to encode payload length */
+ iquic_packno_bits2len(packno_bits)
+ (packet_out->po_nonce ? DNONC_LENGTH : 0)
;
return sz;
}
static void
gquic_Q050_packno_info (const struct lsquic_conn *lconn,
const struct lsquic_packet_out *packet_out, unsigned *packno_off,
unsigned *packno_len)
{
unsigned token_len; /* Need intermediate value to quiet compiler warning */
if (packet_out->po_header_type == HETY_NOT_SET)
*packno_off = 1 +
(lconn->cn_flags & LSCONN_SERVER ? 0 : 8);
else
*packno_off = 1
+ 4
+ 1
+ 1
+ lconn->cn_cid.len
+ (packet_out->po_header_type == HETY_INITIAL ?
(token_len = packet_out->po_token_len,
(1 << vint_val2bits(token_len)) + token_len) : 0)
+ 2;
*packno_len = iquic_packno_bits2len(
lsquic_packet_out_packno_bits(packet_out));
}
static int
gquic_Q050_gen_long_pkt_header (const struct lsquic_conn *lconn,
const struct lsquic_packet_out *packet_out, unsigned char *buf,
size_t bufsz)
{
enum packno_bits packno_bits;
lsquic_ver_tag_t ver_tag;
unsigned token_len, payload_len, bits;
unsigned char *p;
size_t need;
need = gquic_Q050_packout_header_size_long_by_packet(lconn, packet_out);
if (need > bufsz)
{
errno = EINVAL;
return -1;
}
packno_bits = lsquic_packet_out_packno_bits(packet_out);
p = buf;
*p++ = 0x80 | 0x40
| (header_type_to_bin[ packet_out->po_header_type ] << 4)
| packno_bits;
ver_tag = lsquic_ver2tag(lconn->cn_version);
memcpy(p, &ver_tag, sizeof(ver_tag));
p += sizeof(ver_tag);
if (lconn->cn_flags & LSCONN_SERVER)
{
*p++ = 0;
*p++ = lconn->cn_cid.len;
memcpy(p, lconn->cn_cid.idbuf, lconn->cn_cid.len);
p += lconn->cn_cid.len;
}
else
{
*p++ = lconn->cn_cid.len;
memcpy(p, lconn->cn_cid.idbuf, lconn->cn_cid.len);
p += lconn->cn_cid.len;
*p++ = 0;
}
if (HETY_INITIAL == packet_out->po_header_type)
{
token_len = packet_out->po_token_len;
bits = vint_val2bits(token_len);
vint_write(p, token_len, bits, 1 << bits);
p += 1 << bits;
memcpy(p, packet_out->po_token, token_len);
p += token_len;
}
payload_len = packet_out->po_data_sz
+ lconn->cn_esf_c->esf_tag_len
+ iquic_packno_bits2len(packno_bits);
if (packet_out->po_nonce)
payload_len += DNONC_LENGTH;
bits = 1; /* Always use two bytes to encode payload length */
vint_write(p, payload_len, bits, 1 << bits);
p += 1 << bits;
p += write_packno(p, packet_out->po_packno, packno_bits);
if (packet_out->po_nonce)
{
memcpy(p, packet_out->po_nonce, DNONC_LENGTH);
p += DNONC_LENGTH;
}
assert(need == (size_t) (p - buf));
return p - buf;
}
static int
gquic_Q050_gen_reg_pkt_header (const struct lsquic_conn *lconn,
const struct lsquic_packet_out *packet_out, unsigned char *buf,
size_t bufsz)
{
if (0 == (packet_out->po_flags & PO_LONGHEAD))
return gen_short_pkt_header(lconn, packet_out, buf, bufsz);
else
return gquic_Q050_gen_long_pkt_header(lconn, packet_out, buf, bufsz);
}
static size_t
gquic_Q050_packout_header_size_short (const struct lsquic_conn *lconn,
enum packet_out_flags flags)
{
enum packno_bits bits;
size_t sz;
bits = (flags >> POBIT_SHIFT) & 0x3;
sz = 1; /* Type */
sz += (lconn->cn_flags & LSCONN_SERVER) ? 0 : 8;
sz += iquic_packno_bits2len(bits);
return sz;
}
static size_t
gquic_Q050_packout_max_header_size (const struct lsquic_conn *lconn,
enum packet_out_flags flags, size_t dcid_len_unused)
{
if (lconn->cn_flags & LSCONN_SERVER)
{
if (0 == (flags & PO_LONGHEAD))
return gquic_Q050_packout_header_size_short(lconn, flags);
else
return gquic_Q050_packout_header_size_long_by_flags(lconn, flags);
}
else
{
if (lconn->cn_flags & LSCONN_HANDSHAKE_DONE)
return gquic_Q050_packout_header_size_short(lconn, flags);
else
return gquic_Q050_packout_header_size_long_by_flags(lconn, flags);
}
}
static size_t
gquic_Q050_packout_size (const struct lsquic_conn *lconn,
const struct lsquic_packet_out *packet_out)
{
size_t sz;
if ((lconn->cn_flags & LSCONN_HANDSHAKE_DONE)
&& packet_out->po_header_type == HETY_NOT_SET)
sz = gquic_Q050_packout_header_size_short(lconn, packet_out->po_flags);
else
sz = gquic_Q050_packout_header_size_long_by_packet(lconn, packet_out);
sz += packet_out->po_data_sz;
sz += lconn->cn_esf_c->esf_tag_len;
return sz;
}
void
gquic_Q050_parse_packet_in_finish (struct lsquic_packet_in *packet_in,
struct packin_parse_state *state)
{
}
/* Same as Q046 plus CRYPTO frame at slot 8 */
static const enum quic_frame_type byte2frame_type_Q050[0x100] =
{
[0x00] = QUIC_FRAME_PADDING,
[0x01] = QUIC_FRAME_RST_STREAM,
[0x02] = QUIC_FRAME_CONNECTION_CLOSE,
[0x03] = QUIC_FRAME_GOAWAY,
[0x04] = QUIC_FRAME_WINDOW_UPDATE,
[0x05] = QUIC_FRAME_BLOCKED,
[0x06] = QUIC_FRAME_STOP_WAITING,
[0x07] = QUIC_FRAME_PING,
[0x08] = QUIC_FRAME_CRYPTO,
[0x09] = QUIC_FRAME_INVALID,
[0x0A] = QUIC_FRAME_INVALID,
[0x0B] = QUIC_FRAME_INVALID,
[0x0C] = QUIC_FRAME_INVALID,
[0x0D] = QUIC_FRAME_INVALID,
[0x0E] = QUIC_FRAME_INVALID,
[0x0F] = QUIC_FRAME_INVALID,
[0x10] = QUIC_FRAME_INVALID,
[0x11] = QUIC_FRAME_INVALID,
[0x12] = QUIC_FRAME_INVALID,
[0x13] = QUIC_FRAME_INVALID,
[0x14] = QUIC_FRAME_INVALID,
[0x15] = QUIC_FRAME_INVALID,
[0x16] = QUIC_FRAME_INVALID,
[0x17] = QUIC_FRAME_INVALID,
[0x18] = QUIC_FRAME_INVALID,
[0x19] = QUIC_FRAME_INVALID,
[0x1A] = QUIC_FRAME_INVALID,
[0x1B] = QUIC_FRAME_INVALID,
[0x1C] = QUIC_FRAME_INVALID,
[0x1D] = QUIC_FRAME_INVALID,
[0x1E] = QUIC_FRAME_INVALID,
[0x1F] = QUIC_FRAME_INVALID,
[0x20] = QUIC_FRAME_INVALID,
[0x21] = QUIC_FRAME_INVALID,
[0x22] = QUIC_FRAME_INVALID,
[0x23] = QUIC_FRAME_INVALID,
[0x24] = QUIC_FRAME_INVALID,
[0x25] = QUIC_FRAME_INVALID,
[0x26] = QUIC_FRAME_INVALID,
[0x27] = QUIC_FRAME_INVALID,
[0x28] = QUIC_FRAME_INVALID,
[0x29] = QUIC_FRAME_INVALID,
[0x2A] = QUIC_FRAME_INVALID,
[0x2B] = QUIC_FRAME_INVALID,
[0x2C] = QUIC_FRAME_INVALID,
[0x2D] = QUIC_FRAME_INVALID,
[0x2E] = QUIC_FRAME_INVALID,
[0x2F] = QUIC_FRAME_INVALID,
[0x30] = QUIC_FRAME_INVALID,
[0x31] = QUIC_FRAME_INVALID,
[0x32] = QUIC_FRAME_INVALID,
[0x33] = QUIC_FRAME_INVALID,
[0x34] = QUIC_FRAME_INVALID,
[0x35] = QUIC_FRAME_INVALID,
[0x36] = QUIC_FRAME_INVALID,
[0x37] = QUIC_FRAME_INVALID,
[0x38] = QUIC_FRAME_INVALID,
[0x39] = QUIC_FRAME_INVALID,
[0x3A] = QUIC_FRAME_INVALID,
[0x3B] = QUIC_FRAME_INVALID,
[0x3C] = QUIC_FRAME_INVALID,
[0x3D] = QUIC_FRAME_INVALID,
[0x3E] = QUIC_FRAME_INVALID,
[0x3F] = QUIC_FRAME_INVALID,
[0x40] = QUIC_FRAME_ACK,
[0x41] = QUIC_FRAME_ACK,
[0x42] = QUIC_FRAME_ACK,
[0x43] = QUIC_FRAME_ACK,
[0x44] = QUIC_FRAME_ACK,
[0x45] = QUIC_FRAME_ACK,
[0x46] = QUIC_FRAME_ACK,
[0x47] = QUIC_FRAME_ACK,
[0x48] = QUIC_FRAME_ACK,
[0x49] = QUIC_FRAME_ACK,
[0x4A] = QUIC_FRAME_ACK,
[0x4B] = QUIC_FRAME_ACK,
[0x4C] = QUIC_FRAME_ACK,
[0x4D] = QUIC_FRAME_ACK,
[0x4E] = QUIC_FRAME_ACK,
[0x4F] = QUIC_FRAME_ACK,
[0x50] = QUIC_FRAME_ACK,
[0x51] = QUIC_FRAME_ACK,
[0x52] = QUIC_FRAME_ACK,
[0x53] = QUIC_FRAME_ACK,
[0x54] = QUIC_FRAME_ACK,
[0x55] = QUIC_FRAME_ACK,
[0x56] = QUIC_FRAME_ACK,
[0x57] = QUIC_FRAME_ACK,
[0x58] = QUIC_FRAME_ACK,
[0x59] = QUIC_FRAME_ACK,
[0x5A] = QUIC_FRAME_ACK,
[0x5B] = QUIC_FRAME_ACK,
[0x5C] = QUIC_FRAME_ACK,
[0x5D] = QUIC_FRAME_ACK,
[0x5E] = QUIC_FRAME_ACK,
[0x5F] = QUIC_FRAME_ACK,
[0x60] = QUIC_FRAME_ACK,
[0x61] = QUIC_FRAME_ACK,
[0x62] = QUIC_FRAME_ACK,
[0x63] = QUIC_FRAME_ACK,
[0x64] = QUIC_FRAME_ACK,
[0x65] = QUIC_FRAME_ACK,
[0x66] = QUIC_FRAME_ACK,
[0x67] = QUIC_FRAME_ACK,
[0x68] = QUIC_FRAME_ACK,
[0x69] = QUIC_FRAME_ACK,
[0x6A] = QUIC_FRAME_ACK,
[0x6B] = QUIC_FRAME_ACK,
[0x6C] = QUIC_FRAME_ACK,
[0x6D] = QUIC_FRAME_ACK,
[0x6E] = QUIC_FRAME_ACK,
[0x6F] = QUIC_FRAME_ACK,
[0x70] = QUIC_FRAME_ACK,
[0x71] = QUIC_FRAME_ACK,
[0x72] = QUIC_FRAME_ACK,
[0x73] = QUIC_FRAME_ACK,
[0x74] = QUIC_FRAME_ACK,
[0x75] = QUIC_FRAME_ACK,
[0x76] = QUIC_FRAME_ACK,
[0x77] = QUIC_FRAME_ACK,
[0x78] = QUIC_FRAME_ACK,
[0x79] = QUIC_FRAME_ACK,
[0x7A] = QUIC_FRAME_ACK,
[0x7B] = QUIC_FRAME_ACK,
[0x7C] = QUIC_FRAME_ACK,
[0x7D] = QUIC_FRAME_ACK,
[0x7E] = QUIC_FRAME_ACK,
[0x7F] = QUIC_FRAME_ACK,
[0x80] = QUIC_FRAME_STREAM,
[0x81] = QUIC_FRAME_STREAM,
[0x82] = QUIC_FRAME_STREAM,
[0x83] = QUIC_FRAME_STREAM,
[0x84] = QUIC_FRAME_STREAM,
[0x85] = QUIC_FRAME_STREAM,
[0x86] = QUIC_FRAME_STREAM,
[0x87] = QUIC_FRAME_STREAM,
[0x88] = QUIC_FRAME_STREAM,
[0x89] = QUIC_FRAME_STREAM,
[0x8A] = QUIC_FRAME_STREAM,
[0x8B] = QUIC_FRAME_STREAM,
[0x8C] = QUIC_FRAME_STREAM,
[0x8D] = QUIC_FRAME_STREAM,
[0x8E] = QUIC_FRAME_STREAM,
[0x8F] = QUIC_FRAME_STREAM,
[0x90] = QUIC_FRAME_STREAM,
[0x91] = QUIC_FRAME_STREAM,
[0x92] = QUIC_FRAME_STREAM,
[0x93] = QUIC_FRAME_STREAM,
[0x94] = QUIC_FRAME_STREAM,
[0x95] = QUIC_FRAME_STREAM,
[0x96] = QUIC_FRAME_STREAM,
[0x97] = QUIC_FRAME_STREAM,
[0x98] = QUIC_FRAME_STREAM,
[0x99] = QUIC_FRAME_STREAM,
[0x9A] = QUIC_FRAME_STREAM,
[0x9B] = QUIC_FRAME_STREAM,
[0x9C] = QUIC_FRAME_STREAM,
[0x9D] = QUIC_FRAME_STREAM,
[0x9E] = QUIC_FRAME_STREAM,
[0x9F] = QUIC_FRAME_STREAM,
[0xA0] = QUIC_FRAME_STREAM,
[0xA1] = QUIC_FRAME_STREAM,
[0xA2] = QUIC_FRAME_STREAM,
[0xA3] = QUIC_FRAME_STREAM,
[0xA4] = QUIC_FRAME_STREAM,
[0xA5] = QUIC_FRAME_STREAM,
[0xA6] = QUIC_FRAME_STREAM,
[0xA7] = QUIC_FRAME_STREAM,
[0xA8] = QUIC_FRAME_STREAM,
[0xA9] = QUIC_FRAME_STREAM,
[0xAA] = QUIC_FRAME_STREAM,
[0xAB] = QUIC_FRAME_STREAM,
[0xAC] = QUIC_FRAME_STREAM,
[0xAD] = QUIC_FRAME_STREAM,
[0xAE] = QUIC_FRAME_STREAM,
[0xAF] = QUIC_FRAME_STREAM,
[0xB0] = QUIC_FRAME_STREAM,
[0xB1] = QUIC_FRAME_STREAM,
[0xB2] = QUIC_FRAME_STREAM,
[0xB3] = QUIC_FRAME_STREAM,
[0xB4] = QUIC_FRAME_STREAM,
[0xB5] = QUIC_FRAME_STREAM,
[0xB6] = QUIC_FRAME_STREAM,
[0xB7] = QUIC_FRAME_STREAM,
[0xB8] = QUIC_FRAME_STREAM,
[0xB9] = QUIC_FRAME_STREAM,
[0xBA] = QUIC_FRAME_STREAM,
[0xBB] = QUIC_FRAME_STREAM,
[0xBC] = QUIC_FRAME_STREAM,
[0xBD] = QUIC_FRAME_STREAM,
[0xBE] = QUIC_FRAME_STREAM,
[0xBF] = QUIC_FRAME_STREAM,
[0xC0] = QUIC_FRAME_STREAM,
[0xC1] = QUIC_FRAME_STREAM,
[0xC2] = QUIC_FRAME_STREAM,
[0xC3] = QUIC_FRAME_STREAM,
[0xC4] = QUIC_FRAME_STREAM,
[0xC5] = QUIC_FRAME_STREAM,
[0xC6] = QUIC_FRAME_STREAM,
[0xC7] = QUIC_FRAME_STREAM,
[0xC8] = QUIC_FRAME_STREAM,
[0xC9] = QUIC_FRAME_STREAM,
[0xCA] = QUIC_FRAME_STREAM,
[0xCB] = QUIC_FRAME_STREAM,
[0xCC] = QUIC_FRAME_STREAM,
[0xCD] = QUIC_FRAME_STREAM,
[0xCE] = QUIC_FRAME_STREAM,
[0xCF] = QUIC_FRAME_STREAM,
[0xD0] = QUIC_FRAME_STREAM,
[0xD1] = QUIC_FRAME_STREAM,
[0xD2] = QUIC_FRAME_STREAM,
[0xD3] = QUIC_FRAME_STREAM,
[0xD4] = QUIC_FRAME_STREAM,
[0xD5] = QUIC_FRAME_STREAM,
[0xD6] = QUIC_FRAME_STREAM,
[0xD7] = QUIC_FRAME_STREAM,
[0xD8] = QUIC_FRAME_STREAM,
[0xD9] = QUIC_FRAME_STREAM,
[0xDA] = QUIC_FRAME_STREAM,
[0xDB] = QUIC_FRAME_STREAM,
[0xDC] = QUIC_FRAME_STREAM,
[0xDD] = QUIC_FRAME_STREAM,
[0xDE] = QUIC_FRAME_STREAM,
[0xDF] = QUIC_FRAME_STREAM,
[0xE0] = QUIC_FRAME_STREAM,
[0xE1] = QUIC_FRAME_STREAM,
[0xE2] = QUIC_FRAME_STREAM,
[0xE3] = QUIC_FRAME_STREAM,
[0xE4] = QUIC_FRAME_STREAM,
[0xE5] = QUIC_FRAME_STREAM,
[0xE6] = QUIC_FRAME_STREAM,
[0xE7] = QUIC_FRAME_STREAM,
[0xE8] = QUIC_FRAME_STREAM,
[0xE9] = QUIC_FRAME_STREAM,
[0xEA] = QUIC_FRAME_STREAM,
[0xEB] = QUIC_FRAME_STREAM,
[0xEC] = QUIC_FRAME_STREAM,
[0xED] = QUIC_FRAME_STREAM,
[0xEE] = QUIC_FRAME_STREAM,
[0xEF] = QUIC_FRAME_STREAM,
[0xF0] = QUIC_FRAME_STREAM,
[0xF1] = QUIC_FRAME_STREAM,
[0xF2] = QUIC_FRAME_STREAM,
[0xF3] = QUIC_FRAME_STREAM,
[0xF4] = QUIC_FRAME_STREAM,
[0xF5] = QUIC_FRAME_STREAM,
[0xF6] = QUIC_FRAME_STREAM,
[0xF7] = QUIC_FRAME_STREAM,
[0xF8] = QUIC_FRAME_STREAM,
[0xF9] = QUIC_FRAME_STREAM,
[0xFA] = QUIC_FRAME_STREAM,
[0xFB] = QUIC_FRAME_STREAM,
[0xFC] = QUIC_FRAME_STREAM,
[0xFD] = QUIC_FRAME_STREAM,
[0xFE] = QUIC_FRAME_STREAM,
[0xFF] = QUIC_FRAME_STREAM,
};
static enum quic_frame_type
gquic_Q050_parse_frame_type (unsigned char b)
{
return byte2frame_type_Q050[b];
}
static int
gquic_Q050_gen_crypto_frame (unsigned char *buf, size_t buf_len,
uint64_t offset, size_t size, gcf_read_f gcf_read, void *stream)
{
return lsquic_ietf_v1_gen_crypto_frame(buf, 0x8, buf_len, offset,
size, gcf_read, stream);
}
static int
gquic_Q050_parse_crypto_frame (const unsigned char *buf, size_t rem_packet_sz,
struct stream_frame *stream_frame)
{
if (rem_packet_sz > 0)
{
assert(0x08 == buf[0]);
return lsquic_ietf_v1_parse_crypto_frame(buf, rem_packet_sz,
stream_frame);
}
else
return -1;
}
static size_t
gquic_Q050_calc_crypto_frame_header_sz (uint64_t offset, unsigned data_sz)
{
return 1 /* Frame type */
+ (1 << vint_val2bits(offset))
+ (1 << vint_val2bits(data_sz))
;
}
const struct parse_funcs lsquic_parse_funcs_gquic_Q050 =
{
.pf_gen_reg_pkt_header = gquic_Q050_gen_reg_pkt_header,
.pf_parse_packet_in_finish = gquic_Q050_parse_packet_in_finish,
.pf_gen_stream_frame = gquic_be_gen_stream_frame,
.pf_calc_stream_frame_header_sz = calc_stream_frame_header_sz_gquic,
.pf_parse_stream_frame = gquic_be_parse_stream_frame,
.pf_parse_ack_frame = gquic_be_parse_ack_frame,
.pf_gen_ack_frame = gquic_be_gen_ack_frame,
.pf_gen_stop_waiting_frame = gquic_be_gen_stop_waiting_frame,
.pf_parse_stop_waiting_frame = gquic_be_parse_stop_waiting_frame,
.pf_skip_stop_waiting_frame = gquic_be_skip_stop_waiting_frame,
.pf_gen_window_update_frame = gquic_be_gen_window_update_frame,
.pf_parse_window_update_frame = gquic_be_parse_window_update_frame,
.pf_gen_blocked_frame = gquic_be_gen_blocked_frame,
.pf_parse_blocked_frame = gquic_be_parse_blocked_frame,
.pf_gen_rst_frame = gquic_be_gen_rst_frame,
.pf_parse_rst_frame = gquic_be_parse_rst_frame,
.pf_gen_connect_close_frame = gquic_be_gen_connect_close_frame,
.pf_parse_connect_close_frame = gquic_be_parse_connect_close_frame,
.pf_gen_goaway_frame = gquic_be_gen_goaway_frame,
.pf_parse_goaway_frame = gquic_be_parse_goaway_frame,
.pf_gen_ping_frame = gquic_be_gen_ping_frame,
#ifndef NDEBUG
.pf_write_float_time16 = gquic_be_write_float_time16,
.pf_read_float_time16 = gquic_be_read_float_time16,
#endif
.pf_generate_simple_prst = lsquic_generate_iquic_reset,
.pf_parse_frame_type = gquic_Q050_parse_frame_type,
.pf_turn_on_fin = lsquic_turn_on_fin_Q035_thru_Q046,
.pf_packout_size = gquic_Q050_packout_size,
.pf_packout_max_header_size = gquic_Q050_packout_max_header_size,
.pf_calc_packno_bits = gquic_Q050_calc_packno_bits,
.pf_packno_bits2len = gquic_Q050_packno_bits2len,
.pf_gen_crypto_frame = gquic_Q050_gen_crypto_frame,
.pf_parse_crypto_frame = gquic_Q050_parse_crypto_frame,
.pf_packno_info = gquic_Q050_packno_info,
.pf_calc_crypto_frame_header_sz = gquic_Q050_calc_crypto_frame_header_sz,
};

View file

@ -13,26 +13,31 @@
#include "lsquic_parse.h"
#include "lsquic_enc_sess.h"
#include "lsquic_version.h"
#include "lsquic_qtags.h"
static int
parse_ietf_v1_or_Q046_long_begin (struct lsquic_packet_in *packet_in,
parse_ietf_v1_or_Q046plus_long_begin (struct lsquic_packet_in *packet_in,
size_t length, int is_server, unsigned cid_len,
struct packin_parse_state *state)
{
enum lsquic_version version;
lsquic_ver_tag_t tag;
if (length >= 5)
{
memcpy(&tag, packet_in->pi_data + 1, 4);
version = lsquic_tag2ver(tag);
if (version == LSQVER_046)
switch (tag)
{
case TAG('Q', '0', '4', '6'):
return lsquic_Q046_parse_packet_in_long_begin(packet_in, length,
is_server, cid_len, state);
else
case TAG('Q', '0', '5', '0'):
return lsquic_Q050_parse_packet_in_long_begin(packet_in, length,
is_server, cid_len, state);
default:
return lsquic_ietf_v1_parse_packet_in_long_begin(packet_in, length,
is_server, cid_len, state);
}
}
else
return -1;
@ -51,20 +56,20 @@ static int (* const parse_begin_funcs[32]) (struct lsquic_packet_in *,
PBEL(0x80|0x40|0x20|0x10|0x00) = lsquic_Q046_parse_packet_in_long_begin,
PBEL(0x80|0x00|0x20|0x10|0x00) = lsquic_Q046_parse_packet_in_long_begin,
/* 1X00 XGGG: */
PBEL(0x80|0x40|0x00|0x00|0x08) = parse_ietf_v1_or_Q046_long_begin,
PBEL(0x80|0x00|0x00|0x00|0x08) = parse_ietf_v1_or_Q046_long_begin,
PBEL(0x80|0x40|0x00|0x00|0x00) = parse_ietf_v1_or_Q046_long_begin,
PBEL(0x80|0x00|0x00|0x00|0x00) = parse_ietf_v1_or_Q046_long_begin,
PBEL(0x80|0x40|0x00|0x00|0x08) = parse_ietf_v1_or_Q046plus_long_begin,
PBEL(0x80|0x00|0x00|0x00|0x08) = parse_ietf_v1_or_Q046plus_long_begin,
PBEL(0x80|0x40|0x00|0x00|0x00) = parse_ietf_v1_or_Q046plus_long_begin,
PBEL(0x80|0x00|0x00|0x00|0x00) = parse_ietf_v1_or_Q046plus_long_begin,
/* 1X01 XGGG: */
PBEL(0x80|0x40|0x00|0x10|0x08) = parse_ietf_v1_or_Q046_long_begin,
PBEL(0x80|0x00|0x00|0x10|0x08) = parse_ietf_v1_or_Q046_long_begin,
PBEL(0x80|0x40|0x00|0x10|0x00) = parse_ietf_v1_or_Q046_long_begin,
PBEL(0x80|0x00|0x00|0x10|0x00) = parse_ietf_v1_or_Q046_long_begin,
PBEL(0x80|0x40|0x00|0x10|0x08) = parse_ietf_v1_or_Q046plus_long_begin,
PBEL(0x80|0x00|0x00|0x10|0x08) = parse_ietf_v1_or_Q046plus_long_begin,
PBEL(0x80|0x40|0x00|0x10|0x00) = parse_ietf_v1_or_Q046plus_long_begin,
PBEL(0x80|0x00|0x00|0x10|0x00) = parse_ietf_v1_or_Q046plus_long_begin,
/* 1X10 XGGG: */
PBEL(0x80|0x40|0x20|0x00|0x08) = parse_ietf_v1_or_Q046_long_begin,
PBEL(0x80|0x00|0x20|0x00|0x08) = parse_ietf_v1_or_Q046_long_begin,
PBEL(0x80|0x40|0x20|0x00|0x00) = parse_ietf_v1_or_Q046_long_begin,
PBEL(0x80|0x00|0x20|0x00|0x00) = parse_ietf_v1_or_Q046_long_begin,
PBEL(0x80|0x40|0x20|0x00|0x08) = parse_ietf_v1_or_Q046plus_long_begin,
PBEL(0x80|0x00|0x20|0x00|0x08) = parse_ietf_v1_or_Q046plus_long_begin,
PBEL(0x80|0x40|0x20|0x00|0x00) = parse_ietf_v1_or_Q046plus_long_begin,
PBEL(0x80|0x00|0x20|0x00|0x00) = parse_ietf_v1_or_Q046plus_long_begin,
/* 01XX XGGG */
PBEL(0x00|0x40|0x00|0x00|0x00) = lsquic_ietf_v1_parse_packet_in_short_begin,
PBEL(0x00|0x40|0x00|0x00|0x08) = lsquic_ietf_v1_parse_packet_in_short_begin,
@ -102,7 +107,6 @@ lsquic_parse_packet_in_server_begin (struct lsquic_packet_in *packet_in,
}
/* This function does not support Q046 */
int
lsquic_parse_packet_in_begin (lsquic_packet_in_t *packet_in, size_t length,
int is_server, unsigned cid_len, struct packin_parse_state *state)
@ -111,10 +115,9 @@ lsquic_parse_packet_in_begin (lsquic_packet_in_t *packet_in, size_t length,
{
switch (packet_in->pi_data[0] & 0xC0)
{
/* XXX Revisit this: does this logic check out? */
case 0xC0:
case 0x80:
return lsquic_ietf_v1_parse_packet_in_long_begin(packet_in,
return parse_ietf_v1_or_Q046plus_long_begin(packet_in,
length, is_server, cid_len, state);
case 0x00:
return lsquic_gquic_parse_packet_in_begin(packet_in, length,
@ -169,6 +172,27 @@ lsquic_Q046_parse_packet_in_begin (struct lsquic_packet_in *packet_in,
}
int
lsquic_Q050_parse_packet_in_begin (struct lsquic_packet_in *packet_in,
size_t length, int is_server, unsigned cid_len,
struct packin_parse_state *state)
{
assert(!is_server);
assert(cid_len == GQUIC_CID_LEN);
if (length > 0)
{
if (0 == (packet_in->pi_data[0] & 0x80))
return lsquic_ietf_v1_parse_packet_in_short_begin(packet_in, length,
is_server, is_server ? cid_len : 0, state);
else
return lsquic_Q050_parse_packet_in_long_begin(packet_in, length,
is_server, cid_len, state);
}
else
return -1;
}
/* TODO This function uses the full packet parsing functionality to get at
* the CID. This is an overkill and could be optimized -- at the cost of
* some code duplication, of course.

View file

@ -35,7 +35,7 @@ lsquic_Q046_parse_packet_in_begin (struct lsquic_packet_in *,
struct packin_parse_state *);
int
lsquic_Q046_parse_packet_in_begin (struct lsquic_packet_in *,
lsquic_Q050_parse_packet_in_begin (struct lsquic_packet_in *,
size_t length, int is_server, unsigned cid_len,
struct packin_parse_state *);
@ -83,7 +83,7 @@ lsquic_is_valid_iquic_hs_packet (const unsigned char *buf, size_t buf_sz,
lsquic_ver_tag_t *tag);
int
lsquic_is_valid_ietf_v1_or_Q046_hs_packet (const unsigned char *buf,
lsquic_is_valid_ietf_v1_or_Q046plus_hs_packet (const unsigned char *buf,
size_t length, lsquic_ver_tag_t *tagp);
/* Instead of just -1 like CHECK_SPACE(), this macro returns the number

View file

@ -990,6 +990,33 @@ gquic_be_gen_ack_frame (unsigned char *outbuf, size_t outbuf_sz,
}
static int
gquic_be_gen_crypto_frame (unsigned char *buf, size_t buf_len,
uint64_t offset, size_t size, gcf_read_f gcf_read, void *stream)
{
assert(0);
return -1;
}
static int
gquic_be_parse_crypto_frame (const unsigned char *buf, size_t rem_packet_sz,
struct stream_frame *stream_frame)
{
assert(0);
return -1;
}
static void
gquic_be_packno_info (const struct lsquic_conn *lconn,
const struct lsquic_packet_out *packet_out, unsigned *packno_off,
unsigned *packno_len)
{
assert(0);
}
const struct parse_funcs lsquic_parse_funcs_gquic_Q039 =
{
.pf_gen_reg_pkt_header = gquic_be_gen_reg_pkt_header,
@ -1019,10 +1046,13 @@ const struct parse_funcs lsquic_parse_funcs_gquic_Q039 =
.pf_read_float_time16 = gquic_be_read_float_time16,
#endif
.pf_generate_simple_prst = lsquic_generate_gquic_reset,
.pf_parse_frame_type = parse_frame_type_gquic_Q035_thru_Q039,
.pf_turn_on_fin = lsquic_turn_on_fin_Q035_thru_Q039,
.pf_parse_frame_type = lsquic_parse_frame_type_gquic_Q035_thru_Q046,
.pf_turn_on_fin = lsquic_turn_on_fin_Q035_thru_Q046,
.pf_packout_size = lsquic_gquic_packout_size,
.pf_packout_max_header_size = lsquic_gquic_packout_header_size,
.pf_calc_packno_bits = lsquic_gquic_calc_packno_bits,
.pf_packno_bits2len = lsquic_gquic_packno_bits2len,
.pf_gen_crypto_frame = gquic_be_gen_crypto_frame,
.pf_parse_crypto_frame = gquic_be_parse_crypto_frame,
.pf_packno_info = gquic_be_packno_info,
};

View file

@ -198,7 +198,7 @@ lsquic_generate_gquic_reset (const lsquic_cid_t *cidp,
}
static const enum quic_frame_type byte2frame_type_Q035_thru_Q039[0x100] =
static const enum quic_frame_type byte2frame_type_Q035_thru_Q046[0x100] =
{
[0x00] = QUIC_FRAME_PADDING,
[0x01] = QUIC_FRAME_RST_STREAM,
@ -460,14 +460,14 @@ static const enum quic_frame_type byte2frame_type_Q035_thru_Q039[0x100] =
enum quic_frame_type
parse_frame_type_gquic_Q035_thru_Q039 (unsigned char b)
lsquic_parse_frame_type_gquic_Q035_thru_Q046 (unsigned char b)
{
return byte2frame_type_Q035_thru_Q039[b];
return byte2frame_type_Q035_thru_Q046[b];
}
void
lsquic_turn_on_fin_Q035_thru_Q039 (unsigned char *stream_header)
lsquic_turn_on_fin_Q035_thru_Q046 (unsigned char *stream_header)
{
/* 1fdoooss */
*stream_header |= 0x40;

View file

@ -38,6 +38,8 @@
#include "lsquic_conn.h"
#include "lsquic_enc_sess.h"
#include "lsquic_trans_params.h"
#include "lsquic_parse_ietf.h"
#include "lsquic_qtags.h"
#define LSQUIC_LOGGER_MODULE LSQLM_PARSE
#include "lsquic_logger.h"
@ -235,8 +237,7 @@ gen_long_pkt_header (const struct lsquic_conn *lconn,
vint_write(p, payload_len, bits, 1 << bits);
p += 1 << bits;
p += write_packno(p, packet_out->po_packno,
lsquic_packet_out_packno_bits(packet_out));
p += write_packno(p, packet_out->po_packno, packno_bits);
return p - buf;
}
@ -431,9 +432,10 @@ ietf_v1_gen_stream_frame (unsigned char *buf, size_t buf_len,
}
static int
ietf_v1_gen_crypto_frame (unsigned char *buf, size_t buf_len,
uint64_t offset, size_t size, gcf_read_f gcf_read, void *stream)
int
lsquic_ietf_v1_gen_crypto_frame (unsigned char *buf, unsigned char first_byte,
size_t buf_len, uint64_t offset, size_t size, gcf_read_f gcf_read,
void *stream)
{
unsigned char *const end = buf + buf_len;
unsigned char *p;
@ -454,7 +456,7 @@ ietf_v1_gen_crypto_frame (unsigned char *buf, size_t buf_len,
size = n_avail;
p = buf;
*p++ = 0x06;
*p++ = first_byte;
vint_write(p, offset, obits, olen);
p += olen;
@ -470,6 +472,15 @@ ietf_v1_gen_crypto_frame (unsigned char *buf, size_t buf_len,
}
static int
ietf_v1_gen_crypto_frame (unsigned char *buf, size_t buf_len,
uint64_t offset, size_t size, gcf_read_f gcf_read, void *stream)
{
return lsquic_ietf_v1_gen_crypto_frame(buf, 0x6, buf_len, offset,
size, gcf_read, stream);
}
/* return parsed (used) buffer length */
static int
ietf_v1_parse_stream_frame (const unsigned char *buf, size_t rem_packet_sz,
@ -529,9 +540,9 @@ ietf_v1_parse_stream_frame (const unsigned char *buf, size_t rem_packet_sz,
}
static int
ietf_v1_parse_crypto_frame (const unsigned char *buf, size_t rem_packet_sz,
struct stream_frame *stream_frame)
int
lsquic_ietf_v1_parse_crypto_frame (const unsigned char *buf,
size_t rem_packet_sz, struct stream_frame *stream_frame)
{
const unsigned char *const pend = buf + rem_packet_sz;
const unsigned char *p = buf;
@ -540,7 +551,6 @@ ietf_v1_parse_crypto_frame (const unsigned char *buf, size_t rem_packet_sz,
CHECK_SPACE(1, p, pend);
assert(0x06 == *p);
++p;
r = vint_read(p, pend, &offset);
@ -568,6 +578,20 @@ ietf_v1_parse_crypto_frame (const unsigned char *buf, size_t rem_packet_sz,
}
static int
ietf_v1_parse_crypto_frame (const unsigned char *buf, size_t rem_packet_sz,
struct stream_frame *stream_frame)
{
if (rem_packet_sz > 0)
{
assert(0x06 == buf[0]);
return lsquic_ietf_v1_parse_crypto_frame(buf, rem_packet_sz,
stream_frame);
}
else
return -1;
}
#if __GNUC__
# define UNLIKELY(cond) __builtin_expect(cond, 0)
@ -1044,12 +1068,13 @@ ietf_v1_calc_stream_frame_header_sz (lsquic_stream_id_t stream_id,
}
/* [draft-ietf-quic-transport-24] Section 19.6 */
static size_t
ietf_v1_calc_crypto_frame_header_sz (uint64_t offset)
ietf_v1_calc_crypto_frame_header_sz (uint64_t offset, unsigned data_sz)
{
return 1 /* Frame type */
+ (1 << vint_val2bits(offset))
+ 1 /* Data len */
+ (1 << vint_val2bits(data_sz))
;
}
@ -1705,7 +1730,7 @@ lsquic_ietf_v1_parse_packet_in_long_begin (struct lsquic_packet_in *packet_in,
/* Is this a valid Initial packet? We take the perspective of the server. */
int
lsquic_is_valid_ietf_v1_or_Q046_hs_packet (const unsigned char *buf,
lsquic_is_valid_ietf_v1_or_Q046plus_hs_packet (const unsigned char *buf,
size_t length, lsquic_ver_tag_t *tagp)
{
const unsigned char *p = buf;
@ -1727,11 +1752,11 @@ lsquic_is_valid_ietf_v1_or_Q046_hs_packet (const unsigned char *buf,
memcpy(&tag, p, 4);
p += 4;
if (tag == 0)
return 0; /* Client never sends version negotiation packets */
if (tag == * (uint32_t *) "Q046")
switch (tag)
{
case 0:
return 0; /* Client never sends version negotiation packets */
case TAG('Q', '0', '4', '6'):
dcil = p[0] >> 4;
if (dcil)
dcil += 3;
@ -1747,9 +1772,19 @@ lsquic_is_valid_ietf_v1_or_Q046_hs_packet (const unsigned char *buf,
if (end - p < (ptrdiff_t) (dcil + scil + packet_len))
return 0;
}
else
{
break;
case TAG('Q', '0', '5', '0'):
dcil = *p++;
if (dcil != 8)
return 0;
if (p + dcil + 1 >= end)
return 0;
p += dcil;
scil = *p++;
if (scil != 0)
return 0;
goto read_token;
default:
dcil = *p++;
if (dcil < MIN_INITIAL_DCID_LEN || dcil > MAX_CID_LEN)
return 0;
@ -1760,6 +1795,7 @@ lsquic_is_valid_ietf_v1_or_Q046_hs_packet (const unsigned char *buf,
if (p + scil > end || scil > MAX_CID_LEN)
return 0;
p += scil;
read_token:
r = vint_read(p, end, &token_len);
if (r < 0)
return 0;

View file

@ -319,10 +319,10 @@ stream_stream_frame_header_sz (const struct lsquic_stream *stream,
static size_t
stream_crypto_frame_header_sz (const struct lsquic_stream *stream,
unsigned data_sz_IGNORED)
unsigned data_sz)
{
return stream->conn_pub->lconn->cn_pf
->pf_calc_crypto_frame_header_sz(stream->tosend_off);
->pf_calc_crypto_frame_header_sz(stream->tosend_off, data_sz);
}
@ -333,7 +333,7 @@ stream_is_hsk (const struct lsquic_stream *stream)
if (stream->sm_bflags & SMBF_IETF)
return 0;
else
return stream->id == LSQUIC_GQUIC_STREAM_HANDSHAKE;
return lsquic_stream_is_crypto(stream);
}
@ -366,7 +366,7 @@ stream_new_common (lsquic_stream_id_t id, struct lsquic_conn_public *conn_pub,
STAILQ_INIT(&stream->sm_hq_frames);
stream->sm_bflags |= ctor_flags & ((1 << (N_SMBF_FLAGS - 1)) - 1);
stream->sm_bflags |= ctor_flags & ((1 << N_SMBF_FLAGS) - 1);
if (conn_pub->lconn->cn_flags & LSCONN_SERVER)
stream->sm_bflags |= SMBF_SERVER;
@ -374,10 +374,6 @@ stream_new_common (lsquic_stream_id_t id, struct lsquic_conn_public *conn_pub,
}
/* TODO: The logic to figure out whether the stream is connection limited
* should be taken out of the constructor. The caller should specify this
* via one of enum stream_ctor_flags.
*/
lsquic_stream_t *
lsquic_stream_new (lsquic_stream_id_t id,
struct lsquic_conn_public *conn_pub,
@ -411,10 +407,11 @@ lsquic_stream_new (lsquic_stream_id_t id,
lsquic_stream_set_priority_internal(stream,
LSQUIC_STREAM_DEFAULT_PRIO);
stream->sm_write_to_packet = stream_write_to_packet_std;
stream->sm_frame_header_sz = stream_stream_frame_header_sz;
}
else
{
if (lsquic_stream_id_is_critical(ctor_flags & SCF_HTTP, id))
if (ctor_flags & SCF_CRITICAL)
cfcw = NULL;
else
{
@ -427,17 +424,25 @@ lsquic_stream_new (lsquic_stream_id_t id,
stream->sm_readable = stream_readable_http_gquic;
else
stream->sm_readable = stream_readable_non_http;
if (stream_is_hsk(stream))
stream->sm_write_to_packet = stream_write_to_packet_hsk;
if (ctor_flags & SCF_CRYPTO_FRAMES)
{
stream->sm_frame_header_sz = stream_crypto_frame_header_sz;
stream->sm_write_to_packet = stream_write_to_packet_crypto;
}
else
stream->sm_write_to_packet = stream_write_to_packet_std;
{
if (stream_is_hsk(stream))
stream->sm_write_to_packet = stream_write_to_packet_hsk;
else
stream->sm_write_to_packet = stream_write_to_packet_std;
stream->sm_frame_header_sz = stream_stream_frame_header_sz;
}
}
lsquic_sfcw_init(&stream->fc, initial_window, cfcw, conn_pub, id);
stream->max_send_off = initial_send_off;
LSQ_DEBUG("created stream");
SM_HISTORY_APPEND(stream, SHE_CREATED);
stream->sm_frame_header_sz = stream_stream_frame_header_sz;
if (ctor_flags & SCF_CALL_ON_NEW)
lsquic_stream_call_on_new(stream);
return stream;
@ -2877,6 +2882,7 @@ stream_write_to_packet_std (struct frame_gen_ctx *fg_ctx, const size_t size)
}
/* Use for IETF crypto streams and gQUIC crypto stream for versions >= Q050. */
static enum swtp_status
stream_write_to_packet_crypto (struct frame_gen_ctx *fg_ctx, const size_t size)
{
@ -2886,9 +2892,14 @@ stream_write_to_packet_crypto (struct frame_gen_ctx *fg_ctx, const size_t size)
unsigned crypto_header_sz, need_at_least;
struct lsquic_packet_out *packet_out;
unsigned short off;
const enum packnum_space pns = lsquic_enclev2pns[ crypto_level(stream) ];
enum packnum_space pns;
int len, s;
if (stream->sm_bflags & SMBF_IETF)
pns = lsquic_enclev2pns[ crypto_level(stream) ];
else
pns = PNS_INIT;
assert(size > 0);
crypto_header_sz = stream->sm_frame_header_sz(stream, size);
need_at_least = crypto_header_sz + 1;
@ -2919,6 +2930,15 @@ stream_write_to_packet_crypto (struct frame_gen_ctx *fg_ctx, const size_t size)
packet_out->po_flags |= PO_HELLO;
if (!(stream->sm_bflags & SMBF_IETF))
{
const unsigned short before = packet_out->po_data_sz;
lsquic_packet_out_zero_pad(packet_out);
/* XXX: too hacky */
if (before < packet_out->po_data_sz)
send_ctl->sc_bytes_scheduled += packet_out->po_data_sz - before;
}
check_flush_threshold(stream);
return SWTP_OK;
}
@ -3993,22 +4013,6 @@ lsquic_stream_get_hset (struct lsquic_stream *stream)
}
/* GQUIC-only function */
int
lsquic_stream_id_is_critical (int use_http, lsquic_stream_id_t stream_id)
{
return stream_id == LSQUIC_GQUIC_STREAM_HANDSHAKE
|| (stream_id == LSQUIC_GQUIC_STREAM_HEADERS && use_http);
}
int
lsquic_stream_is_critical (const struct lsquic_stream *stream)
{
return stream->sm_bflags & SMBF_CRITICAL;
}
void
lsquic_stream_set_stream_if (struct lsquic_stream *stream,
const struct lsquic_stream_if *stream_if, void *stream_if_ctx)

View file

@ -2,9 +2,6 @@
#ifndef LSQUIC_STREAM_H
#define LSQUIC_STREAM_H
#define LSQUIC_GQUIC_STREAM_HANDSHAKE 1
#define LSQUIC_GQUIC_STREAM_HEADERS 3
#define LSQUIC_STREAM_DEFAULT_PRIO 16 /* RFC 7540, Section 5.3.5 */
@ -178,12 +175,13 @@ enum stream_b_flags
SMBF_SERVER = 1 << 0,
SMBF_IETF = 1 << 1,
SMBF_USE_HEADERS = 1 << 2,
SMBF_CRYPTO = 1 << 3,
SMBF_CRYPTO = 1 << 3, /* Crypto stream: applies to both gQUIC and IETF QUIC */
SMBF_CRITICAL = 1 << 4, /* This is a critical stream */
SMBF_AUTOSWITCH = 1 << 5,
SMBF_RW_ONCE = 1 << 6, /* When set, read/write events are dispatched once per call */
SMBF_CONN_LIMITED = 1 << 7,
#define N_SMBF_FLAGS 8
SMBF_HEADERS = 1 << 8, /* Headers stream */
#define N_SMBF_FLAGS 9
};
@ -356,6 +354,7 @@ enum stream_ctor_flags
SCF_USE_DI_HASH = (1 << (N_SMBF_FLAGS + 1)), /* Use hash-based data input. If not set,
* the nocopy data input is used.
*/
SCF_CRYPTO_FRAMES = (1 << (N_SMBF_FLAGS + 2)), /* Write CRYPTO frames */
SCF_DI_AUTOSWITCH = SMBF_AUTOSWITCH, /* Automatically switch between nocopy
* and hash-based to data input for optimal
* performance.
@ -364,6 +363,8 @@ enum stream_ctor_flags
SCF_CRITICAL = SMBF_CRITICAL, /* This is a critical stream */
SCF_IETF = SMBF_IETF,
SCF_HTTP = SMBF_USE_HEADERS,
SCF_CRYPTO = SMBF_CRYPTO,
SCF_HEADERS = SMBF_HEADERS,
};
@ -501,11 +502,9 @@ lsquic_stream_update_sfcw (lsquic_stream_t *, uint64_t max_off);
int
lsquic_stream_set_priority_internal (lsquic_stream_t *, unsigned priority);
int
lsquic_stream_id_is_critical (int use_http, lsquic_stream_id_t);
#define lsquic_stream_is_critical(s) ((s)->sm_bflags & SMBF_CRITICAL)
int
lsquic_stream_is_critical (const struct lsquic_stream *);
#define lsquic_stream_is_crypto(s) ((s)->sm_bflags & SMBF_CRYPTO)
size_t
lsquic_stream_mem_used (const struct lsquic_stream *);

View file

@ -11,6 +11,7 @@ static const unsigned char version_tags[N_LSQVER][4] =
[LSQVER_039] = { 'Q', '0', '3', '9', },
[LSQVER_043] = { 'Q', '0', '4', '3', },
[LSQVER_046] = { 'Q', '0', '4', '6', },
[LSQVER_050] = { 'Q', '0', '5', '0', },
#if LSQUIC_USE_Q098
[LSQVER_098] = { 'Q', '0', '9', '8', },
#endif
@ -49,6 +50,7 @@ const char *const lsquic_ver2str[N_LSQVER] = {
[LSQVER_039] = "Q039",
[LSQVER_043] = "Q043",
[LSQVER_046] = "Q046",
[LSQVER_050] = "Q050",
#if LSQUIC_USE_Q098
[LSQVER_098] = "Q098",
#endif