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
|
2019-09-18
|
||||||
- 2.4.0
|
- 2.4.0
|
||||||
- [FEATURE] QUIC and HTTP/3 Internet Draft 23 support
|
- [FEATURE] QUIC and HTTP/3 Internet Draft 23 support
|
||||||
|
|
|
@ -25,7 +25,7 @@ extern "C" {
|
||||||
|
|
||||||
#define LSQUIC_MAJOR_VERSION 2
|
#define LSQUIC_MAJOR_VERSION 2
|
||||||
#define LSQUIC_MINOR_VERSION 4
|
#define LSQUIC_MINOR_VERSION 4
|
||||||
#define LSQUIC_PATCH_VERSION 0
|
#define LSQUIC_PATCH_VERSION 2
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Engine flags:
|
* Engine flags:
|
||||||
|
|
|
@ -47,6 +47,7 @@ static const char *const lsquic_alid2str[] =
|
||||||
[AL_CID_THROT] = "CID_THROT",
|
[AL_CID_THROT] = "CID_THROT",
|
||||||
[AL_PATH_CHAL_0] = "PATH_CHAL_0",
|
[AL_PATH_CHAL_0] = "PATH_CHAL_0",
|
||||||
[AL_PATH_CHAL_1] = "PATH_CHAL_1",
|
[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,
|
||||||
AL_PATH_CHAL_0 = AL_PATH_CHAL,
|
AL_PATH_CHAL_0 = AL_PATH_CHAL,
|
||||||
AL_PATH_CHAL_1,
|
AL_PATH_CHAL_1,
|
||||||
|
AL_SESS_TICKET,
|
||||||
MAX_LSQUIC_ALARMS
|
MAX_LSQUIC_ALARMS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -54,6 +55,7 @@ enum alarm_id_bit {
|
||||||
ALBIT_PATH_CHAL = 1 << AL_PATH_CHAL,
|
ALBIT_PATH_CHAL = 1 << AL_PATH_CHAL,
|
||||||
ALBIT_PATH_CHAL_0 = 1 << AL_PATH_CHAL_0,
|
ALBIT_PATH_CHAL_0 = 1 << AL_PATH_CHAL_0,
|
||||||
ALBIT_PATH_CHAL_1 = 1 << AL_PATH_CHAL_1,
|
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 *
|
const lsquic_cid_t *
|
||||||
(*ci_get_log_cid) (const struct lsquic_conn *);
|
(*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
|
#define LSCONN_CCE_BITS 3
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#ifndef LSQUIC_ENC_SESS_H
|
#ifndef LSQUIC_ENC_SESS_H
|
||||||
#define LSQUIC_ENC_SESS_H 1
|
#define LSQUIC_ENC_SESS_H 1
|
||||||
|
|
||||||
|
struct lsquic_alarmset;
|
||||||
struct lsquic_engine_public;
|
struct lsquic_engine_public;
|
||||||
struct lsquic_packet_out;
|
struct lsquic_packet_out;
|
||||||
struct lsquic_packet_in;
|
struct lsquic_packet_in;
|
||||||
|
@ -262,7 +263,8 @@ struct enc_session_funcs_iquic
|
||||||
struct lsquic_conn *, const struct lsquic_cid *,
|
struct lsquic_conn *, const struct lsquic_cid *,
|
||||||
const struct ver_neg *, void *(crypto_streams)[4],
|
const struct ver_neg *, void *(crypto_streams)[4],
|
||||||
const struct crypto_stream_if *,
|
const struct crypto_stream_if *,
|
||||||
const unsigned char *, size_t);
|
const unsigned char *, size_t,
|
||||||
|
struct lsquic_alarmset *);
|
||||||
|
|
||||||
void
|
void
|
||||||
(*esfi_destroy) (enc_session_t *);
|
(*esfi_destroy) (enc_session_t *);
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "lsquic_frab_list.h"
|
#include "lsquic_frab_list.h"
|
||||||
#include "lsquic_tokgen.h"
|
#include "lsquic_tokgen.h"
|
||||||
#include "lsquic_ietf.h"
|
#include "lsquic_ietf.h"
|
||||||
|
#include "lsquic_alarmset.h"
|
||||||
|
|
||||||
#if __GNUC__
|
#if __GNUC__
|
||||||
# define UNLIKELY(cond) __builtin_expect(cond, 0)
|
# define UNLIKELY(cond) __builtin_expect(cond, 0)
|
||||||
|
@ -106,6 +107,10 @@ iquic_esf_get_server_cert_chain (enc_session_t *);
|
||||||
static void
|
static void
|
||||||
maybe_drop_SSL (struct enc_sess_iquic *);
|
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 *,
|
typedef void (*gen_hp_mask_f)(struct enc_sess_iquic *,
|
||||||
const struct header_prot *, unsigned cliser,
|
const struct header_prot *, unsigned cliser,
|
||||||
|
@ -236,6 +241,7 @@ struct enc_sess_iquic
|
||||||
ESI_ALPN_CHECKED = 1 << 8,
|
ESI_ALPN_CHECKED = 1 << 8,
|
||||||
ESI_CACHED_INFO = 1 << 9,
|
ESI_CACHED_INFO = 1 << 9,
|
||||||
ESI_1RTT_ACKED = 1 << 10,
|
ESI_1RTT_ACKED = 1 << 10,
|
||||||
|
ESI_WANT_TICKET = 1 << 11,
|
||||||
} esi_flags;
|
} esi_flags;
|
||||||
enum evp_aead_direction_t
|
enum evp_aead_direction_t
|
||||||
esi_dir[2]; /* client, server */
|
esi_dir[2]; /* client, server */
|
||||||
|
@ -264,6 +270,8 @@ struct enc_sess_iquic
|
||||||
struct frab_list esi_frals[N_ENC_LEVS];
|
struct frab_list esi_frals[N_ENC_LEVS];
|
||||||
struct transport_params
|
struct transport_params
|
||||||
esi_peer_tp;
|
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,
|
struct lsquic_engine_public *enpub, struct lsquic_conn *lconn,
|
||||||
const lsquic_cid_t *dcid, const struct ver_neg *ver_neg,
|
const lsquic_cid_t *dcid, const struct ver_neg *ver_neg,
|
||||||
void *crypto_streams[4], const struct crypto_stream_if *cryst_if,
|
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;
|
struct enc_sess_iquic *enc_sess;
|
||||||
|
|
||||||
|
@ -720,6 +729,12 @@ iquic_esfi_create_client (const char *hostname,
|
||||||
enc_sess->esi_zero_rtt_sz = 0;
|
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;
|
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,
|
enc_sess->esi_enpub->enp_stream_if->on_zero_rtt_info(enc_sess->esi_conn,
|
||||||
buf, buf_sz);
|
buf, buf_sz);
|
||||||
free(buf);
|
free(buf);
|
||||||
|
enc_sess->esi_flags &= ~ESI_WANT_TICKET;
|
||||||
|
lsquic_alarmset_unset(enc_sess->esi_alset, AL_SESS_TICKET);
|
||||||
return 0;
|
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
|
static void
|
||||||
maybe_drop_SSL (struct enc_sess_iquic *enc_sess)
|
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
|
&& enc_sess->esi_ssl
|
||||||
&& lsquic_frab_list_empty(&enc_sess->esi_frals[ENC_LEV_FORW]))
|
&& lsquic_frab_list_empty(&enc_sess->esi_frals[ENC_LEV_FORW]))
|
||||||
{
|
{
|
||||||
LSQ_DEBUG("drop SSL object");
|
if ((enc_sess->esi_flags & (ESI_SERVER|ESI_WANT_TICKET))
|
||||||
cache_info(enc_sess);
|
!= ESI_WANT_TICKET)
|
||||||
SSL_free(enc_sess->esi_ssl);
|
drop_SSL(enc_sess);
|
||||||
enc_sess->esi_ssl = NULL;
|
else if (enc_sess->esi_alset
|
||||||
free_handshake_keys(enc_sess);
|
&& !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[
|
typedef char enums_have_the_same_value[
|
||||||
(int) ssl_encryption_initial == (int) ENC_LEV_CLEAR &&
|
(int) ssl_encryption_initial == (int) ENC_LEV_CLEAR &&
|
||||||
(int) ssl_encryption_early_data == (int) ENC_LEV_EARLY &&
|
(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
|
static void
|
||||||
chsk_ietf_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
|
chsk_ietf_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
struct enc_sess_iquic *const enc_sess = (void *) ctx;
|
struct enc_sess_iquic *const enc_sess = (void *) ctx;
|
||||||
enum enc_level enc_level = enc_sess->esi_cryst_if->csi_enc_level(stream);
|
enum enc_level enc_level = enc_sess->esi_cryst_if->csi_enc_level(stream);
|
||||||
struct readf_ctx readf_ctx = { enc_sess, enc_level, 0, };
|
struct readf_ctx readf_ctx = { enc_sess, enc_level, 0, };
|
||||||
|
ssize_t nread;
|
||||||
|
|
||||||
|
|
||||||
ssize_t nread = enc_sess->esi_cryst_if->csi_readf(stream,
|
if (enc_sess->esi_ssl)
|
||||||
readf_cb, &readf_ctx);
|
{
|
||||||
|
nread = enc_sess->esi_cryst_if->csi_readf(stream, readf_cb, &readf_ctx);
|
||||||
if (!(nread < 0 || readf_ctx.err))
|
if (!(nread < 0 || readf_ctx.err))
|
||||||
iquic_esfi_shake_stream((enc_session_t *)enc_sess, stream, "on_read");
|
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
|
else
|
||||||
enc_sess->esi_conn->cn_if->ci_internal_error(enc_sess->esi_conn,
|
{
|
||||||
"shaking stream failed: nread: %zd, err: %d, SSL err: %"PRIu32,
|
/* This branch is reached when we don't want TLS ticket and drop
|
||||||
nread, readf_ctx.err, ERR_get_error());
|
* 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_GOAWAY_CLOSE = 1 << 23,
|
||||||
IFC_FIRST_TICK = 1 << 24,
|
IFC_FIRST_TICK = 1 << 24,
|
||||||
IFC_IGNORE_HSK = 1 << 25,
|
IFC_IGNORE_HSK = 1 << 25,
|
||||||
|
IFC_PROC_CRYPTO = 1 << 26,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -359,9 +360,9 @@ struct ietf_full_conn
|
||||||
unsigned ifc_last_retire_prior_to;
|
unsigned ifc_last_retire_prior_to;
|
||||||
lsquic_time_t ifc_last_live_update;
|
lsquic_time_t ifc_last_live_update;
|
||||||
struct conn_path ifc_paths[N_PATHS];
|
struct conn_path ifc_paths[N_PATHS];
|
||||||
struct lsquic_stream *ifc_crypto_streams[N_ENC_LEVS];
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
|
struct lsquic_stream *crypto_streams[N_ENC_LEVS];
|
||||||
struct ver_neg
|
struct ver_neg
|
||||||
ifcli_ver_neg;
|
ifcli_ver_neg;
|
||||||
uint64_t ifcli_max_push_id;
|
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_conn.cn_esf.i->esfi_create_client(hostname,
|
||||||
conn->ifc_enpub, &conn->ifc_conn, CUR_DCID(conn),
|
conn->ifc_enpub, &conn->ifc_conn, CUR_DCID(conn),
|
||||||
&conn->ifc_u.cli.ifcli_ver_neg,
|
&conn->ifc_u.cli.ifcli_ver_neg,
|
||||||
(void **) conn->ifc_crypto_streams, &crypto_stream_if,
|
(void **) conn->ifc_u.cli.crypto_streams, &crypto_stream_if,
|
||||||
zero_rtt, zero_rtt_sz);
|
zero_rtt, zero_rtt_sz, &conn->ifc_alset);
|
||||||
if (!conn->ifc_conn.cn_enc_session)
|
if (!conn->ifc_conn.cn_enc_session)
|
||||||
{
|
{
|
||||||
/* TODO: free other stuff */
|
/* TODO: free other stuff */
|
||||||
|
@ -1044,17 +1045,17 @@ lsquic_ietf_full_conn_client_new (struct lsquic_engine_public *enpub,
|
||||||
return NULL;
|
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,
|
ENC_LEV_CLEAR, &conn->ifc_pub, &lsquic_cry_sm_if,
|
||||||
conn->ifc_conn.cn_enc_session,
|
conn->ifc_conn.cn_enc_session,
|
||||||
SCF_IETF|SCF_DI_AUTOSWITCH|SCF_CALL_ON_NEW|SCF_CRITICAL);
|
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 */
|
/* TODO: free other stuff */
|
||||||
free(conn);
|
free(conn);
|
||||||
return NULL;
|
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 */
|
/* TODO: free other stuff */
|
||||||
free(conn);
|
free(conn);
|
||||||
|
@ -1065,9 +1066,10 @@ lsquic_ietf_full_conn_client_new (struct lsquic_engine_public *enpub,
|
||||||
if (!conn->ifc_pub.packet_out_malo)
|
if (!conn->ifc_pub.packet_out_malo)
|
||||||
{
|
{
|
||||||
free(conn);
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
conn->ifc_flags |= IFC_PROC_CRYPTO;
|
||||||
|
|
||||||
LSQ_DEBUG("negotiating version %s",
|
LSQ_DEBUG("negotiating version %s",
|
||||||
lsquic_ver2str[conn->ifc_u.cli.ifcli_ver_neg.vn_ver]);
|
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
|
static void
|
||||||
ietf_full_conn_ci_destroy (struct lsquic_conn *lconn)
|
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;
|
struct lsquic_hash_elem *el;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
for (streamp = conn->ifc_crypto_streams; streamp <
|
if (!(conn->ifc_flags & IFC_SERVER))
|
||||||
conn->ifc_crypto_streams + sizeof(conn->ifc_crypto_streams)
|
{
|
||||||
/ sizeof(conn->ifc_crypto_streams[0]); ++streamp)
|
for (streamp = conn->ifc_u.cli.crypto_streams; streamp <
|
||||||
if (*streamp)
|
conn->ifc_u.cli.crypto_streams
|
||||||
lsquic_stream_destroy(*streamp);
|
+ 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)))
|
while ((el = lsquic_hash_first(conn->ifc_pub.all_streams)))
|
||||||
{
|
{
|
||||||
stream = lsquic_hashelem_getdata(el);
|
stream = lsquic_hashelem_getdata(el);
|
||||||
|
@ -3366,9 +3398,10 @@ process_crypto_stream_read_events (struct ietf_full_conn *conn)
|
||||||
{
|
{
|
||||||
struct lsquic_stream **stream;
|
struct lsquic_stream **stream;
|
||||||
|
|
||||||
for (stream = conn->ifc_crypto_streams; stream <
|
assert(!(conn->ifc_flags & IFC_SERVER));
|
||||||
conn->ifc_crypto_streams + sizeof(conn->ifc_crypto_streams)
|
for (stream = conn->ifc_u.cli.crypto_streams; stream <
|
||||||
/ sizeof(conn->ifc_crypto_streams[0]); ++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)
|
if (*stream && (*stream)->sm_qflags & SMQF_WANT_READ)
|
||||||
lsquic_stream_dispatch_read_events(*stream);
|
lsquic_stream_dispatch_read_events(*stream);
|
||||||
}
|
}
|
||||||
|
@ -3379,9 +3412,10 @@ process_crypto_stream_write_events (struct ietf_full_conn *conn)
|
||||||
{
|
{
|
||||||
struct lsquic_stream **stream;
|
struct lsquic_stream **stream;
|
||||||
|
|
||||||
for (stream = conn->ifc_crypto_streams; stream <
|
assert(!(conn->ifc_flags & IFC_SERVER));
|
||||||
conn->ifc_crypto_streams + sizeof(conn->ifc_crypto_streams)
|
for (stream = conn->ifc_u.cli.crypto_streams; stream <
|
||||||
/ sizeof(conn->ifc_crypto_streams[0]); ++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)
|
if (*stream && (*stream)->sm_qflags & SMQF_WRITE_Q_FLAGS)
|
||||||
lsquic_stream_dispatch_write_events(*stream);
|
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
|
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 lsquic_packet_in *packet_in, const unsigned char *p, size_t len)
|
||||||
{
|
{
|
||||||
struct stream_frame stream_frame;
|
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,
|
parsed_len = conn->ifc_conn.cn_pf->pf_parse_crypto_frame(p, len,
|
||||||
&stream_frame);
|
&stream_frame);
|
||||||
if (parsed_len > 0)
|
if (parsed_len > 0)
|
||||||
|
{
|
||||||
|
LSQ_DEBUG("discard %d-byte CRYPTO frame", parsed_len);
|
||||||
return (unsigned) parsed_len;
|
return (unsigned) parsed_len;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static unsigned
|
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 lsquic_packet_in *packet_in, const unsigned char *p, size_t len)
|
||||||
{
|
{
|
||||||
struct stream_frame *stream_frame;
|
struct stream_frame *stream_frame;
|
||||||
|
@ -4286,6 +4322,12 @@ process_crypto_frame_client (struct ietf_full_conn *conn,
|
||||||
enum enc_level enc_level;
|
enum enc_level enc_level;
|
||||||
int parsed_len;
|
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);
|
stream_frame = lsquic_malo_get(conn->ifc_pub.mm->malo.stream_frame);
|
||||||
if (!stream_frame)
|
if (!stream_frame)
|
||||||
{
|
{
|
||||||
|
@ -4317,8 +4359,9 @@ process_crypto_frame_client (struct ietf_full_conn *conn,
|
||||||
return parsed_len;
|
return parsed_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn->ifc_crypto_streams[enc_level])
|
assert(!(conn->ifc_flags & IFC_SERVER));
|
||||||
stream = conn->ifc_crypto_streams[enc_level];
|
if (conn->ifc_u.cli.crypto_streams[enc_level])
|
||||||
|
stream = conn->ifc_u.cli.crypto_streams[enc_level];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = lsquic_stream_new_crypto(enc_level, &conn->ifc_pub,
|
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);
|
ABORT_WARN("cannot create crypto stream for level %u", enc_level);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
conn->ifc_crypto_streams[enc_level] = stream;
|
conn->ifc_u.cli.crypto_streams[enc_level] = stream;
|
||||||
(void) lsquic_stream_wantread(stream, 1);
|
(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
|
static unsigned
|
||||||
process_stream_frame (struct ietf_full_conn *conn,
|
process_stream_frame (struct ietf_full_conn *conn,
|
||||||
struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len)
|
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_alarmset_unset(&conn->ifc_alset, AL_ACK_INIT + PNS_INIT);
|
||||||
lsquic_send_ctl_empty_pns(&conn->ifc_send_ctl, PNS_INIT);
|
lsquic_send_ctl_empty_pns(&conn->ifc_send_ctl, PNS_INIT);
|
||||||
lsquic_rechist_cleanup(&conn->ifc_rechist[PNS_INIT]);
|
lsquic_rechist_cleanup(&conn->ifc_rechist[PNS_INIT]);
|
||||||
if (conn->ifc_crypto_streams[ENC_LEV_CLEAR])
|
if (!(conn->ifc_flags & IFC_SERVER))
|
||||||
{
|
if (conn->ifc_u.cli.crypto_streams[ENC_LEV_CLEAR])
|
||||||
lsquic_stream_destroy(conn->ifc_crypto_streams[ENC_LEV_CLEAR]);
|
{
|
||||||
conn->ifc_crypto_streams[ENC_LEV_CLEAR] = NULL;
|
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_alarmset_unset(&conn->ifc_alset, AL_ACK_HSK);
|
||||||
lsquic_send_ctl_empty_pns(&conn->ifc_send_ctl, PNS_HSK);
|
lsquic_send_ctl_empty_pns(&conn->ifc_send_ctl, PNS_HSK);
|
||||||
lsquic_rechist_cleanup(&conn->ifc_rechist[PNS_HSK]);
|
lsquic_rechist_cleanup(&conn->ifc_rechist[PNS_HSK]);
|
||||||
if (conn->ifc_crypto_streams[ENC_LEV_INIT])
|
if (!(conn->ifc_flags & IFC_SERVER))
|
||||||
{
|
if (conn->ifc_u.cli.crypto_streams[ENC_LEV_INIT])
|
||||||
lsquic_stream_destroy(conn->ifc_crypto_streams[ENC_LEV_INIT]);
|
{
|
||||||
conn->ifc_crypto_streams[ENC_LEV_INIT] = NULL;
|
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 = {
|
static const struct conn_iface ietf_full_conn_iface = {
|
||||||
.ci_abort = ietf_full_conn_ci_abort,
|
.ci_abort = ietf_full_conn_ci_abort,
|
||||||
.ci_abort_error = ietf_full_conn_ci_abort_error,
|
.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_close = ietf_full_conn_ci_close,
|
||||||
.ci_destroy = ietf_full_conn_ci_destroy,
|
.ci_destroy = ietf_full_conn_ci_destroy,
|
||||||
.ci_drain_time = ietf_full_conn_ci_drain_time,
|
.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_ctx = ietf_full_conn_ci_get_ctx,
|
||||||
.ci_get_engine = ietf_full_conn_ci_get_engine,
|
.ci_get_engine = ietf_full_conn_ci_get_engine,
|
||||||
.ci_get_log_cid = ietf_full_conn_ci_get_log_cid,
|
.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,
|
maybe_schedule_ss_for_stream(conn, stream->id,
|
||||||
HEC_REQUEST_CANCELLED);
|
HEC_REQUEST_CANCELLED);
|
||||||
}
|
}
|
||||||
if (stream->sm_hash_el.qhe_flags & QHE_HASHED)
|
lsquic_stream_close(stream);
|
||||||
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);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LSQ_DEBUG("unknown unidirectional stream %"PRIu64 " of type %"PRIu64
|
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,
|
maybe_schedule_ss_for_stream(conn, stream->id,
|
||||||
HEC_STREAM_CREATION_ERROR);
|
HEC_STREAM_CREATION_ERROR);
|
||||||
if (stream->sm_hash_el.qhe_flags & QHE_HASHED)
|
lsquic_stream_close(stream);
|
||||||
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);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,10 @@ static enum swtp_status
|
||||||
stream_write_to_packet_crypto (struct frame_gen_ctx *fg_ctx, const size_t size);
|
stream_write_to_packet_crypto (struct frame_gen_ctx *fg_ctx, const size_t size);
|
||||||
|
|
||||||
static size_t
|
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
|
static size_t
|
||||||
stream_write_avail_with_headers (struct lsquic_stream *);
|
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
|
static void
|
||||||
stream_hq_frame_put (struct lsquic_stream *, struct stream_hq_frame *);
|
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 =
|
const struct stream_filter_if hq_stream_filter_if =
|
||||||
{
|
{
|
||||||
.sfi_readable = hq_filter_readable,
|
.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->stream_if = stream_if;
|
||||||
stream->conn_pub = conn_pub;
|
stream->conn_pub = conn_pub;
|
||||||
stream->sm_onnew_arg = stream_if_ctx;
|
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);
|
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
|
static void
|
||||||
maybe_finish_stream (lsquic_stream_t *stream)
|
maybe_finish_stream (lsquic_stream_t *stream)
|
||||||
{
|
{
|
||||||
if (0 == (stream->stream_flags & STREAM_FINISHED) &&
|
if (0 == (stream->stream_flags & STREAM_FINISHED) &&
|
||||||
stream_is_finished(stream))
|
stream_is_finished(stream))
|
||||||
{
|
lsquic_stream_force_finish(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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -718,10 +730,9 @@ lsquic_stream_readable (struct lsquic_stream *stream)
|
||||||
|
|
||||||
|
|
||||||
static size_t
|
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;
|
uint64_t stream_avail, conn_avail;
|
||||||
size_t hq_frames_sz;
|
|
||||||
|
|
||||||
stream_avail = stream->max_send_off - stream->tosend_off
|
stream_avail = stream->max_send_off - stream->tosend_off
|
||||||
- stream->sm_n_buffered;
|
- stream->sm_n_buffered;
|
||||||
|
@ -733,20 +744,47 @@ stream_write_avail (struct lsquic_stream *stream)
|
||||||
stream_avail = conn_avail;
|
stream_avail = conn_avail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((stream->sm_bflags & (SMBF_IETF|SMBF_USE_HEADERS))
|
return stream_avail;
|
||||||
== (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 */
|
|
||||||
|
|
||||||
if (stream_avail > hq_frames_sz)
|
|
||||||
stream_avail -= hq_frames_sz;
|
static size_t
|
||||||
else
|
stream_write_avail_with_frames (struct lsquic_stream *stream)
|
||||||
stream_avail = 0;
|
{
|
||||||
|
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)
|
stream_write_avail_with_headers (struct lsquic_stream *stream)
|
||||||
{
|
{
|
||||||
if (stream->stream_flags & STREAM_PUSHING)
|
if (stream->stream_flags & STREAM_PUSHING)
|
||||||
return stream_write_avail(stream);
|
return stream_write_avail_with_frames(stream);
|
||||||
|
|
||||||
switch (stream->sm_send_headers_state)
|
switch (stream->sm_send_headers_state)
|
||||||
{
|
{
|
||||||
|
@ -787,7 +825,7 @@ stream_write_avail_with_headers (struct lsquic_stream *stream)
|
||||||
/* fall-through */
|
/* fall-through */
|
||||||
default:
|
default:
|
||||||
assert(SSHS_HBLOCK_SENDING == stream->sm_send_headers_state);
|
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
|
static void
|
||||||
stream_shutdown_write (lsquic_stream_t *stream)
|
stream_shutdown_write (lsquic_stream_t *stream)
|
||||||
{
|
{
|
||||||
|
@ -1447,6 +1503,7 @@ stream_shutdown_write (lsquic_stream_t *stream)
|
||||||
*/
|
*/
|
||||||
if (!(stream->sm_bflags & SMBF_CRYPTO)
|
if (!(stream->sm_bflags & SMBF_CRYPTO)
|
||||||
&& !(stream->stream_flags & (STREAM_FIN_SENT|STREAM_RST_SENT))
|
&& !(stream->stream_flags & (STREAM_FIN_SENT|STREAM_RST_SENT))
|
||||||
|
&& !stream_is_incoming_unidir(stream)
|
||||||
&& !(stream->sm_qflags & SMQF_SEND_RST))
|
&& !(stream->sm_qflags & SMQF_SEND_RST))
|
||||||
{
|
{
|
||||||
if (stream->sm_n_buffered == 0)
|
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,
|
TAILQ_REMOVE(&stream->conn_pub->sending_streams, stream,
|
||||||
next_send_stream);
|
next_send_stream);
|
||||||
stream->sm_qflags &= ~SMQF_SENDING_FLAGS;
|
stream->sm_qflags &= ~SMQF_SENDING_FLAGS;
|
||||||
|
drop_buffered_data(stream);
|
||||||
LSQ_DEBUG("fake-reset stream%s",
|
LSQ_DEBUG("fake-reset stream%s",
|
||||||
stream_stalled(stream) ? " (stalled)" : "");
|
stream_stalled(stream) ? " (stalled)" : "");
|
||||||
maybe_finish_stream(stream);
|
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");
|
LSQ_DEBUG("header block has been sent: restore default behavior");
|
||||||
stream->sm_send_headers_state = SSHS_BEGIN;
|
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);
|
want_write = !!(stream->sm_qflags & SMQF_WANT_WRITE);
|
||||||
if (want_write != stream->sm_saved_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;
|
struct stream_hq_frame *shf;
|
||||||
uint64_t cur_off, end;
|
uint64_t cur_off, end;
|
||||||
size_t frame_sz;
|
size_t frame_sz;
|
||||||
int extendable;
|
unsigned extendable;
|
||||||
|
|
||||||
cur_off = stream->sm_payload + stream->sm_n_buffered;
|
cur_off = stream->sm_payload + stream->sm_n_buffered;
|
||||||
STAILQ_FOREACH(shf, &stream->sm_hq_frames, shf_next)
|
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 (shf)
|
||||||
{
|
{
|
||||||
if (len > end - cur_off)
|
if (len > end + extendable - cur_off)
|
||||||
len = end - cur_off;
|
len = end + extendable - cur_off;
|
||||||
frame_sz = stream_hq_frame_size(shf);
|
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);
|
shf = stream_activate_hq_frame(stream, cur_off, HQFT_DATA, 0, len);
|
||||||
/* XXX malloc can fail */
|
/* XXX malloc can fail */
|
||||||
if (len > stream_hq_frame_end(shf) - cur_off)
|
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;
|
return 0;
|
||||||
avail -= frame_sz;
|
avail -= frame_sz;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!(shf->shf_flags & SHF_CC_PAID))
|
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;
|
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);
|
n_allowed = stream_get_n_allowed(stream);
|
||||||
assert(stream->sm_n_buffered + len <= n_allowed);
|
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;
|
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))
|
if ((stream->sm_bflags & (SMBF_IETF|SMBF_USE_HEADERS))
|
||||||
== (SMBF_IETF|SMBF_USE_HEADERS))
|
== (SMBF_IETF|SMBF_USE_HEADERS))
|
||||||
len = update_buffered_hq_frames(stream, len, avail);
|
len = update_buffered_hq_frames(stream, len, avail);
|
||||||
|
|
|
@ -584,4 +584,7 @@ lsquic_stream_duplicate_push (struct lsquic_stream *, uint64_t push_id);
|
||||||
int
|
int
|
||||||
lsquic_stream_push_promise (struct lsquic_stream *, struct push_promise *);
|
lsquic_stream_push_promise (struct lsquic_stream *, struct push_promise *);
|
||||||
|
|
||||||
|
void
|
||||||
|
lsquic_stream_force_finish (struct lsquic_stream *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -393,19 +393,31 @@ packetization_write_as_much_as_you_can (lsquic_stream_t *stream,
|
||||||
lsquic_stream_ctx_t *ctx)
|
lsquic_stream_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
struct packetization_test_stream_ctx *const pack_ctx = (void *) 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;
|
ssize_t n_written;
|
||||||
|
size_t avail;
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
while (pack_ctx->off < pack_ctx->len)
|
while (pack_ctx->off < pack_ctx->len)
|
||||||
{
|
{
|
||||||
n_to_write = calc_n_to_write(pack_ctx->write_size);
|
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)
|
if (n_to_write > pack_ctx->len - pack_ctx->off)
|
||||||
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_written = lsquic_stream_write(stream, pack_ctx->buf + pack_ctx->off,
|
||||||
n_to_write);
|
n_to_write);
|
||||||
if (n_written == 0)
|
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;
|
break;
|
||||||
|
}
|
||||||
pack_ctx->off += n_written;
|
pack_ctx->off += n_written;
|
||||||
if (pack_ctx->flush_after_each_write)
|
if (pack_ctx->flush_after_each_write)
|
||||||
{
|
{
|
||||||
|
@ -425,16 +437,27 @@ packetization_perform_one_write (lsquic_stream_t *stream,
|
||||||
lsquic_stream_ctx_t *ctx)
|
lsquic_stream_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
struct packetization_test_stream_ctx *const pack_ctx = (void *) 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;
|
ssize_t n_written;
|
||||||
|
size_t avail;
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
n_to_write = calc_n_to_write(pack_ctx->write_size);
|
n_to_write = calc_n_to_write(pack_ctx->write_size);
|
||||||
if (n_to_write > pack_ctx->len - pack_ctx->off)
|
if (n_to_write > pack_ctx->len - pack_ctx->off)
|
||||||
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_written = lsquic_stream_write(stream, pack_ctx->buf + pack_ctx->off,
|
||||||
n_to_write);
|
n_to_write);
|
||||||
assert(n_written >= 0);
|
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;
|
pack_ctx->off += n_written;
|
||||||
if (pack_ctx->flush_after_each_write)
|
if (pack_ctx->flush_after_each_write)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue