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

@ -1,3 +1,10 @@
2019-12-23
- 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.
2019-12-18
- 2.7.3
- [DEBUG] Further dedup next advisory tick messages when reason is

View File

@ -15,7 +15,7 @@ and OpenLiteSpeed. We think it is free of major problems. Nevertheless, do
not hesitate to report bugs back to us. Even better, send us fixes and
improvements!
Currently supported QUIC versions are Q039, Q043, Q046, ID-23, and ID-24.
Currently supported QUIC versions are Q039, Q043, Q046, Q050, ID-23, and ID-24.
Support for newer versions will be added soon after they are released.
Documentation

View File

@ -24,8 +24,8 @@ extern "C" {
#endif
#define LSQUIC_MAJOR_VERSION 2
#define LSQUIC_MINOR_VERSION 7
#define LSQUIC_PATCH_VERSION 3
#define LSQUIC_MINOR_VERSION 8
#define LSQUIC_PATCH_VERSION 0
/**
* Engine flags:
@ -112,6 +112,13 @@ enum lsquic_version
*/
LSQVER_046,
/**
* Q050. Variable-length QUIC server connection IDs. Use CRYPTO frames
* for handshake. IETF header format matching invariants-06. Packet
* number encryption. Initial packets are obfuscated.
*/
LSQVER_050,
#if LSQUIC_USE_Q098
/**
* Q098. This is a made-up, experimental version used to test version
@ -144,7 +151,7 @@ enum lsquic_version
};
/**
* We currently support versions 39, 43, 46, and IETF Draft-23
* We currently support versions 39, 43, 46, 50, and IETF Draft-23 and Draft-24
* @see lsquic_version
*/
#define LSQUIC_SUPPORTED_VERSIONS ((1 << N_LSQVER) - 1)
@ -152,7 +159,7 @@ enum lsquic_version
/**
* List of versions in which the server never includes CID in short packets.
*/
#define LSQUIC_FORCED_TCID0_VERSIONS (1 << LSQVER_046)
#define LSQUIC_FORCED_TCID0_VERSIONS ((1 << LSQVER_046)|(1 << LSQVER_050))
#define LSQUIC_EXPERIMENTAL_VERSIONS ( \
(1 << LSQVER_VERNEG) | LSQUIC_EXPERIMENTAL_Q098)

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

View File

@ -30,7 +30,6 @@ SET(TESTS
arr
attq
blocked_gquic_be
buf
bw_sampler
conn_close_gquic_be
crypto_gen

View File

@ -1,44 +0,0 @@
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
#include <assert.h>
#include <stddef.h>
#include <string.h>
#ifdef WIN32
#include <vc_compat.h>
#endif
#include "lsquic_buf.h"
int
main (void)
{
struct lsquic_buf *buf;
int s;
buf = lsquic_buf_create(10);
assert(buf);
assert(0 == lsquic_buf_size(buf));
assert(10 == lsquic_buf_avail(buf));
assert(10 == lsquic_buf_capacity(buf));
s = lsquic_buf_append(NULL, NULL, 0);
assert(s < 0);
s = lsquic_buf_append(buf, (void *) 123, -1);
assert(s < 0);
s = lsquic_buf_append(buf, "dude", 4);
assert(4 == s);
assert(4 == lsquic_buf_size(buf));
assert(6 == lsquic_buf_avail(buf));
assert(10 == lsquic_buf_capacity(buf));
s = lsquic_buf_append(buf, ", where is my car?!", 20);
assert(20 == s);
assert(4 + 20 == lsquic_buf_size(buf));
assert(0 == strcasecmp(lsquic_buf_begin(buf), "Dude, where is my car?!"));
/* Yeah, where's your car, dude? */
return 0;
}

View File

@ -424,15 +424,15 @@ static const struct export_key_test tests[] = {
static void
run_ekt_test (const struct export_key_test *test)
{
int s;
int s, i;
unsigned char client_key[0x100],
server_key[0x100],
client_iv[0x100],
server_iv[0x100];
/* XXX: sub_key is confusing -- why is it so large? */
unsigned char sub_key[0x1000];
unsigned char sub_key[32];
unsigned char c_hp[16], s_hp[16];
/* Sanity check the test itself: */
assert(test->ekt_client_key_sz < sizeof(client_key));
@ -440,23 +440,28 @@ run_ekt_test (const struct export_key_test *test)
assert(test->ekt_server_iv_sz < sizeof(server_iv));
assert(test->ekt_client_iv_sz < sizeof(client_iv));
s = export_key_material(test->ekt_ikm, (uint32_t)test->ekt_ikm_sz,
test->ekt_salt, (int)test->ekt_salt_sz,
test->ekt_context, (uint32_t)test->ekt_context_sz,
(uint16_t)test->ekt_client_key_sz, client_key,
(uint16_t)test->ekt_server_key_sz, server_key,
(uint16_t)test->ekt_client_iv_sz, client_iv,
(uint16_t)test->ekt_server_iv_sz, server_iv,
sub_key);
assert(0 == s); /* This function always returns zero */
if (test->ekt_client_key_sz)
assert(0 == memcmp(client_key, test->ekt_client_key,
test->ekt_client_key_sz));
if (test->ekt_server_key_sz)
assert(0 == memcmp(server_key, test->ekt_server_key,
test->ekt_server_key_sz));
for (i = 0; i < 2; ++i)
{
s = lsquic_export_key_material(test->ekt_ikm, (uint32_t)test->ekt_ikm_sz,
test->ekt_salt, (int)test->ekt_salt_sz,
test->ekt_context, (uint32_t)test->ekt_context_sz,
(uint16_t)test->ekt_client_key_sz, client_key,
(uint16_t)test->ekt_server_key_sz, server_key,
(uint16_t)test->ekt_client_iv_sz, client_iv,
(uint16_t)test->ekt_server_iv_sz, server_iv,
sub_key,
/* Keys should not change because HP pointers are given */
i ? c_hp : NULL,
i ? s_hp : NULL
);
assert(0 == s); /* This function always returns zero */
if (test->ekt_client_key_sz)
assert(0 == memcmp(client_key, test->ekt_client_key,
test->ekt_client_key_sz));
if (test->ekt_server_key_sz)
assert(0 == memcmp(server_key, test->ekt_server_key,
test->ekt_server_key_sz));
}
}

View File

@ -21,7 +21,7 @@ void test_HKDF()
32) == 0);
L = 42;
lshkdf_expand(prk, (const unsigned char *) "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9", 10, L, okm, 0, NULL, 0, NULL, 0, NULL, 0, NULL);
lshkdf_expand(prk, (const unsigned char *) "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9", 10, L, okm, 0, NULL, 0, NULL, 0, NULL, 0, NULL, NULL, NULL);
assert(memcmp(okm, "\x3c\xb2\x5f\x25\xfa\xac\xd5\x7a\x90\x43\x4f\x64\xd0\x36\x2f\x2a"
"\x2d\x2d\x0a\x90\xcf\x1a\x5a\x4c\x5d\xb0\x2d\x56\xec\xc4\xc5\xbf"
"\x34\x00\x72\x08\xd5\xb8\x87\x18\x58\x65", L) == 0);
@ -52,7 +52,7 @@ void test_HKDF()
"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef"
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
80, L, okm, 0, NULL, 0, NULL, 0, NULL, 0, NULL);
80, L, okm, 0, NULL, 0, NULL, 0, NULL, 0, NULL, NULL, NULL);
assert(memcmp(okm, "\xb1\x1e\x39\x8d\xc8\x03\x27\xa1\xc8\xe7\xf7\x8c\x59\x6a\x49\x34"
"\x4f\x01\x2e\xda\x2d\x4e\xfa\xd8\xa0\x50\xcc\x4c\x19\xaf\xa9\x7c"
"\x59\x04\x5a\x99\xca\xc7\x82\x72\x71\xcb\x41\xc6\x5e\x59\x0e\x09"
@ -71,7 +71,7 @@ void test_HKDF()
32) == 0);
L = 42;
lshkdf_expand(prk, NULL, 0, L, okm, 0, NULL, 0, NULL, 0, NULL, 0, NULL);
lshkdf_expand(prk, NULL, 0, L, okm, 0, NULL, 0, NULL, 0, NULL, 0, NULL, NULL, NULL);
assert(memcmp(okm, "\x8d\xa4\xe7\x75\xa5\x63\xc1\x8f\x71\x5f\x80\x2a\x06\x3c\x5a\x31"
"\xb8\xa1\x1f\x5c\x5e\xe1\x87\x9e\xc3\x45\x4e\x5f\x3c\x73\x8d\x2d"
"\x9d\x20\x13\x95\xfa\xa4\xb6\x1a\x96\xc8", L) == 0);

View File

@ -158,8 +158,8 @@ struct stream_info
const struct stream_info infos1[] = {
{ LSQUIC_GQUIC_STREAM_HANDSHAKE, SMBF_CRITICAL, 0, },
{ LSQUIC_GQUIC_STREAM_HEADERS, SMBF_CRITICAL, 0, },
{ 1, SMBF_CRITICAL, 0, },
{ 3, SMBF_CRITICAL, 0, },
{ 5, 0, 0, },
{ 7, 0, 1, },
{ 127, 0, 200, },
@ -167,8 +167,8 @@ const struct stream_info infos1[] = {
const struct stream_info infos2[] = {
{ LSQUIC_GQUIC_STREAM_HANDSHAKE, SMBF_CRITICAL, 0, },
{ LSQUIC_GQUIC_STREAM_HEADERS, SMBF_CRITICAL, 0, },
{ 1, SMBF_CRITICAL, 0, },
{ 3, SMBF_CRITICAL, 0, },
{ 5, 0, 4, },
{ 7, 0, 1, },
{ 127, 0, 200, },

View File

@ -426,14 +426,23 @@ new_frame_in (struct test_objs *tobjs, size_t off, size_t sz, int fin)
static lsquic_stream_t *
new_stream_ext (struct test_objs *tobjs, unsigned stream_id, uint64_t send_off)
{
enum stream_ctor_flags ctor_flags;
if (g_use_crypto_ctor)
return lsquic_stream_new_crypto(stream_id, &tobjs->conn_pub,
tobjs->stream_if, tobjs->stream_if_ctx,
tobjs->ctor_flags | SCF_CRITICAL);
else
{
/* For the purposes of the unit test, consider streams 1 and 3 critical */
if (stream_id == 3 || stream_id == 1)
ctor_flags = SCF_CRITICAL;
else
ctor_flags = 0;
return lsquic_stream_new(stream_id, &tobjs->conn_pub, tobjs->stream_if,
tobjs->stream_if_ctx, tobjs->initial_stream_window, send_off,
tobjs->ctor_flags);
tobjs->ctor_flags | ctor_flags);
}
}
@ -1256,7 +1265,7 @@ test_unlimited_stream_flush_data (struct test_objs *tobjs)
const struct lsquic_conn_cap *const cap = &tobjs->conn_pub.conn_cap;
assert(0x4000 == lsquic_conn_cap_avail(cap)); /* Self-check */
stream = new_stream(tobjs, LSQUIC_GQUIC_STREAM_HANDSHAKE);
stream = new_stream(tobjs, 1);
n = lsquic_stream_write(stream, buf, 100);
assert(n == 100);
@ -1540,7 +1549,7 @@ test_conn_unlimited (void)
unsigned char *const data = calloc(1, 0x4000);
/* Test 1: first write headers, then data stream */
header_stream = new_stream(&tobjs, LSQUIC_GQUIC_STREAM_HANDSHAKE);
header_stream = new_stream(&tobjs, 1);
data_stream = new_stream(&tobjs, 123);
nw = lsquic_stream_write(header_stream, data, 98);
assert(98 == nw);
@ -1552,7 +1561,7 @@ test_conn_unlimited (void)
lsquic_stream_destroy(data_stream);
/* Test 2: first write data, then headers stream */
header_stream = new_stream(&tobjs, LSQUIC_GQUIC_STREAM_HANDSHAKE);
header_stream = new_stream(&tobjs, 1);
data_stream = new_stream(&tobjs, 123);
lsquic_conn_cap_init(&tobjs.conn_pub.conn_cap, 0x4000);
nw = lsquic_stream_write(data_stream, data, 0x4000);
@ -2775,7 +2784,7 @@ test_window_update2 (void)
init_test_objs(&tobjs, 0x4000, 0x4000, NULL);
n_closed = 0;
stream = new_stream_ext(&tobjs, LSQUIC_GQUIC_STREAM_HANDSHAKE, 3);
stream = new_stream_ext(&tobjs, 1, 3);
nw = lsquic_stream_write(stream, "1234567890", 10);
lsquic_stream_flush(stream);
assert(("lsquic_stream_write is limited by the send window", 3 == nw));