mirror of
https://gitea.invidious.io/iv-org/litespeed-quic.git
synced 2024-08-15 00:53:43 +00:00
Release 2.4.2
- [BUGFIX] H3 framing: fix zero-byte write when space is available - [BUGFIX] Don't send STREAM frame when incoming unidirectgional stream is closed - [BUGFIX] Cancel all pending writes by stream reset by a GOAWAY - [BUGFIX] Fix use-after-free in IETF full conn - [OPTIMIZATION] Wait for session tickets for two seconds and then drop SSL object and crypto streams.
This commit is contained in:
parent
3ff30b2745
commit
65728dc5ee
11 changed files with 320 additions and 109 deletions
10
CHANGELOG
10
CHANGELOG
|
@ -1,3 +1,13 @@
|
|||
2019-09-23
|
||||
- 2.4.2
|
||||
- [BUGFIX] H3 framing: fix zero-byte write when space is available
|
||||
- [BUGFIX] Don't send STREAM frame when incoming unidirectgional stream
|
||||
is closed
|
||||
- [BUGFIX] Cancel all pending writes by stream reset by a GOAWAY
|
||||
- [BUGFIX] Fix use-after-free in IETF full conn
|
||||
- [OPTIMIZATION] Wait for session tickets for two seconds and then drop
|
||||
SSL object and crypto streams.
|
||||
|
||||
2019-09-18
|
||||
- 2.4.0
|
||||
- [FEATURE] QUIC and HTTP/3 Internet Draft 23 support
|
||||
|
|
|
@ -25,7 +25,7 @@ extern "C" {
|
|||
|
||||
#define LSQUIC_MAJOR_VERSION 2
|
||||
#define LSQUIC_MINOR_VERSION 4
|
||||
#define LSQUIC_PATCH_VERSION 0
|
||||
#define LSQUIC_PATCH_VERSION 2
|
||||
|
||||
/**
|
||||
* Engine flags:
|
||||
|
|
|
@ -47,6 +47,7 @@ static const char *const lsquic_alid2str[] =
|
|||
[AL_CID_THROT] = "CID_THROT",
|
||||
[AL_PATH_CHAL_0] = "PATH_CHAL_0",
|
||||
[AL_PATH_CHAL_1] = "PATH_CHAL_1",
|
||||
[AL_SESS_TICKET] = "SESS_TICKET",
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ enum alarm_id {
|
|||
AL_PATH_CHAL,
|
||||
AL_PATH_CHAL_0 = AL_PATH_CHAL,
|
||||
AL_PATH_CHAL_1,
|
||||
AL_SESS_TICKET,
|
||||
MAX_LSQUIC_ALARMS
|
||||
};
|
||||
|
||||
|
@ -54,6 +55,7 @@ enum alarm_id_bit {
|
|||
ALBIT_PATH_CHAL = 1 << AL_PATH_CHAL,
|
||||
ALBIT_PATH_CHAL_0 = 1 << AL_PATH_CHAL_0,
|
||||
ALBIT_PATH_CHAL_1 = 1 << AL_PATH_CHAL_1,
|
||||
ALBIT_SESS_TICKET = 1 << AL_SESS_TICKET,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -240,6 +240,10 @@ struct conn_iface
|
|||
|
||||
const lsquic_cid_t *
|
||||
(*ci_get_log_cid) (const struct lsquic_conn *);
|
||||
|
||||
/* Optional method. Only used by the IETF client code. */
|
||||
void
|
||||
(*ci_drop_crypto_streams) (struct lsquic_conn *);
|
||||
};
|
||||
|
||||
#define LSCONN_CCE_BITS 3
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#ifndef LSQUIC_ENC_SESS_H
|
||||
#define LSQUIC_ENC_SESS_H 1
|
||||
|
||||
struct lsquic_alarmset;
|
||||
struct lsquic_engine_public;
|
||||
struct lsquic_packet_out;
|
||||
struct lsquic_packet_in;
|
||||
|
@ -262,7 +263,8 @@ struct enc_session_funcs_iquic
|
|||
struct lsquic_conn *, const struct lsquic_cid *,
|
||||
const struct ver_neg *, void *(crypto_streams)[4],
|
||||
const struct crypto_stream_if *,
|
||||
const unsigned char *, size_t);
|
||||
const unsigned char *, size_t,
|
||||
struct lsquic_alarmset *);
|
||||
|
||||
void
|
||||
(*esfi_destroy) (enc_session_t *);
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "lsquic_frab_list.h"
|
||||
#include "lsquic_tokgen.h"
|
||||
#include "lsquic_ietf.h"
|
||||
#include "lsquic_alarmset.h"
|
||||
|
||||
#if __GNUC__
|
||||
# define UNLIKELY(cond) __builtin_expect(cond, 0)
|
||||
|
@ -106,6 +107,10 @@ iquic_esf_get_server_cert_chain (enc_session_t *);
|
|||
static void
|
||||
maybe_drop_SSL (struct enc_sess_iquic *);
|
||||
|
||||
static void
|
||||
no_sess_ticket (enum alarm_id alarm_id, void *ctx,
|
||||
lsquic_time_t expiry, lsquic_time_t now);
|
||||
|
||||
|
||||
typedef void (*gen_hp_mask_f)(struct enc_sess_iquic *,
|
||||
const struct header_prot *, unsigned cliser,
|
||||
|
@ -236,6 +241,7 @@ struct enc_sess_iquic
|
|||
ESI_ALPN_CHECKED = 1 << 8,
|
||||
ESI_CACHED_INFO = 1 << 9,
|
||||
ESI_1RTT_ACKED = 1 << 10,
|
||||
ESI_WANT_TICKET = 1 << 11,
|
||||
} esi_flags;
|
||||
enum evp_aead_direction_t
|
||||
esi_dir[2]; /* client, server */
|
||||
|
@ -264,6 +270,8 @@ struct enc_sess_iquic
|
|||
struct frab_list esi_frals[N_ENC_LEVS];
|
||||
struct transport_params
|
||||
esi_peer_tp;
|
||||
struct lsquic_alarmset
|
||||
*esi_alset;
|
||||
};
|
||||
|
||||
|
||||
|
@ -651,7 +659,8 @@ iquic_esfi_create_client (const char *hostname,
|
|||
struct lsquic_engine_public *enpub, struct lsquic_conn *lconn,
|
||||
const lsquic_cid_t *dcid, const struct ver_neg *ver_neg,
|
||||
void *crypto_streams[4], const struct crypto_stream_if *cryst_if,
|
||||
const unsigned char *zero_rtt, size_t zero_rtt_sz)
|
||||
const unsigned char *zero_rtt, size_t zero_rtt_sz,
|
||||
struct lsquic_alarmset *alset)
|
||||
{
|
||||
struct enc_sess_iquic *enc_sess;
|
||||
|
||||
|
@ -720,6 +729,12 @@ iquic_esfi_create_client (const char *hostname,
|
|||
enc_sess->esi_zero_rtt_sz = 0;
|
||||
}
|
||||
|
||||
if (enc_sess->esi_enpub->enp_stream_if->on_zero_rtt_info)
|
||||
enc_sess->esi_flags |= ESI_WANT_TICKET;
|
||||
enc_sess->esi_alset = alset;
|
||||
lsquic_alarmset_init_alarm(enc_sess->esi_alset, AL_SESS_TICKET,
|
||||
no_sess_ticket, enc_sess);
|
||||
|
||||
return enc_sess;
|
||||
}
|
||||
|
||||
|
@ -1192,6 +1207,8 @@ iquic_new_session_cb (SSL *ssl, SSL_SESSION *session)
|
|||
enc_sess->esi_enpub->enp_stream_if->on_zero_rtt_info(enc_sess->esi_conn,
|
||||
buf, buf_sz);
|
||||
free(buf);
|
||||
enc_sess->esi_flags &= ~ESI_WANT_TICKET;
|
||||
lsquic_alarmset_unset(enc_sess->esi_alset, AL_SESS_TICKET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2202,6 +2219,20 @@ cache_info (struct enc_sess_iquic *enc_sess)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
drop_SSL (struct enc_sess_iquic *enc_sess)
|
||||
{
|
||||
LSQ_DEBUG("drop SSL object");
|
||||
if (enc_sess->esi_conn->cn_if->ci_drop_crypto_streams)
|
||||
enc_sess->esi_conn->cn_if->ci_drop_crypto_streams(
|
||||
enc_sess->esi_conn);
|
||||
cache_info(enc_sess);
|
||||
SSL_free(enc_sess->esi_ssl);
|
||||
enc_sess->esi_ssl = NULL;
|
||||
free_handshake_keys(enc_sess);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
maybe_drop_SSL (struct enc_sess_iquic *enc_sess)
|
||||
{
|
||||
|
@ -2216,15 +2247,32 @@ maybe_drop_SSL (struct enc_sess_iquic *enc_sess)
|
|||
&& enc_sess->esi_ssl
|
||||
&& lsquic_frab_list_empty(&enc_sess->esi_frals[ENC_LEV_FORW]))
|
||||
{
|
||||
LSQ_DEBUG("drop SSL object");
|
||||
cache_info(enc_sess);
|
||||
SSL_free(enc_sess->esi_ssl);
|
||||
enc_sess->esi_ssl = NULL;
|
||||
free_handshake_keys(enc_sess);
|
||||
if ((enc_sess->esi_flags & (ESI_SERVER|ESI_WANT_TICKET))
|
||||
!= ESI_WANT_TICKET)
|
||||
drop_SSL(enc_sess);
|
||||
else if (enc_sess->esi_alset
|
||||
&& !lsquic_alarmset_is_set(enc_sess->esi_alset, AL_SESS_TICKET))
|
||||
{
|
||||
LSQ_DEBUG("no session ticket: delay dropping SSL object");
|
||||
lsquic_alarmset_set(enc_sess->esi_alset, AL_SESS_TICKET,
|
||||
/* Wait up to two seconds for session tickets */
|
||||
lsquic_time_now() + 2000000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
no_sess_ticket (enum alarm_id alarm_id, void *ctx,
|
||||
lsquic_time_t expiry, lsquic_time_t now)
|
||||
{
|
||||
struct enc_sess_iquic *enc_sess = ctx;
|
||||
|
||||
LSQ_DEBUG("no session tickets forthcoming -- drop SSL");
|
||||
drop_SSL(enc_sess);
|
||||
}
|
||||
|
||||
|
||||
typedef char enums_have_the_same_value[
|
||||
(int) ssl_encryption_initial == (int) ENC_LEV_CLEAR &&
|
||||
(int) ssl_encryption_early_data == (int) ENC_LEV_EARLY &&
|
||||
|
@ -2583,23 +2631,43 @@ readf_cb (void *ctx, const unsigned char *buf, size_t len, int fin)
|
|||
}
|
||||
|
||||
|
||||
static size_t
|
||||
discard_cb (void *ctx, const unsigned char *buf, size_t len, int fin)
|
||||
{
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
chsk_ietf_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
|
||||
{
|
||||
struct enc_sess_iquic *const enc_sess = (void *) ctx;
|
||||
enum enc_level enc_level = enc_sess->esi_cryst_if->csi_enc_level(stream);
|
||||
struct readf_ctx readf_ctx = { enc_sess, enc_level, 0, };
|
||||
ssize_t nread;
|
||||
|
||||
|
||||
ssize_t nread = enc_sess->esi_cryst_if->csi_readf(stream,
|
||||
readf_cb, &readf_ctx);
|
||||
|
||||
if (!(nread < 0 || readf_ctx.err))
|
||||
iquic_esfi_shake_stream((enc_session_t *)enc_sess, stream, "on_read");
|
||||
if (enc_sess->esi_ssl)
|
||||
{
|
||||
nread = enc_sess->esi_cryst_if->csi_readf(stream, readf_cb, &readf_ctx);
|
||||
if (!(nread < 0 || readf_ctx.err))
|
||||
iquic_esfi_shake_stream((enc_session_t *)enc_sess, stream,
|
||||
"on_read");
|
||||
else
|
||||
enc_sess->esi_conn->cn_if->ci_internal_error(enc_sess->esi_conn,
|
||||
"shaking stream failed: nread: %zd, err: %d, SSL err: %"PRIu32,
|
||||
nread, readf_ctx.err, ERR_get_error());
|
||||
}
|
||||
else
|
||||
enc_sess->esi_conn->cn_if->ci_internal_error(enc_sess->esi_conn,
|
||||
"shaking stream failed: nread: %zd, err: %d, SSL err: %"PRIu32,
|
||||
nread, readf_ctx.err, ERR_get_error());
|
||||
{
|
||||
/* This branch is reached when we don't want TLS ticket and drop
|
||||
* the SSL object before we process TLS tickets that have been
|
||||
* already received and waiting in the incoming stream buffer.
|
||||
*/
|
||||
nread = enc_sess->esi_cryst_if->csi_readf(stream, discard_cb, NULL);
|
||||
lsquic_stream_wantread(stream, 0);
|
||||
LSQ_DEBUG("no SSL object: discard %zd bytes of SSL data", nread);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -123,6 +123,7 @@ enum ifull_conn_flags
|
|||
IFC_GOAWAY_CLOSE = 1 << 23,
|
||||
IFC_FIRST_TICK = 1 << 24,
|
||||
IFC_IGNORE_HSK = 1 << 25,
|
||||
IFC_PROC_CRYPTO = 1 << 26,
|
||||
};
|
||||
|
||||
|
||||
|
@ -359,9 +360,9 @@ struct ietf_full_conn
|
|||
unsigned ifc_last_retire_prior_to;
|
||||
lsquic_time_t ifc_last_live_update;
|
||||
struct conn_path ifc_paths[N_PATHS];
|
||||
struct lsquic_stream *ifc_crypto_streams[N_ENC_LEVS];
|
||||
union {
|
||||
struct {
|
||||
struct lsquic_stream *crypto_streams[N_ENC_LEVS];
|
||||
struct ver_neg
|
||||
ifcli_ver_neg;
|
||||
uint64_t ifcli_max_push_id;
|
||||
|
@ -1035,8 +1036,8 @@ lsquic_ietf_full_conn_client_new (struct lsquic_engine_public *enpub,
|
|||
conn->ifc_conn.cn_esf.i->esfi_create_client(hostname,
|
||||
conn->ifc_enpub, &conn->ifc_conn, CUR_DCID(conn),
|
||||
&conn->ifc_u.cli.ifcli_ver_neg,
|
||||
(void **) conn->ifc_crypto_streams, &crypto_stream_if,
|
||||
zero_rtt, zero_rtt_sz);
|
||||
(void **) conn->ifc_u.cli.crypto_streams, &crypto_stream_if,
|
||||
zero_rtt, zero_rtt_sz, &conn->ifc_alset);
|
||||
if (!conn->ifc_conn.cn_enc_session)
|
||||
{
|
||||
/* TODO: free other stuff */
|
||||
|
@ -1044,17 +1045,17 @@ lsquic_ietf_full_conn_client_new (struct lsquic_engine_public *enpub,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
conn->ifc_crypto_streams[ENC_LEV_CLEAR] = lsquic_stream_new_crypto(
|
||||
conn->ifc_u.cli.crypto_streams[ENC_LEV_CLEAR] = lsquic_stream_new_crypto(
|
||||
ENC_LEV_CLEAR, &conn->ifc_pub, &lsquic_cry_sm_if,
|
||||
conn->ifc_conn.cn_enc_session,
|
||||
SCF_IETF|SCF_DI_AUTOSWITCH|SCF_CALL_ON_NEW|SCF_CRITICAL);
|
||||
if (!conn->ifc_crypto_streams[ENC_LEV_CLEAR])
|
||||
if (!conn->ifc_u.cli.crypto_streams[ENC_LEV_CLEAR])
|
||||
{
|
||||
/* TODO: free other stuff */
|
||||
free(conn);
|
||||
return NULL;
|
||||
}
|
||||
if (!lsquic_stream_get_ctx(conn->ifc_crypto_streams[ENC_LEV_CLEAR]))
|
||||
if (!lsquic_stream_get_ctx(conn->ifc_u.cli.crypto_streams[ENC_LEV_CLEAR]))
|
||||
{
|
||||
/* TODO: free other stuff */
|
||||
free(conn);
|
||||
|
@ -1065,9 +1066,10 @@ lsquic_ietf_full_conn_client_new (struct lsquic_engine_public *enpub,
|
|||
if (!conn->ifc_pub.packet_out_malo)
|
||||
{
|
||||
free(conn);
|
||||
lsquic_stream_destroy(conn->ifc_crypto_streams[ENC_LEV_CLEAR]);
|
||||
lsquic_stream_destroy(conn->ifc_u.cli.crypto_streams[ENC_LEV_CLEAR]);
|
||||
return NULL;
|
||||
}
|
||||
conn->ifc_flags |= IFC_PROC_CRYPTO;
|
||||
|
||||
LSQ_DEBUG("negotiating version %s",
|
||||
lsquic_ver2str[conn->ifc_u.cli.ifcli_ver_neg.vn_ver]);
|
||||
|
@ -2322,6 +2324,32 @@ ietf_full_conn_ci_retire_cid (struct lsquic_conn *lconn)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
drop_crypto_streams (struct ietf_full_conn *conn)
|
||||
{
|
||||
struct lsquic_stream **streamp;
|
||||
unsigned count;
|
||||
|
||||
if (!(conn->ifc_flags & IFC_PROC_CRYPTO))
|
||||
return;
|
||||
|
||||
conn->ifc_flags &= ~IFC_PROC_CRYPTO;
|
||||
|
||||
count = 0;
|
||||
for (streamp = conn->ifc_u.cli.crypto_streams; streamp <
|
||||
conn->ifc_u.cli.crypto_streams + sizeof(conn->ifc_u.cli.crypto_streams)
|
||||
/ sizeof(conn->ifc_u.cli.crypto_streams[0]); ++streamp)
|
||||
if (*streamp)
|
||||
{
|
||||
lsquic_stream_force_finish(*streamp);
|
||||
*streamp = NULL;
|
||||
++count;
|
||||
}
|
||||
|
||||
LSQ_DEBUG("dropped %u crypto stream%.*s", count, count != 1, "s");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ietf_full_conn_ci_destroy (struct lsquic_conn *lconn)
|
||||
{
|
||||
|
@ -2332,11 +2360,15 @@ ietf_full_conn_ci_destroy (struct lsquic_conn *lconn)
|
|||
struct lsquic_hash_elem *el;
|
||||
unsigned i;
|
||||
|
||||
for (streamp = conn->ifc_crypto_streams; streamp <
|
||||
conn->ifc_crypto_streams + sizeof(conn->ifc_crypto_streams)
|
||||
/ sizeof(conn->ifc_crypto_streams[0]); ++streamp)
|
||||
if (*streamp)
|
||||
lsquic_stream_destroy(*streamp);
|
||||
if (!(conn->ifc_flags & IFC_SERVER))
|
||||
{
|
||||
for (streamp = conn->ifc_u.cli.crypto_streams; streamp <
|
||||
conn->ifc_u.cli.crypto_streams
|
||||
+ sizeof(conn->ifc_u.cli.crypto_streams)
|
||||
/ sizeof(conn->ifc_u.cli.crypto_streams[0]); ++streamp)
|
||||
if (*streamp)
|
||||
lsquic_stream_destroy(*streamp);
|
||||
}
|
||||
while ((el = lsquic_hash_first(conn->ifc_pub.all_streams)))
|
||||
{
|
||||
stream = lsquic_hashelem_getdata(el);
|
||||
|
@ -3366,9 +3398,10 @@ process_crypto_stream_read_events (struct ietf_full_conn *conn)
|
|||
{
|
||||
struct lsquic_stream **stream;
|
||||
|
||||
for (stream = conn->ifc_crypto_streams; stream <
|
||||
conn->ifc_crypto_streams + sizeof(conn->ifc_crypto_streams)
|
||||
/ sizeof(conn->ifc_crypto_streams[0]); ++stream)
|
||||
assert(!(conn->ifc_flags & IFC_SERVER));
|
||||
for (stream = conn->ifc_u.cli.crypto_streams; stream <
|
||||
conn->ifc_u.cli.crypto_streams + sizeof(conn->ifc_u.cli.crypto_streams)
|
||||
/ sizeof(conn->ifc_u.cli.crypto_streams[0]); ++stream)
|
||||
if (*stream && (*stream)->sm_qflags & SMQF_WANT_READ)
|
||||
lsquic_stream_dispatch_read_events(*stream);
|
||||
}
|
||||
|
@ -3379,9 +3412,10 @@ process_crypto_stream_write_events (struct ietf_full_conn *conn)
|
|||
{
|
||||
struct lsquic_stream **stream;
|
||||
|
||||
for (stream = conn->ifc_crypto_streams; stream <
|
||||
conn->ifc_crypto_streams + sizeof(conn->ifc_crypto_streams)
|
||||
/ sizeof(conn->ifc_crypto_streams[0]); ++stream)
|
||||
assert(!(conn->ifc_flags & IFC_SERVER));
|
||||
for (stream = conn->ifc_u.cli.crypto_streams; stream <
|
||||
conn->ifc_u.cli.crypto_streams + sizeof(conn->ifc_u.cli.crypto_streams)
|
||||
/ sizeof(conn->ifc_u.cli.crypto_streams[0]); ++stream)
|
||||
if (*stream && (*stream)->sm_qflags & SMQF_WRITE_Q_FLAGS)
|
||||
lsquic_stream_dispatch_write_events(*stream);
|
||||
}
|
||||
|
@ -4260,9 +4294,8 @@ process_stop_sending_frame (struct ietf_full_conn *conn,
|
|||
}
|
||||
|
||||
|
||||
/* Ignore CRYPTO frames in server mode */
|
||||
static unsigned
|
||||
process_crypto_frame_server (struct ietf_full_conn *conn,
|
||||
discard_crypto_frame (struct ietf_full_conn *conn,
|
||||
struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len)
|
||||
{
|
||||
struct stream_frame stream_frame;
|
||||
|
@ -4271,14 +4304,17 @@ process_crypto_frame_server (struct ietf_full_conn *conn,
|
|||
parsed_len = conn->ifc_conn.cn_pf->pf_parse_crypto_frame(p, len,
|
||||
&stream_frame);
|
||||
if (parsed_len > 0)
|
||||
{
|
||||
LSQ_DEBUG("discard %d-byte CRYPTO frame", parsed_len);
|
||||
return (unsigned) parsed_len;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned
|
||||
process_crypto_frame_client (struct ietf_full_conn *conn,
|
||||
process_crypto_frame (struct ietf_full_conn *conn,
|
||||
struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len)
|
||||
{
|
||||
struct stream_frame *stream_frame;
|
||||
|
@ -4286,6 +4322,12 @@ process_crypto_frame_client (struct ietf_full_conn *conn,
|
|||
enum enc_level enc_level;
|
||||
int parsed_len;
|
||||
|
||||
/* Ignore CRYPTO frames in server mode and in client mode after SSL object
|
||||
* is gone.
|
||||
*/
|
||||
if (!(conn->ifc_flags & IFC_PROC_CRYPTO))
|
||||
return discard_crypto_frame(conn, packet_in, p, len);
|
||||
|
||||
stream_frame = lsquic_malo_get(conn->ifc_pub.mm->malo.stream_frame);
|
||||
if (!stream_frame)
|
||||
{
|
||||
|
@ -4317,8 +4359,9 @@ process_crypto_frame_client (struct ietf_full_conn *conn,
|
|||
return parsed_len;
|
||||
}
|
||||
|
||||
if (conn->ifc_crypto_streams[enc_level])
|
||||
stream = conn->ifc_crypto_streams[enc_level];
|
||||
assert(!(conn->ifc_flags & IFC_SERVER));
|
||||
if (conn->ifc_u.cli.crypto_streams[enc_level])
|
||||
stream = conn->ifc_u.cli.crypto_streams[enc_level];
|
||||
else
|
||||
{
|
||||
stream = lsquic_stream_new_crypto(enc_level, &conn->ifc_pub,
|
||||
|
@ -4330,7 +4373,7 @@ process_crypto_frame_client (struct ietf_full_conn *conn,
|
|||
ABORT_WARN("cannot create crypto stream for level %u", enc_level);
|
||||
return 0;
|
||||
}
|
||||
conn->ifc_crypto_streams[enc_level] = stream;
|
||||
conn->ifc_u.cli.crypto_streams[enc_level] = stream;
|
||||
(void) lsquic_stream_wantread(stream, 1);
|
||||
}
|
||||
|
||||
|
@ -4357,17 +4400,6 @@ process_crypto_frame_client (struct ietf_full_conn *conn,
|
|||
}
|
||||
|
||||
|
||||
static unsigned
|
||||
process_crypto_frame (struct ietf_full_conn *conn,
|
||||
struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len)
|
||||
{
|
||||
if (conn->ifc_flags & IFC_SERVER)
|
||||
return process_crypto_frame_server(conn, packet_in, p, len);
|
||||
else
|
||||
return process_crypto_frame_client(conn, packet_in, p, len);
|
||||
}
|
||||
|
||||
|
||||
static unsigned
|
||||
process_stream_frame (struct ietf_full_conn *conn,
|
||||
struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len)
|
||||
|
@ -5419,11 +5451,12 @@ ignore_init (struct ietf_full_conn *conn)
|
|||
lsquic_alarmset_unset(&conn->ifc_alset, AL_ACK_INIT + PNS_INIT);
|
||||
lsquic_send_ctl_empty_pns(&conn->ifc_send_ctl, PNS_INIT);
|
||||
lsquic_rechist_cleanup(&conn->ifc_rechist[PNS_INIT]);
|
||||
if (conn->ifc_crypto_streams[ENC_LEV_CLEAR])
|
||||
{
|
||||
lsquic_stream_destroy(conn->ifc_crypto_streams[ENC_LEV_CLEAR]);
|
||||
conn->ifc_crypto_streams[ENC_LEV_CLEAR] = NULL;
|
||||
}
|
||||
if (!(conn->ifc_flags & IFC_SERVER))
|
||||
if (conn->ifc_u.cli.crypto_streams[ENC_LEV_CLEAR])
|
||||
{
|
||||
lsquic_stream_destroy(conn->ifc_u.cli.crypto_streams[ENC_LEV_CLEAR]);
|
||||
conn->ifc_u.cli.crypto_streams[ENC_LEV_CLEAR] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -5436,11 +5469,12 @@ ignore_hsk (struct ietf_full_conn *conn)
|
|||
lsquic_alarmset_unset(&conn->ifc_alset, AL_ACK_HSK);
|
||||
lsquic_send_ctl_empty_pns(&conn->ifc_send_ctl, PNS_HSK);
|
||||
lsquic_rechist_cleanup(&conn->ifc_rechist[PNS_HSK]);
|
||||
if (conn->ifc_crypto_streams[ENC_LEV_INIT])
|
||||
{
|
||||
lsquic_stream_destroy(conn->ifc_crypto_streams[ENC_LEV_INIT]);
|
||||
conn->ifc_crypto_streams[ENC_LEV_INIT] = NULL;
|
||||
}
|
||||
if (!(conn->ifc_flags & IFC_SERVER))
|
||||
if (conn->ifc_u.cli.crypto_streams[ENC_LEV_INIT])
|
||||
{
|
||||
lsquic_stream_destroy(conn->ifc_u.cli.crypto_streams[ENC_LEV_INIT]);
|
||||
conn->ifc_u.cli.crypto_streams[ENC_LEV_INIT] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -6385,6 +6419,14 @@ ietf_full_conn_ci_record_addrs (struct lsquic_conn *lconn, void *peer_ctx,
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
ietf_full_conn_ci_drop_crypto_streams (struct lsquic_conn *lconn)
|
||||
{
|
||||
struct ietf_full_conn *conn = (struct ietf_full_conn *) lconn;
|
||||
drop_crypto_streams(conn);
|
||||
}
|
||||
|
||||
|
||||
static const struct conn_iface ietf_full_conn_iface = {
|
||||
.ci_abort = ietf_full_conn_ci_abort,
|
||||
.ci_abort_error = ietf_full_conn_ci_abort_error,
|
||||
|
@ -6395,6 +6437,7 @@ static const struct conn_iface ietf_full_conn_iface = {
|
|||
.ci_close = ietf_full_conn_ci_close,
|
||||
.ci_destroy = ietf_full_conn_ci_destroy,
|
||||
.ci_drain_time = ietf_full_conn_ci_drain_time,
|
||||
.ci_drop_crypto_streams = ietf_full_conn_ci_drop_crypto_streams,
|
||||
.ci_get_ctx = ietf_full_conn_ci_get_ctx,
|
||||
.ci_get_engine = ietf_full_conn_ci_get_engine,
|
||||
.ci_get_log_cid = ietf_full_conn_ci_get_log_cid,
|
||||
|
@ -6763,10 +6806,7 @@ apply_uni_stream_class (struct ietf_full_conn *conn,
|
|||
maybe_schedule_ss_for_stream(conn, stream->id,
|
||||
HEC_REQUEST_CANCELLED);
|
||||
}
|
||||
if (stream->sm_hash_el.qhe_flags & QHE_HASHED)
|
||||
lsquic_hash_erase(conn->ifc_pub.all_streams, &stream->sm_hash_el);
|
||||
assert((stream->sm_qflags & SMQF_WANT_READ) == SMQF_WANT_READ);
|
||||
lsquic_stream_destroy(stream);
|
||||
lsquic_stream_close(stream);
|
||||
break;
|
||||
default:
|
||||
LSQ_DEBUG("unknown unidirectional stream %"PRIu64 " of type %"PRIu64
|
||||
|
@ -6779,10 +6819,7 @@ apply_uni_stream_class (struct ietf_full_conn *conn,
|
|||
*/
|
||||
maybe_schedule_ss_for_stream(conn, stream->id,
|
||||
HEC_STREAM_CREATION_ERROR);
|
||||
if (stream->sm_hash_el.qhe_flags & QHE_HASHED)
|
||||
lsquic_hash_erase(conn->ifc_pub.all_streams, &stream->sm_hash_el);
|
||||
assert((stream->sm_qflags & SMQF_WANT_READ) == SMQF_WANT_READ);
|
||||
lsquic_stream_destroy(stream);
|
||||
lsquic_stream_close(stream);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,7 +113,10 @@ static enum swtp_status
|
|||
stream_write_to_packet_crypto (struct frame_gen_ctx *fg_ctx, const size_t size);
|
||||
|
||||
static size_t
|
||||
stream_write_avail (struct lsquic_stream *);
|
||||
stream_write_avail_no_frames (struct lsquic_stream *);
|
||||
|
||||
static size_t
|
||||
stream_write_avail_with_frames (struct lsquic_stream *);
|
||||
|
||||
static size_t
|
||||
stream_write_avail_with_headers (struct lsquic_stream *);
|
||||
|
@ -151,6 +154,9 @@ on_write_pp_wrapper (struct lsquic_stream *, lsquic_stream_ctx_t *);
|
|||
static void
|
||||
stream_hq_frame_put (struct lsquic_stream *, struct stream_hq_frame *);
|
||||
|
||||
static size_t
|
||||
stream_hq_frame_size (const struct stream_hq_frame *);
|
||||
|
||||
const struct stream_filter_if hq_stream_filter_if =
|
||||
{
|
||||
.sfi_readable = hq_filter_readable,
|
||||
|
@ -352,7 +358,7 @@ stream_new_common (lsquic_stream_id_t id, struct lsquic_conn_public *conn_pub,
|
|||
stream->stream_if = stream_if;
|
||||
stream->conn_pub = conn_pub;
|
||||
stream->sm_onnew_arg = stream_if_ctx;
|
||||
stream->sm_write_avail = stream_write_avail;
|
||||
stream->sm_write_avail = stream_write_avail_no_frames;
|
||||
|
||||
STAILQ_INIT(&stream->sm_hq_frames);
|
||||
|
||||
|
@ -606,20 +612,26 @@ stream_is_finished (const lsquic_stream_t *stream)
|
|||
}
|
||||
|
||||
|
||||
/* This is an internal function */
|
||||
void
|
||||
lsquic_stream_force_finish (struct lsquic_stream *stream)
|
||||
{
|
||||
LSQ_DEBUG("stream is now finished");
|
||||
SM_HISTORY_APPEND(stream, SHE_FINISHED);
|
||||
if (0 == (stream->sm_qflags & SMQF_SERVICE_FLAGS))
|
||||
TAILQ_INSERT_TAIL(&stream->conn_pub->service_streams, stream,
|
||||
next_service_stream);
|
||||
stream->sm_qflags |= SMQF_FREE_STREAM;
|
||||
stream->stream_flags |= STREAM_FINISHED;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
maybe_finish_stream (lsquic_stream_t *stream)
|
||||
{
|
||||
if (0 == (stream->stream_flags & STREAM_FINISHED) &&
|
||||
stream_is_finished(stream))
|
||||
{
|
||||
LSQ_DEBUG("stream is now finished");
|
||||
SM_HISTORY_APPEND(stream, SHE_FINISHED);
|
||||
if (0 == (stream->sm_qflags & SMQF_SERVICE_FLAGS))
|
||||
TAILQ_INSERT_TAIL(&stream->conn_pub->service_streams, stream,
|
||||
next_service_stream);
|
||||
stream->sm_qflags |= SMQF_FREE_STREAM;
|
||||
stream->stream_flags |= STREAM_FINISHED;
|
||||
}
|
||||
lsquic_stream_force_finish(stream);
|
||||
}
|
||||
|
||||
|
||||
|
@ -718,10 +730,9 @@ lsquic_stream_readable (struct lsquic_stream *stream)
|
|||
|
||||
|
||||
static size_t
|
||||
stream_write_avail (struct lsquic_stream *stream)
|
||||
stream_write_avail_no_frames (struct lsquic_stream *stream)
|
||||
{
|
||||
uint64_t stream_avail, conn_avail;
|
||||
size_t hq_frames_sz;
|
||||
|
||||
stream_avail = stream->max_send_off - stream->tosend_off
|
||||
- stream->sm_n_buffered;
|
||||
|
@ -733,20 +744,47 @@ stream_write_avail (struct lsquic_stream *stream)
|
|||
stream_avail = conn_avail;
|
||||
}
|
||||
|
||||
if ((stream->sm_bflags & (SMBF_IETF|SMBF_USE_HEADERS))
|
||||
== (SMBF_IETF|SMBF_USE_HEADERS))
|
||||
{
|
||||
hq_frames_sz = active_hq_frame_sizes(stream);
|
||||
if (hq_frames_sz == 0)
|
||||
hq_frames_sz = 3; /* Smallest new frame */
|
||||
return stream_avail;
|
||||
}
|
||||
|
||||
if (stream_avail > hq_frames_sz)
|
||||
stream_avail -= hq_frames_sz;
|
||||
else
|
||||
stream_avail = 0;
|
||||
|
||||
static size_t
|
||||
stream_write_avail_with_frames (struct lsquic_stream *stream)
|
||||
{
|
||||
uint64_t stream_avail, conn_avail;
|
||||
const struct stream_hq_frame *shf;
|
||||
size_t size;
|
||||
|
||||
stream_avail = stream->max_send_off - stream->tosend_off
|
||||
- stream->sm_n_buffered;
|
||||
STAILQ_FOREACH(shf, &stream->sm_hq_frames, shf_next)
|
||||
if (!(shf->shf_flags & SHF_WRITTEN))
|
||||
{
|
||||
size = stream_hq_frame_size(shf);
|
||||
assert(size <= stream_avail);
|
||||
stream_avail -= size;
|
||||
}
|
||||
|
||||
if (stream->sm_bflags & SMBF_CONN_LIMITED)
|
||||
{
|
||||
conn_avail = lsquic_conn_cap_avail(&stream->conn_pub->conn_cap);
|
||||
STAILQ_FOREACH(shf, &stream->sm_hq_frames, shf_next)
|
||||
if (!(shf->shf_flags & SHF_CC_PAID))
|
||||
{
|
||||
size = stream_hq_frame_size(shf);
|
||||
if (size < conn_avail)
|
||||
conn_avail -= size;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
if (conn_avail < stream_avail)
|
||||
stream_avail = conn_avail;
|
||||
}
|
||||
|
||||
return stream_avail;
|
||||
if (stream_avail >= 3 /* Smallest new frame */)
|
||||
return stream_avail;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -772,7 +810,7 @@ static size_t
|
|||
stream_write_avail_with_headers (struct lsquic_stream *stream)
|
||||
{
|
||||
if (stream->stream_flags & STREAM_PUSHING)
|
||||
return stream_write_avail(stream);
|
||||
return stream_write_avail_with_frames(stream);
|
||||
|
||||
switch (stream->sm_send_headers_state)
|
||||
{
|
||||
|
@ -787,7 +825,7 @@ stream_write_avail_with_headers (struct lsquic_stream *stream)
|
|||
/* fall-through */
|
||||
default:
|
||||
assert(SSHS_HBLOCK_SENDING == stream->sm_send_headers_state);
|
||||
return stream_write_avail(stream);
|
||||
return stream_write_avail_with_frames(stream);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1432,6 +1470,24 @@ stream_shutdown_read (lsquic_stream_t *stream)
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
stream_is_incoming_unidir (const struct lsquic_stream *stream)
|
||||
{
|
||||
enum stream_id_type sit;
|
||||
|
||||
if (stream->sm_bflags & SMBF_IETF)
|
||||
{
|
||||
sit = stream->id & SIT_MASK;
|
||||
if (stream->sm_bflags & SMBF_SERVER)
|
||||
return sit == SIT_UNI_CLIENT;
|
||||
else
|
||||
return sit == SIT_UNI_SERVER;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
stream_shutdown_write (lsquic_stream_t *stream)
|
||||
{
|
||||
|
@ -1447,6 +1503,7 @@ stream_shutdown_write (lsquic_stream_t *stream)
|
|||
*/
|
||||
if (!(stream->sm_bflags & SMBF_CRYPTO)
|
||||
&& !(stream->stream_flags & (STREAM_FIN_SENT|STREAM_RST_SENT))
|
||||
&& !stream_is_incoming_unidir(stream)
|
||||
&& !(stream->sm_qflags & SMQF_SEND_RST))
|
||||
{
|
||||
if (stream->sm_n_buffered == 0)
|
||||
|
@ -1544,7 +1601,7 @@ fake_reset_unused_stream (lsquic_stream_t *stream)
|
|||
TAILQ_REMOVE(&stream->conn_pub->sending_streams, stream,
|
||||
next_send_stream);
|
||||
stream->sm_qflags &= ~SMQF_SENDING_FLAGS;
|
||||
|
||||
drop_buffered_data(stream);
|
||||
LSQ_DEBUG("fake-reset stream%s",
|
||||
stream_stalled(stream) ? " (stalled)" : "");
|
||||
maybe_finish_stream(stream);
|
||||
|
@ -1771,7 +1828,7 @@ stream_hblock_sent (struct lsquic_stream *stream)
|
|||
|
||||
LSQ_DEBUG("header block has been sent: restore default behavior");
|
||||
stream->sm_send_headers_state = SSHS_BEGIN;
|
||||
stream->sm_write_avail = stream_write_avail;
|
||||
stream->sm_write_avail = stream_write_avail_with_frames;
|
||||
|
||||
want_write = !!(stream->sm_qflags & SMQF_WANT_WRITE);
|
||||
if (want_write != stream->sm_saved_want_write)
|
||||
|
@ -2944,7 +3001,7 @@ update_buffered_hq_frames (struct lsquic_stream *stream, size_t len,
|
|||
struct stream_hq_frame *shf;
|
||||
uint64_t cur_off, end;
|
||||
size_t frame_sz;
|
||||
int extendable;
|
||||
unsigned extendable;
|
||||
|
||||
cur_off = stream->sm_payload + stream->sm_n_buffered;
|
||||
STAILQ_FOREACH(shf, &stream->sm_hq_frames, shf_next)
|
||||
|
@ -2958,12 +3015,13 @@ update_buffered_hq_frames (struct lsquic_stream *stream, size_t len,
|
|||
|
||||
if (shf)
|
||||
{
|
||||
if (len > end - cur_off)
|
||||
len = end - cur_off;
|
||||
if (len > end + extendable - cur_off)
|
||||
len = end + extendable - cur_off;
|
||||
frame_sz = stream_hq_frame_size(shf);
|
||||
}
|
||||
else if (avail >= 3)
|
||||
else
|
||||
{
|
||||
assert(avail >= 3);
|
||||
shf = stream_activate_hq_frame(stream, cur_off, HQFT_DATA, 0, len);
|
||||
/* XXX malloc can fail */
|
||||
if (len > stream_hq_frame_end(shf) - cur_off)
|
||||
|
@ -2974,8 +3032,6 @@ update_buffered_hq_frames (struct lsquic_stream *stream, size_t len,
|
|||
return 0;
|
||||
avail -= frame_sz;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (!(shf->shf_flags & SHF_CC_PAID))
|
||||
{
|
||||
|
@ -3006,6 +3062,15 @@ save_to_buffer (lsquic_stream_t *stream, struct lsquic_reader *reader,
|
|||
{
|
||||
size_t avail, n_written, n_allowed;
|
||||
|
||||
avail = lsquic_stream_write_avail(stream);
|
||||
if (avail < len)
|
||||
len = avail;
|
||||
if (len == 0)
|
||||
{
|
||||
LSQ_DEBUG("zero-byte write (avail: %zu)", avail);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n_allowed = stream_get_n_allowed(stream);
|
||||
assert(stream->sm_n_buffered + len <= n_allowed);
|
||||
|
||||
|
@ -3017,10 +3082,6 @@ save_to_buffer (lsquic_stream_t *stream, struct lsquic_reader *reader,
|
|||
stream->sm_n_allocated = n_allowed;
|
||||
}
|
||||
|
||||
avail = lsquic_stream_write_avail(stream);
|
||||
if (avail < len)
|
||||
len = avail;
|
||||
|
||||
if ((stream->sm_bflags & (SMBF_IETF|SMBF_USE_HEADERS))
|
||||
== (SMBF_IETF|SMBF_USE_HEADERS))
|
||||
len = update_buffered_hq_frames(stream, len, avail);
|
||||
|
|
|
@ -584,4 +584,7 @@ lsquic_stream_duplicate_push (struct lsquic_stream *, uint64_t push_id);
|
|||
int
|
||||
lsquic_stream_push_promise (struct lsquic_stream *, struct push_promise *);
|
||||
|
||||
void
|
||||
lsquic_stream_force_finish (struct lsquic_stream *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -393,19 +393,31 @@ packetization_write_as_much_as_you_can (lsquic_stream_t *stream,
|
|||
lsquic_stream_ctx_t *ctx)
|
||||
{
|
||||
struct packetization_test_stream_ctx *const pack_ctx = (void *) ctx;
|
||||
unsigned n_to_write;
|
||||
unsigned n_to_write, n_sched;
|
||||
ssize_t n_written;
|
||||
size_t avail;
|
||||
int s;
|
||||
|
||||
while (pack_ctx->off < pack_ctx->len)
|
||||
{
|
||||
n_to_write = calc_n_to_write(pack_ctx->write_size);
|
||||
n_sched = lsquic_send_ctl_n_scheduled(stream->conn_pub->send_ctl);
|
||||
if (n_to_write > pack_ctx->len - pack_ctx->off)
|
||||
n_to_write = pack_ctx->len - pack_ctx->off;
|
||||
n_written = lsquic_stream_write(stream, pack_ctx->buf + pack_ctx->off,
|
||||
n_to_write);
|
||||
if (n_written == 0)
|
||||
{
|
||||
if (n_to_write && SSHS_BEGIN == stream->sm_send_headers_state
|
||||
&& lsquic_send_ctl_can_send(stream->conn_pub->send_ctl))
|
||||
{
|
||||
avail = lsquic_stream_write_avail(stream);
|
||||
assert(avail == 0
|
||||
|| lsquic_send_ctl_n_scheduled(
|
||||
stream->conn_pub->send_ctl) > n_sched);
|
||||
}
|
||||
break;
|
||||
}
|
||||
pack_ctx->off += n_written;
|
||||
if (pack_ctx->flush_after_each_write)
|
||||
{
|
||||
|
@ -425,16 +437,27 @@ packetization_perform_one_write (lsquic_stream_t *stream,
|
|||
lsquic_stream_ctx_t *ctx)
|
||||
{
|
||||
struct packetization_test_stream_ctx *const pack_ctx = (void *) ctx;
|
||||
unsigned n_to_write;
|
||||
unsigned n_to_write, n_sched;
|
||||
ssize_t n_written;
|
||||
size_t avail;
|
||||
int s;
|
||||
|
||||
n_to_write = calc_n_to_write(pack_ctx->write_size);
|
||||
if (n_to_write > pack_ctx->len - pack_ctx->off)
|
||||
n_to_write = pack_ctx->len - pack_ctx->off;
|
||||
n_sched = lsquic_send_ctl_n_scheduled(stream->conn_pub->send_ctl);
|
||||
n_written = lsquic_stream_write(stream, pack_ctx->buf + pack_ctx->off,
|
||||
n_to_write);
|
||||
assert(n_written >= 0);
|
||||
if (n_written == 0 && SSHS_BEGIN == stream->sm_send_headers_state
|
||||
&& n_to_write
|
||||
&& lsquic_send_ctl_can_send(stream->conn_pub->send_ctl))
|
||||
{
|
||||
avail = lsquic_stream_write_avail(stream);
|
||||
assert(avail == 0
|
||||
|| lsquic_send_ctl_n_scheduled(
|
||||
stream->conn_pub->send_ctl) > n_sched);
|
||||
}
|
||||
pack_ctx->off += n_written;
|
||||
if (pack_ctx->flush_after_each_write)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue