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:
parent
ff892190dd
commit
7a8b2ece3a
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) ( \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -30,7 +30,6 @@ SET(TESTS
|
|||
arr
|
||||
attq
|
||||
blocked_gquic_be
|
||||
buf
|
||||
bw_sampler
|
||||
conn_close_gquic_be
|
||||
crypto_gen
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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, },
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue