mirror of
				https://gitea.invidious.io/iv-org/litespeed-quic.git
				synced 2024-08-15 00:53:43 +00:00 
			
		
		
		
	Release 2.23.0
- [FEATURE] IETF Client 0-RTT support. - [BUGFIX] Do not schedule MTU probe on first tick. - [BUGFIX] Parsing DATAGRAM frame. - [BUGFIX] If push promise fails, do not invoke hset destructor. - [BUGFIX] Client: When connections are IDed by port number, check DCID. Fixes issue #176. - Revert the 2.22.1 lsquic_is_valid_hs_packet change. All that was necessary is a change to the way we call it in lsquic_engine. No change to the function itself is required.
This commit is contained in:
		
							parent
							
								
									f3d781aa59
								
							
						
					
					
						commit
						04f8f447b2
					
				
					 24 changed files with 808 additions and 309 deletions
				
			
		
							
								
								
									
										12
									
								
								CHANGELOG
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								CHANGELOG
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,3 +1,15 @@
 | 
			
		|||
2020-10-13
 | 
			
		||||
    - 2.23.0
 | 
			
		||||
    - [FEATURE] IETF Client 0-RTT support.
 | 
			
		||||
    - [BUGFIX] Do not schedule MTU probe on first tick.
 | 
			
		||||
    - [BUGFIX] Parsing DATAGRAM frame.
 | 
			
		||||
    - [BUGFIX] If push promise fails, do not invoke hset destructor.
 | 
			
		||||
    - [BUGFIX] Client: When connections are IDed by port number, check DCID.
 | 
			
		||||
      Fixes issue #176.
 | 
			
		||||
    - Revert the 2.22.1 lsquic_is_valid_hs_packet change.  All that was
 | 
			
		||||
      necessary is a change to the way we call it in lsquic_engine.  No
 | 
			
		||||
      change to the function itself is required.
 | 
			
		||||
 | 
			
		||||
2020-10-08
 | 
			
		||||
    - 2.22.1
 | 
			
		||||
    - [BUGFIX] Function that checks validity of handshake packets.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1506,8 +1506,14 @@ idle_on_write (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
 | 
			
		|||
                headers.count = sizeof(header_arr) / sizeof(header_arr[0]);
 | 
			
		||||
                req = new_req(GET, push_path->path, st_h->req->authority_str);
 | 
			
		||||
                if (req)
 | 
			
		||||
                    (void) lsquic_conn_push_stream(lsquic_stream_conn(stream),
 | 
			
		||||
                                req, stream, &headers);
 | 
			
		||||
                {
 | 
			
		||||
                    if (0 != lsquic_conn_push_stream(lsquic_stream_conn(stream),
 | 
			
		||||
                                                            req, stream, &headers))
 | 
			
		||||
                    {
 | 
			
		||||
                        LSQ_WARN("stream push failed");
 | 
			
		||||
                        interop_server_hset_destroy(req);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                    LSQ_WARN("cannot allocate req for push");
 | 
			
		||||
                free(push_path);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -93,7 +93,11 @@ load_cert (struct lsquic_hash *certs, const char *optarg)
 | 
			
		|||
    SSL_CTX_set_max_proto_version(cert->ce_ssl_ctx, TLS1_3_VERSION);
 | 
			
		||||
    SSL_CTX_set_default_verify_paths(cert->ce_ssl_ctx);
 | 
			
		||||
    SSL_CTX_set_alpn_select_cb(cert->ce_ssl_ctx, select_alpn, NULL);
 | 
			
		||||
    SSL_CTX_set_early_data_enabled(cert->ce_ssl_ctx, 1);    /* XXX */
 | 
			
		||||
    {
 | 
			
		||||
        const char *const s = getenv("LSQUIC_ENABLE_EARLY_DATA");
 | 
			
		||||
        if (!s || atoi(s))
 | 
			
		||||
            SSL_CTX_set_early_data_enabled(cert->ce_ssl_ctx, 1);    /* XXX */
 | 
			
		||||
    }
 | 
			
		||||
    if (1 != SSL_CTX_use_certificate_chain_file(cert->ce_ssl_ctx, cert_file))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_ERROR("SSL_CTX_use_certificate_chain_file failed: %s", cert_file);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1993,6 +1993,11 @@ set_engine_option (struct lsquic_engine_settings *settings,
 | 
			
		|||
            settings->es_qpack_dec_max_blocked = atoi(val);
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        if (0 == strncmp(name, "init_max_streams_bidi", 21))
 | 
			
		||||
        {
 | 
			
		||||
            settings->es_init_max_streams_bidi = atoi(val);
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case 23:
 | 
			
		||||
        if (0 == strncmp(name, "max_udp_payload_size_rx", 23))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,9 +58,9 @@ developed by the IETF.  Both types are included in a single enum:
 | 
			
		|||
 | 
			
		||||
        IETF QUIC version ID 29
 | 
			
		||||
 | 
			
		||||
    .. member:: LSQVER_ID30; this version is deprecated.
 | 
			
		||||
    .. member:: LSQVER_ID30
 | 
			
		||||
 | 
			
		||||
        IETF QUIC version ID 30
 | 
			
		||||
        IETF QUIC version ID 30; this version is deprecated.
 | 
			
		||||
 | 
			
		||||
    .. member:: LSQVER_ID31
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,9 +24,9 @@ copyright = u'2020, LiteSpeed Technologies'
 | 
			
		|||
author = u'LiteSpeed Technologies'
 | 
			
		||||
 | 
			
		||||
# The short X.Y version
 | 
			
		||||
version = u'2.22'
 | 
			
		||||
version = u'2.23'
 | 
			
		||||
# The full version, including alpha/beta/rc tags
 | 
			
		||||
release = u'2.22.1'
 | 
			
		||||
release = u'2.23.0'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# -- General configuration ---------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ connections.
 | 
			
		|||
 | 
			
		||||
To aid development, there is a :macro:`LSQUIC_FORCED_TCID0_VERSIONS` that
 | 
			
		||||
specifies the list of versions with 0-sized connections.  (If you, for
 | 
			
		||||
example, want to turn them.)
 | 
			
		||||
example, want to turn them off.)
 | 
			
		||||
 | 
			
		||||
Once gQUIC becomes deprecated in the future, there will remain no technical
 | 
			
		||||
reason why a single engine instance could not be used both for client and
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,8 +24,8 @@ extern "C" {
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
#define LSQUIC_MAJOR_VERSION 2
 | 
			
		||||
#define LSQUIC_MINOR_VERSION 22
 | 
			
		||||
#define LSQUIC_PATCH_VERSION 1
 | 
			
		||||
#define LSQUIC_MINOR_VERSION 23
 | 
			
		||||
#define LSQUIC_PATCH_VERSION 0
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Engine flags:
 | 
			
		||||
| 
						 | 
				
			
			@ -1923,8 +1923,7 @@ lsquic_get_h3_alpns (unsigned versions);
 | 
			
		|||
 * been established: it will return incorrect result.
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
lsquic_is_valid_hs_packet (lsquic_engine_t *, const unsigned char *,
 | 
			
		||||
                                        size_t bufsz, size_t packet_in_sz);
 | 
			
		||||
lsquic_is_valid_hs_packet (lsquic_engine_t *, const unsigned char *, size_t);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Parse cid from packet stored in `buf' and store it to `cid'.  Returns 0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -282,6 +282,10 @@ struct conn_iface
 | 
			
		|||
    /* Optional method */
 | 
			
		||||
    size_t
 | 
			
		||||
    (*ci_get_min_datagram_size) (struct lsquic_conn *);
 | 
			
		||||
 | 
			
		||||
    /* Optional method */
 | 
			
		||||
    void
 | 
			
		||||
    (*ci_early_data_failed) (struct lsquic_conn *);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define LSCONN_CCE_BITS 3
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,8 @@ struct ssl_stream_method_st;
 | 
			
		|||
struct ssl_st;
 | 
			
		||||
struct sockaddr;
 | 
			
		||||
struct conn_cid_elem;
 | 
			
		||||
struct lsquic_engine_settings;
 | 
			
		||||
enum lsquic_version;
 | 
			
		||||
 | 
			
		||||
#define DNONC_LENGTH 32
 | 
			
		||||
#define SRST_LENGTH 16
 | 
			
		||||
| 
						 | 
				
			
			@ -242,12 +244,6 @@ struct enc_session_funcs_gquic
 | 
			
		|||
    void (*esf_reset_cid) (enc_session_t *, const lsquic_cid_t *);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum iquic_handshake_status {
 | 
			
		||||
    IHS_WANT_READ,
 | 
			
		||||
    IHS_WANT_WRITE,
 | 
			
		||||
    IHS_STOP,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct crypto_stream_if
 | 
			
		||||
{
 | 
			
		||||
    ssize_t     (*csi_write) (void *stream, const void *buf, size_t len);
 | 
			
		||||
| 
						 | 
				
			
			@ -371,4 +367,10 @@ lsquic_sess_resume_version (const unsigned char *, size_t);
 | 
			
		|||
 */
 | 
			
		||||
#define IQUIC_TAG_LEN 16
 | 
			
		||||
 | 
			
		||||
/* Return number of bytes written to `buf' or -1 on error */
 | 
			
		||||
int
 | 
			
		||||
lsquic_enc_sess_ietf_gen_quic_ctx (
 | 
			
		||||
                const struct lsquic_engine_settings *settings,
 | 
			
		||||
                enum lsquic_version version, unsigned char *buf, size_t bufsz);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -107,6 +107,20 @@ static void
 | 
			
		|||
no_sess_ticket (enum alarm_id alarm_id, void *ctx,
 | 
			
		||||
                                  lsquic_time_t expiry, lsquic_time_t now);
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
iquic_new_session_cb (SSL *, SSL_SESSION *);
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
keylog_callback (const SSL *, const char *);
 | 
			
		||||
 | 
			
		||||
static enum ssl_verify_result_t
 | 
			
		||||
verify_server_cert_callback (SSL *, uint8_t *out_alert);
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
maybe_setup_key_logging (struct enc_sess_iquic *);
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
iquic_esfi_destroy (enc_session_t *);
 | 
			
		||||
 | 
			
		||||
#define SAMPLE_SZ 16
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -223,7 +237,7 @@ struct enc_sess_iquic
 | 
			
		|||
    lsquic_cid_t         esi_iscid; /* Initial SCID */
 | 
			
		||||
    unsigned             esi_key_phase;
 | 
			
		||||
    enum {
 | 
			
		||||
        ESI_INITIALIZED  = 1 << 0,
 | 
			
		||||
        ESI_UNUSED0      = 1 << 0,
 | 
			
		||||
        ESI_LOG_SECRETS  = 1 << 1,
 | 
			
		||||
        ESI_HANDSHAKE_OK = 1 << 2,
 | 
			
		||||
        ESI_ODCID        = 1 << 3,
 | 
			
		||||
| 
						 | 
				
			
			@ -243,17 +257,15 @@ struct enc_sess_iquic
 | 
			
		|||
        ESI_MAX_PACKNO_INIT = 1 << 17,
 | 
			
		||||
        ESI_MAX_PACKNO_HSK  = ESI_MAX_PACKNO_INIT << PNS_HSK,
 | 
			
		||||
        ESI_MAX_PACKNO_APP  = ESI_MAX_PACKNO_INIT << PNS_APP,
 | 
			
		||||
        ESI_HAVE_0RTT_TP = 1 << 20,
 | 
			
		||||
    }                    esi_flags;
 | 
			
		||||
    enum enc_level       esi_last_w;
 | 
			
		||||
    unsigned             esi_trasec_sz;
 | 
			
		||||
    char                *esi_hostname;
 | 
			
		||||
    void                *esi_keylog_handle;
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
    char                *esi_sni_bypass;
 | 
			
		||||
#endif
 | 
			
		||||
    const unsigned char *esi_alpn;
 | 
			
		||||
    unsigned char       *esi_sess_resume_buf;
 | 
			
		||||
    size_t               esi_sess_resume_sz;
 | 
			
		||||
    /* Need MD and AEAD for key rotation */
 | 
			
		||||
    const EVP_MD        *esi_md;
 | 
			
		||||
    const EVP_AEAD      *esi_aead;
 | 
			
		||||
| 
						 | 
				
			
			@ -279,6 +291,7 @@ struct enc_sess_iquic
 | 
			
		|||
                         esi_hp_batch_packets[HP_BATCH_SIZE];
 | 
			
		||||
    unsigned char        esi_hp_batch_samples[HP_BATCH_SIZE][SAMPLE_SZ];
 | 
			
		||||
    unsigned char        esi_grease;
 | 
			
		||||
    signed char          esi_have_forw;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -696,24 +709,23 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
 | 
			
		|||
 | 
			
		||||
static SSL_SESSION *
 | 
			
		||||
maybe_create_SSL_SESSION (struct enc_sess_iquic *enc_sess,
 | 
			
		||||
                                                    const SSL_CTX *ssl_ctx)
 | 
			
		||||
            const SSL_CTX *ssl_ctx, const unsigned char *sess_resume,
 | 
			
		||||
                                                        size_t sess_resume_sz)
 | 
			
		||||
{
 | 
			
		||||
    SSL_SESSION *ssl_session;
 | 
			
		||||
    lsquic_ver_tag_t ver_tag;
 | 
			
		||||
    enum lsquic_version quic_ver;
 | 
			
		||||
    uint32_t rtt_ver, ticket_sz, trapa_sz;
 | 
			
		||||
    const unsigned char *ticket_buf, *trapa_buf, *p;
 | 
			
		||||
    const unsigned char *const end
 | 
			
		||||
                    = enc_sess->esi_sess_resume_buf + enc_sess->esi_sess_resume_sz;
 | 
			
		||||
    const unsigned char *const end = sess_resume + sess_resume_sz;
 | 
			
		||||
 | 
			
		||||
    if (enc_sess->esi_sess_resume_sz
 | 
			
		||||
                    < sizeof(ver_tag) + sizeof(rtt_ver) + sizeof(ticket_sz))
 | 
			
		||||
    if (sess_resume_sz < sizeof(ver_tag) + sizeof(rtt_ver) + sizeof(ticket_sz))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_DEBUG("rtt buf too short");
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    p = enc_sess->esi_sess_resume_buf;
 | 
			
		||||
    p = sess_resume;
 | 
			
		||||
    memcpy(&ver_tag, p, sizeof(ver_tag));
 | 
			
		||||
    p += sizeof(ver_tag);
 | 
			
		||||
    quic_ver = lsquic_tag2ver(ver_tag);
 | 
			
		||||
| 
						 | 
				
			
			@ -760,8 +772,6 @@ maybe_create_SSL_SESSION (struct enc_sess_iquic *enc_sess,
 | 
			
		|||
    p += trapa_sz;
 | 
			
		||||
    assert(p == end);
 | 
			
		||||
 | 
			
		||||
    (void) /* TODO */ trapa_buf;
 | 
			
		||||
 | 
			
		||||
    ssl_session = SSL_SESSION_from_bytes(ticket_buf, ticket_sz, ssl_ctx);
 | 
			
		||||
    if (!ssl_session)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -769,6 +779,22 @@ maybe_create_SSL_SESSION (struct enc_sess_iquic *enc_sess,
 | 
			
		|||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (SSL_SESSION_early_data_capable(ssl_session))
 | 
			
		||||
    {
 | 
			
		||||
        if (0 > (quic_ver == LSQVER_ID27 ? lsquic_tp_decode_27
 | 
			
		||||
                    : lsquic_tp_decode)(trapa_buf, trapa_sz, 1,
 | 
			
		||||
                                                    &enc_sess->esi_peer_tp))
 | 
			
		||||
        {
 | 
			
		||||
            SSL_SESSION_free(ssl_session);
 | 
			
		||||
            LSQ_WARN("cannot parse stored transport parameters");
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
        LSQ_DEBUG("early data capable, will try 0-RTT");
 | 
			
		||||
        enc_sess->esi_flags |= ESI_HAVE_0RTT_TP;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        LSQ_DEBUG("early data not capable -- not trying 0-RTT");
 | 
			
		||||
 | 
			
		||||
    LSQ_INFO("instantiated SSL_SESSION from serialized buffer");
 | 
			
		||||
    return ssl_session;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -795,6 +821,16 @@ iquic_esfi_create_client (const char *hostname,
 | 
			
		|||
            struct lsquic_alarmset *alset, unsigned max_streams_uni)
 | 
			
		||||
{
 | 
			
		||||
    struct enc_sess_iquic *enc_sess;
 | 
			
		||||
    SSL_CTX *ssl_ctx;
 | 
			
		||||
    SSL_SESSION *ssl_session;
 | 
			
		||||
    const struct alpn_map *am;
 | 
			
		||||
    int transpa_len;
 | 
			
		||||
    char errbuf[ERR_ERROR_STRING_BUF_LEN];
 | 
			
		||||
    unsigned char trans_params[0x80
 | 
			
		||||
#if LSQUIC_TEST_QUANTUM_READINESS
 | 
			
		||||
        + 4 + lsquic_tp_get_quantum_sz()
 | 
			
		||||
#endif
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    fiu_return_on("enc_sess_ietf/create_client", NULL);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -802,18 +838,6 @@ iquic_esfi_create_client (const char *hostname,
 | 
			
		|||
    if (!enc_sess)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    if (hostname)
 | 
			
		||||
    {
 | 
			
		||||
        enc_sess->esi_hostname = strdup(hostname);
 | 
			
		||||
        if (!enc_sess->esi_hostname)
 | 
			
		||||
        {
 | 
			
		||||
            free(enc_sess);
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        enc_sess->esi_hostname = NULL;
 | 
			
		||||
 | 
			
		||||
    enc_sess->esi_enpub = enpub;
 | 
			
		||||
    enc_sess->esi_streams = crypto_streams;
 | 
			
		||||
    enc_sess->esi_cryst_if = cryst_if;
 | 
			
		||||
| 
						 | 
				
			
			@ -844,35 +868,123 @@ iquic_esfi_create_client (const char *hostname,
 | 
			
		|||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Have to wait until the call to init_client() -- this is when the
 | 
			
		||||
     * result of version negotiation is known.
 | 
			
		||||
     */
 | 
			
		||||
    enc_sess->esi_max_streams_uni = max_streams_uni;
 | 
			
		||||
 | 
			
		||||
    if (enc_sess->esi_enpub->enp_alpn)
 | 
			
		||||
        enc_sess->esi_alpn = enc_sess->esi_enpub->enp_alpn;
 | 
			
		||||
    else if (enc_sess->esi_enpub->enp_flags & ENPUB_HTTP)
 | 
			
		||||
    {
 | 
			
		||||
        for (am = s_h3_alpns; am < s_h3_alpns + sizeof(s_h3_alpns)
 | 
			
		||||
                                                / sizeof(s_h3_alpns[0]); ++am)
 | 
			
		||||
            if (am->version == enc_sess->esi_ver_neg->vn_ver)
 | 
			
		||||
                goto alpn_selected;
 | 
			
		||||
        LSQ_ERROR("version %s has no matching ALPN",
 | 
			
		||||
                                lsquic_ver2str[enc_sess->esi_ver_neg->vn_ver]);
 | 
			
		||||
        goto err;
 | 
			
		||||
  alpn_selected:
 | 
			
		||||
        enc_sess->esi_alpn = am->alpn;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LSQ_DEBUG("Create new SSL_CTX");
 | 
			
		||||
    ssl_ctx = SSL_CTX_new(TLS_method());
 | 
			
		||||
    if (!ssl_ctx)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_ERROR("cannot create SSL context: %s",
 | 
			
		||||
            ERR_error_string(ERR_get_error(), errbuf));
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
    SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION);
 | 
			
		||||
    SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION);
 | 
			
		||||
    SSL_CTX_set_default_verify_paths(ssl_ctx);
 | 
			
		||||
    SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_CLIENT);
 | 
			
		||||
    if (enc_sess->esi_enpub->enp_stream_if->on_sess_resume_info)
 | 
			
		||||
        SSL_CTX_sess_set_new_cb(ssl_ctx, iquic_new_session_cb);
 | 
			
		||||
    if (enc_sess->esi_enpub->enp_kli)
 | 
			
		||||
        SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
 | 
			
		||||
    if (enc_sess->esi_enpub->enp_verify_cert
 | 
			
		||||
            || LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)
 | 
			
		||||
            || LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_QLOG))
 | 
			
		||||
        SSL_CTX_set_custom_verify(ssl_ctx, SSL_VERIFY_PEER,
 | 
			
		||||
            verify_server_cert_callback);
 | 
			
		||||
    SSL_CTX_set_early_data_enabled(ssl_ctx, 1);
 | 
			
		||||
 | 
			
		||||
    enc_sess->esi_ssl = SSL_new(ssl_ctx);
 | 
			
		||||
    if (!enc_sess->esi_ssl)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_ERROR("cannot create SSL object: %s",
 | 
			
		||||
            ERR_error_string(ERR_get_error(), errbuf));
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    transpa_len = gen_trans_params(enc_sess, trans_params,
 | 
			
		||||
                                                    sizeof(trans_params));
 | 
			
		||||
    if (transpa_len < 0)
 | 
			
		||||
    {
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
    if (1 != SSL_set_quic_transport_params(enc_sess->esi_ssl, trans_params,
 | 
			
		||||
                                                            transpa_len))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_ERROR("cannot set QUIC transport params: %s",
 | 
			
		||||
            ERR_error_string(ERR_get_error(), errbuf));
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!(SSL_set_quic_method(enc_sess->esi_ssl, &cry_quic_method)))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_INFO("could not set stream method");
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    maybe_setup_key_logging(enc_sess);
 | 
			
		||||
 | 
			
		||||
    if (enc_sess->esi_alpn &&
 | 
			
		||||
            0 != SSL_set_alpn_protos(enc_sess->esi_ssl, enc_sess->esi_alpn,
 | 
			
		||||
                                                    enc_sess->esi_alpn[0] + 1))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_ERROR("cannot set ALPN: %s",
 | 
			
		||||
            ERR_error_string(ERR_get_error(), errbuf));
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
    if (1 != SSL_set_tlsext_host_name(enc_sess->esi_ssl, hostname))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_ERROR("cannot set hostname: %s",
 | 
			
		||||
            ERR_error_string(ERR_get_error(), errbuf));
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (sess_resume && sess_resume_sz)
 | 
			
		||||
    {
 | 
			
		||||
        enc_sess->esi_sess_resume_buf = malloc(sess_resume_sz);
 | 
			
		||||
        if (enc_sess->esi_sess_resume_buf)
 | 
			
		||||
        ssl_session = maybe_create_SSL_SESSION(enc_sess, ssl_ctx,
 | 
			
		||||
                                                sess_resume, sess_resume_sz);
 | 
			
		||||
        if (ssl_session)
 | 
			
		||||
        {
 | 
			
		||||
            memcpy(enc_sess->esi_sess_resume_buf, sess_resume, sess_resume_sz);
 | 
			
		||||
            enc_sess->esi_sess_resume_sz = sess_resume_sz;
 | 
			
		||||
            (void)  /* This only ever returns 1: */
 | 
			
		||||
                SSL_set_session(enc_sess->esi_ssl, ssl_session);
 | 
			
		||||
            SSL_SESSION_free(ssl_session);
 | 
			
		||||
            ssl_session = NULL;
 | 
			
		||||
            enc_sess->esi_flags |= ESI_USE_SSL_TICKET;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            enc_sess->esi_sess_resume_sz = 0;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        enc_sess->esi_sess_resume_buf = NULL;
 | 
			
		||||
        enc_sess->esi_sess_resume_sz = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SSL_set_ex_data(enc_sess->esi_ssl, s_idx, enc_sess);
 | 
			
		||||
    SSL_set_connect_state(enc_sess->esi_ssl);
 | 
			
		||||
 | 
			
		||||
    if (enc_sess->esi_enpub->enp_stream_if->on_sess_resume_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);
 | 
			
		||||
 | 
			
		||||
    enc_sess->esi_max_streams_uni = max_streams_uni;
 | 
			
		||||
 | 
			
		||||
    SSL_CTX_free(ssl_ctx);
 | 
			
		||||
    return enc_sess;
 | 
			
		||||
 | 
			
		||||
  err:
 | 
			
		||||
    if (enc_sess)
 | 
			
		||||
        iquic_esfi_destroy(enc_sess);
 | 
			
		||||
    if (ssl_ctx)
 | 
			
		||||
        SSL_CTX_free(ssl_ctx);
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1242,6 +1354,7 @@ iquic_esfi_init_server (enc_session_t *enc_session_p)
 | 
			
		|||
{
 | 
			
		||||
    struct enc_sess_iquic *const enc_sess = enc_session_p;
 | 
			
		||||
    const struct alpn_map *am;
 | 
			
		||||
    unsigned quic_ctx_idx;
 | 
			
		||||
    int transpa_len;
 | 
			
		||||
    SSL_CTX *ssl_ctx = NULL;
 | 
			
		||||
    union {
 | 
			
		||||
| 
						 | 
				
			
			@ -1287,9 +1400,10 @@ iquic_esfi_init_server (enc_session_t *enc_session_p)
 | 
			
		|||
        LSQ_INFO("could not set stream method");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    /* TODO: set to transport parameter string instead of the constant string */
 | 
			
		||||
    quic_ctx_idx = enc_sess->esi_conn->cn_version == LSQVER_ID27 ? 0 : 1;
 | 
			
		||||
    if (!SSL_set_quic_early_data_context(enc_sess->esi_ssl,
 | 
			
		||||
                                                (unsigned char *) "lsquic", 6))
 | 
			
		||||
                        enc_sess->esi_enpub->enp_quic_ctx_buf[quic_ctx_idx],
 | 
			
		||||
                        enc_sess->esi_enpub->enp_quic_ctx_sz[quic_ctx_idx]))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_INFO("could not set early data context");
 | 
			
		||||
        return -1;
 | 
			
		||||
| 
						 | 
				
			
			@ -1317,7 +1431,6 @@ iquic_esfi_init_server (enc_session_t *enc_session_p)
 | 
			
		|||
    SSL_set_ex_data(enc_sess->esi_ssl, s_idx, enc_sess);
 | 
			
		||||
    SSL_set_accept_state(enc_sess->esi_ssl);
 | 
			
		||||
    LSQ_DEBUG("initialized server enc session");
 | 
			
		||||
    enc_sess->esi_flags |= ESI_INITIALIZED;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1415,129 +1528,6 @@ iquic_new_session_cb (SSL *ssl, SSL_SESSION *session)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
init_client (struct enc_sess_iquic *const enc_sess)
 | 
			
		||||
{
 | 
			
		||||
    SSL_CTX *ssl_ctx;
 | 
			
		||||
    SSL_SESSION *ssl_session;
 | 
			
		||||
    const struct alpn_map *am;
 | 
			
		||||
    int transpa_len;
 | 
			
		||||
    char errbuf[ERR_ERROR_STRING_BUF_LEN];
 | 
			
		||||
#define hexbuf errbuf   /* This is a dual-purpose buffer */
 | 
			
		||||
    unsigned char trans_params[0x80
 | 
			
		||||
#if LSQUIC_TEST_QUANTUM_READINESS
 | 
			
		||||
        + 4 + lsquic_tp_get_quantum_sz()
 | 
			
		||||
#endif
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    if (enc_sess->esi_enpub->enp_alpn)
 | 
			
		||||
        enc_sess->esi_alpn = enc_sess->esi_enpub->enp_alpn;
 | 
			
		||||
    else if (enc_sess->esi_enpub->enp_flags & ENPUB_HTTP)
 | 
			
		||||
    {
 | 
			
		||||
        for (am = s_h3_alpns; am < s_h3_alpns + sizeof(s_h3_alpns)
 | 
			
		||||
                                                / sizeof(s_h3_alpns[0]); ++am)
 | 
			
		||||
            if (am->version == enc_sess->esi_ver_neg->vn_ver)
 | 
			
		||||
                goto ok;
 | 
			
		||||
        LSQ_ERROR("version %s has no matching ALPN",
 | 
			
		||||
                                lsquic_ver2str[enc_sess->esi_ver_neg->vn_ver]);
 | 
			
		||||
        return -1;
 | 
			
		||||
  ok:   enc_sess->esi_alpn = am->alpn;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LSQ_DEBUG("Create new SSL_CTX");
 | 
			
		||||
    ssl_ctx = SSL_CTX_new(TLS_method());
 | 
			
		||||
    if (!ssl_ctx)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_ERROR("cannot create SSL context: %s",
 | 
			
		||||
            ERR_error_string(ERR_get_error(), errbuf));
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
    SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION);
 | 
			
		||||
    SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION);
 | 
			
		||||
    SSL_CTX_set_default_verify_paths(ssl_ctx);
 | 
			
		||||
    SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_CLIENT);
 | 
			
		||||
    if (enc_sess->esi_enpub->enp_stream_if->on_sess_resume_info)
 | 
			
		||||
        SSL_CTX_sess_set_new_cb(ssl_ctx, iquic_new_session_cb);
 | 
			
		||||
    if (enc_sess->esi_enpub->enp_kli)
 | 
			
		||||
        SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
 | 
			
		||||
    if (enc_sess->esi_enpub->enp_verify_cert
 | 
			
		||||
            || LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)
 | 
			
		||||
            || LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_QLOG))
 | 
			
		||||
        SSL_CTX_set_custom_verify(ssl_ctx, SSL_VERIFY_PEER,
 | 
			
		||||
            verify_server_cert_callback);
 | 
			
		||||
    SSL_CTX_set_early_data_enabled(ssl_ctx, 1);
 | 
			
		||||
 | 
			
		||||
    transpa_len = gen_trans_params(enc_sess, trans_params,
 | 
			
		||||
                                                    sizeof(trans_params));
 | 
			
		||||
    if (transpa_len < 0)
 | 
			
		||||
    {
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enc_sess->esi_ssl = SSL_new(ssl_ctx);
 | 
			
		||||
    if (!enc_sess->esi_ssl)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_ERROR("cannot create SSL object: %s",
 | 
			
		||||
            ERR_error_string(ERR_get_error(), errbuf));
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
    if (!(SSL_set_quic_method(enc_sess->esi_ssl, &cry_quic_method)))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_INFO("could not set stream method");
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
    maybe_setup_key_logging(enc_sess);
 | 
			
		||||
    if (1 != SSL_set_quic_transport_params(enc_sess->esi_ssl, trans_params,
 | 
			
		||||
                                                            transpa_len))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_ERROR("cannot set QUIC transport params: %s",
 | 
			
		||||
            ERR_error_string(ERR_get_error(), errbuf));
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
    if (enc_sess->esi_alpn &&
 | 
			
		||||
            0 != SSL_set_alpn_protos(enc_sess->esi_ssl, enc_sess->esi_alpn,
 | 
			
		||||
                                                    enc_sess->esi_alpn[0] + 1))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_ERROR("cannot set ALPN: %s",
 | 
			
		||||
            ERR_error_string(ERR_get_error(), errbuf));
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
    if (1 != SSL_set_tlsext_host_name(enc_sess->esi_ssl,
 | 
			
		||||
                                                    enc_sess->esi_hostname))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_ERROR("cannot set hostname: %s",
 | 
			
		||||
            ERR_error_string(ERR_get_error(), errbuf));
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
    free(enc_sess->esi_hostname);
 | 
			
		||||
    enc_sess->esi_hostname = NULL;
 | 
			
		||||
    if (enc_sess->esi_sess_resume_buf)
 | 
			
		||||
    {
 | 
			
		||||
        ssl_session = maybe_create_SSL_SESSION(enc_sess, ssl_ctx);
 | 
			
		||||
        if (ssl_session)
 | 
			
		||||
        {
 | 
			
		||||
            if (SSL_set_session(enc_sess->esi_ssl, ssl_session))
 | 
			
		||||
                enc_sess->esi_flags |= ESI_USE_SSL_TICKET;
 | 
			
		||||
            else
 | 
			
		||||
                LSQ_WARN("cannot set session");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SSL_set_ex_data(enc_sess->esi_ssl, s_idx, enc_sess);
 | 
			
		||||
    SSL_set_connect_state(enc_sess->esi_ssl);
 | 
			
		||||
    SSL_CTX_free(ssl_ctx);
 | 
			
		||||
    LSQ_DEBUG("initialized client enc session");
 | 
			
		||||
    enc_sess->esi_flags |= ESI_INITIALIZED;
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
  err:
 | 
			
		||||
    if (ssl_ctx)
 | 
			
		||||
        SSL_CTX_free(ssl_ctx);
 | 
			
		||||
    return -1;
 | 
			
		||||
#undef hexbuf
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct crypto_params
 | 
			
		||||
{
 | 
			
		||||
    const EVP_AEAD      *aead;
 | 
			
		||||
| 
						 | 
				
			
			@ -1607,14 +1597,72 @@ get_crypto_params (const struct enc_sess_iquic *enc_sess,
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* [draft-ietf-quic-transport-31] Section 7.4.1:
 | 
			
		||||
 " If 0-RTT data is accepted by the server, the server MUST NOT reduce
 | 
			
		||||
 " any limits or alter any values that might be violated by the client
 | 
			
		||||
 " with its 0-RTT data.  In particular, a server that accepts 0-RTT data
 | 
			
		||||
 " MUST NOT set values for the following parameters (Section 18.2) that
 | 
			
		||||
 " are smaller than the remembered value of the parameters.
 | 
			
		||||
 "
 | 
			
		||||
 " *  active_connection_id_limit
 | 
			
		||||
 "
 | 
			
		||||
 " *  initial_max_data
 | 
			
		||||
 "
 | 
			
		||||
 " *  initial_max_stream_data_bidi_local
 | 
			
		||||
 "
 | 
			
		||||
 " *  initial_max_stream_data_bidi_remote
 | 
			
		||||
 "
 | 
			
		||||
 " *  initial_max_stream_data_uni
 | 
			
		||||
 "
 | 
			
		||||
 " *  initial_max_streams_bidi
 | 
			
		||||
 "
 | 
			
		||||
 " *  initial_max_streams_uni
 | 
			
		||||
 */
 | 
			
		||||
#define REDUCTION_PROHIBITED_TPS                                     (0 \
 | 
			
		||||
    | (1 << TPI_ACTIVE_CONNECTION_ID_LIMIT)                             \
 | 
			
		||||
    | (1 << TPI_INIT_MAX_DATA)                                          \
 | 
			
		||||
    | (1 << TPI_INIT_MAX_STREAMS_UNI)                                   \
 | 
			
		||||
    | (1 << TPI_INIT_MAX_STREAMS_BIDI)                                  \
 | 
			
		||||
    | (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL)                        \
 | 
			
		||||
    | (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE)                       \
 | 
			
		||||
    | (1 << TPI_INIT_MAX_STREAM_DATA_UNI)                               \
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
check_server_tps_for_violations (const struct enc_sess_iquic *enc_sess,
 | 
			
		||||
                            const struct transport_params *params_0rtt,
 | 
			
		||||
                            const struct transport_params *new_params)
 | 
			
		||||
{
 | 
			
		||||
    enum transport_param_id tpi;
 | 
			
		||||
 | 
			
		||||
    for (tpi = 0; tpi <= MAX_NUMERIC_TPI; ++tpi)
 | 
			
		||||
        if ((1 << tpi) & REDUCTION_PROHIBITED_TPS)
 | 
			
		||||
            if (new_params->tp_numerics[tpi] > params_0rtt->tp_numerics[tpi])
 | 
			
		||||
            {
 | 
			
		||||
                LSQ_INFO("server's new TP %s increased in value from %"PRIu64
 | 
			
		||||
                    " to %"PRIu64, lsquic_tpi2str[tpi],
 | 
			
		||||
                        params_0rtt->tp_numerics[tpi],
 | 
			
		||||
                        new_params->tp_numerics[tpi]);
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
    LSQ_DEBUG("server's new transport parameters do not violate save 0-RTT "
 | 
			
		||||
        "parameters");
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
get_peer_transport_params (struct enc_sess_iquic *enc_sess)
 | 
			
		||||
{
 | 
			
		||||
    struct transport_params *const trans_params = &enc_sess->esi_peer_tp;
 | 
			
		||||
    struct transport_params params_0rtt;
 | 
			
		||||
    const uint8_t *params_buf;
 | 
			
		||||
    size_t bufsz;
 | 
			
		||||
    char *params_str;
 | 
			
		||||
    const enum lsquic_version version = enc_sess->esi_conn->cn_version;
 | 
			
		||||
    int have_0rtt_tp;
 | 
			
		||||
 | 
			
		||||
    SSL_get_peer_quic_transport_params(enc_sess->esi_ssl, ¶ms_buf, &bufsz);
 | 
			
		||||
    if (!params_buf)
 | 
			
		||||
| 
						 | 
				
			
			@ -1623,6 +1671,13 @@ get_peer_transport_params (struct enc_sess_iquic *enc_sess)
 | 
			
		|||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    have_0rtt_tp = !!(enc_sess->esi_flags & ESI_HAVE_0RTT_TP);
 | 
			
		||||
    if (have_0rtt_tp)
 | 
			
		||||
    {
 | 
			
		||||
        params_0rtt = enc_sess->esi_peer_tp;
 | 
			
		||||
        enc_sess->esi_flags &= ~ESI_HAVE_0RTT_TP;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LSQ_DEBUG("have peer transport parameters (%zu bytes)", bufsz);
 | 
			
		||||
    if (0 > (version == LSQVER_ID27 ? lsquic_tp_decode_27
 | 
			
		||||
                : lsquic_tp_decode)(params_buf, bufsz,
 | 
			
		||||
| 
						 | 
				
			
			@ -1646,6 +1701,10 @@ get_peer_transport_params (struct enc_sess_iquic *enc_sess)
 | 
			
		|||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (have_0rtt_tp && 0 != check_server_tps_for_violations(enc_sess,
 | 
			
		||||
                                                ¶ms_0rtt, trans_params))
 | 
			
		||||
        return -1;
 | 
			
		||||
 | 
			
		||||
    const lsquic_cid_t *const cids[LAST_TPI + 1] = {
 | 
			
		||||
        [TP_CID_IDX(TPI_ORIGINAL_DEST_CID)]  = enc_sess->esi_flags & ESI_ODCID ? &enc_sess->esi_odcid : NULL,
 | 
			
		||||
        [TP_CID_IDX(TPI_RETRY_SOURCE_CID)]   = enc_sess->esi_flags & ESI_RSCID ? &enc_sess->esi_rscid : NULL,
 | 
			
		||||
| 
						 | 
				
			
			@ -1771,6 +1830,14 @@ maybe_get_peer_transport_params (struct enc_sess_iquic *enc_sess)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
enum iquic_handshake_status {
 | 
			
		||||
    IHS_WANT_READ,
 | 
			
		||||
    IHS_WANT_WRITE,
 | 
			
		||||
    IHS_WANT_RW,
 | 
			
		||||
    IHS_STOP,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static enum iquic_handshake_status
 | 
			
		||||
iquic_esfi_handshake (struct enc_sess_iquic *enc_sess)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1791,9 +1858,12 @@ iquic_esfi_handshake (struct enc_sess_iquic *enc_sess)
 | 
			
		|||
            LSQ_DEBUG("retry write");
 | 
			
		||||
            return IHS_WANT_WRITE;
 | 
			
		||||
        case SSL_ERROR_EARLY_DATA_REJECTED:
 | 
			
		||||
            LSQ_DEBUG("early data rejected");
 | 
			
		||||
            hsk_status = LSQ_HSK_RESUMED_FAIL;
 | 
			
		||||
            goto err;
 | 
			
		||||
            LSQ_DEBUG("early data rejected: reset");
 | 
			
		||||
            SSL_reset_early_data_reject(enc_sess->esi_ssl);
 | 
			
		||||
            if (enc_sess->esi_conn->cn_if->ci_early_data_failed)
 | 
			
		||||
                enc_sess->esi_conn->cn_if->ci_early_data_failed(
 | 
			
		||||
                                                        enc_sess->esi_conn);
 | 
			
		||||
            return IHS_WANT_RW;
 | 
			
		||||
            /* fall through */
 | 
			
		||||
        default:
 | 
			
		||||
            LSQ_DEBUG("handshake: %s", ERR_error_string(err, errbuf));
 | 
			
		||||
| 
						 | 
				
			
			@ -1866,7 +1936,9 @@ iquic_esfi_get_peer_transport_params (enc_session_t *enc_session_p)
 | 
			
		|||
{
 | 
			
		||||
    struct enc_sess_iquic *const enc_sess = enc_session_p;
 | 
			
		||||
 | 
			
		||||
    if (0 == maybe_get_peer_transport_params(enc_sess))
 | 
			
		||||
    if (enc_sess->esi_flags & ESI_HAVE_0RTT_TP)
 | 
			
		||||
        return &enc_sess->esi_peer_tp;
 | 
			
		||||
    else if (0 == maybe_get_peer_transport_params(enc_sess))
 | 
			
		||||
        return &enc_sess->esi_peer_tp;
 | 
			
		||||
    else
 | 
			
		||||
        return NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -1892,8 +1964,6 @@ iquic_esfi_destroy (enc_session_t *enc_session_p)
 | 
			
		|||
    free_handshake_keys(enc_sess);
 | 
			
		||||
    cleanup_hp(&enc_sess->esi_hp);
 | 
			
		||||
 | 
			
		||||
    free(enc_sess->esi_sess_resume_buf);
 | 
			
		||||
    free(enc_sess->esi_hostname);
 | 
			
		||||
    free(enc_sess);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1910,11 +1980,18 @@ static const enum enc_level hety2el[] =
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const enum enc_level pns2enc_level[] =
 | 
			
		||||
static const enum enc_level pns2enc_level[2][N_PNS] =
 | 
			
		||||
{
 | 
			
		||||
    [PNS_INIT]  = ENC_LEV_CLEAR,
 | 
			
		||||
    [PNS_HSK]   = ENC_LEV_INIT,
 | 
			
		||||
    [PNS_APP]   = ENC_LEV_FORW,
 | 
			
		||||
    [0] = {
 | 
			
		||||
        [PNS_INIT]  = ENC_LEV_CLEAR,
 | 
			
		||||
        [PNS_HSK]   = ENC_LEV_INIT,
 | 
			
		||||
        [PNS_APP]   = ENC_LEV_EARLY,
 | 
			
		||||
    },
 | 
			
		||||
    [1] = {
 | 
			
		||||
        [PNS_INIT]  = ENC_LEV_CLEAR,
 | 
			
		||||
        [PNS_HSK]   = ENC_LEV_INIT,
 | 
			
		||||
        [PNS_APP]   = ENC_LEV_FORW,
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1941,8 +2018,7 @@ iquic_esf_encrypt_packet (enc_session_t *enc_session_p,
 | 
			
		|||
    char errbuf[ERR_ERROR_STRING_BUF_LEN];
 | 
			
		||||
 | 
			
		||||
    pns = lsquic_packet_out_pns(packet_out);
 | 
			
		||||
    /* TODO Obviously, will need more logic for 0-RTT */
 | 
			
		||||
    enc_level = pns2enc_level[ pns ];
 | 
			
		||||
    enc_level = pns2enc_level[ enc_sess->esi_have_forw ][ pns ];
 | 
			
		||||
 | 
			
		||||
    if (enc_level == ENC_LEV_FORW)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -2458,7 +2534,7 @@ static int
 | 
			
		|||
iquic_esf_sess_resume_enabled (enc_session_t *enc_session_p)
 | 
			
		||||
{
 | 
			
		||||
    struct enc_sess_iquic *const enc_sess = enc_session_p;
 | 
			
		||||
    return enc_sess->esi_sess_resume_buf != NULL;
 | 
			
		||||
    return !!(enc_sess->esi_flags & ESI_USE_SSL_TICKET);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2817,6 +2893,9 @@ set_secret (SSL *ssl, enum ssl_encryption_level_t level,
 | 
			
		|||
            key_len, hexbuf));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (rw && enc_level == ENC_LEV_FORW)
 | 
			
		||||
        enc_sess->esi_have_forw = 1;
 | 
			
		||||
 | 
			
		||||
    return 1;
 | 
			
		||||
 | 
			
		||||
  err:
 | 
			
		||||
| 
						 | 
				
			
			@ -2955,25 +3034,11 @@ chsk_ietf_on_new_stream (void *stream_if_ctx, struct lsquic_stream *stream)
 | 
			
		|||
    enum enc_level enc_level;
 | 
			
		||||
 | 
			
		||||
    enc_level = enc_sess->esi_cryst_if->csi_enc_level(stream);
 | 
			
		||||
    if (enc_level != ENC_LEV_CLEAR)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_DEBUG("skip initialization of stream at level %u", enc_level);
 | 
			
		||||
        goto end;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (
 | 
			
		||||
        (enc_sess->esi_flags & ESI_SERVER) == 0 &&
 | 
			
		||||
        0 != init_client(enc_sess))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_WARN("enc session could not be initialized");
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enc_sess->esi_cryst_if->csi_wantwrite(stream, 1);
 | 
			
		||||
    if (enc_level == ENC_LEV_CLEAR)
 | 
			
		||||
        enc_sess->esi_cryst_if->csi_wantwrite(stream, 1);
 | 
			
		||||
 | 
			
		||||
    LSQ_DEBUG("handshake stream created successfully");
 | 
			
		||||
 | 
			
		||||
  end:
 | 
			
		||||
    return stream_if_ctx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3006,6 +3071,7 @@ chsk_ietf_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
 | 
			
		|||
static const char *const ihs2str[] = {
 | 
			
		||||
    [IHS_WANT_READ]  = "want read",
 | 
			
		||||
    [IHS_WANT_WRITE] = "want write",
 | 
			
		||||
    [IHS_WANT_RW]    = "want rw",
 | 
			
		||||
    [IHS_STOP]       = "stop",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3036,6 +3102,10 @@ iquic_esfi_shake_stream (enc_session_t *sess,
 | 
			
		|||
        enc_sess->esi_cryst_if->csi_wantwrite(stream, 1);
 | 
			
		||||
        enc_sess->esi_cryst_if->csi_wantread(stream, 0);
 | 
			
		||||
        break;
 | 
			
		||||
    case IHS_WANT_RW:
 | 
			
		||||
        enc_sess->esi_cryst_if->csi_wantwrite(stream, 1);
 | 
			
		||||
        enc_sess->esi_cryst_if->csi_wantread(stream, 1);
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        assert(st == IHS_STOP);
 | 
			
		||||
        write = !lsquic_frab_list_empty(&enc_sess->esi_frals[enc_level]);
 | 
			
		||||
| 
						 | 
				
			
			@ -3209,3 +3279,96 @@ const unsigned char *const lsquic_retry_nonce_buf[N_IETF_RETRY_VERSIONS] =
 | 
			
		|||
    /* [draft-ietf-quic-tls-29] Section 5.8 */
 | 
			
		||||
    (unsigned char *) "\xe5\x49\x30\xf9\x7f\x21\x36\xf0\x53\x0a\x8c\x1c",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
lsquic_enc_sess_ietf_gen_quic_ctx (
 | 
			
		||||
                const struct lsquic_engine_settings *settings,
 | 
			
		||||
                enum lsquic_version version, unsigned char *buf, size_t bufsz)
 | 
			
		||||
{
 | 
			
		||||
    struct transport_params params;
 | 
			
		||||
    int len;
 | 
			
		||||
 | 
			
		||||
    /* This code is pretty much copied from gen_trans_params(), with
 | 
			
		||||
     * small (but important) exceptions.
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    memset(¶ms, 0, sizeof(params));
 | 
			
		||||
    params.tp_init_max_data = settings->es_init_max_data;
 | 
			
		||||
    params.tp_init_max_stream_data_bidi_local
 | 
			
		||||
                            = settings->es_init_max_stream_data_bidi_local;
 | 
			
		||||
    params.tp_init_max_stream_data_bidi_remote
 | 
			
		||||
                            = settings->es_init_max_stream_data_bidi_remote;
 | 
			
		||||
    params.tp_init_max_stream_data_uni
 | 
			
		||||
                            = settings->es_init_max_stream_data_uni;
 | 
			
		||||
    params.tp_init_max_streams_uni
 | 
			
		||||
                            = settings->es_init_max_streams_uni;
 | 
			
		||||
    params.tp_init_max_streams_bidi
 | 
			
		||||
                            = settings->es_init_max_streams_bidi;
 | 
			
		||||
    params.tp_ack_delay_exponent
 | 
			
		||||
                            = TP_DEF_ACK_DELAY_EXP;
 | 
			
		||||
    params.tp_max_idle_timeout = settings->es_idle_timeout * 1000;
 | 
			
		||||
    params.tp_max_ack_delay = TP_DEF_MAX_ACK_DELAY;
 | 
			
		||||
    params.tp_active_connection_id_limit = MAX_IETF_CONN_DCIDS;
 | 
			
		||||
    params.tp_set |= (1 << TPI_INIT_MAX_DATA)
 | 
			
		||||
                  |  (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL)
 | 
			
		||||
                  |  (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE)
 | 
			
		||||
                  |  (1 << TPI_INIT_MAX_STREAM_DATA_UNI)
 | 
			
		||||
                  |  (1 << TPI_INIT_MAX_STREAMS_UNI)
 | 
			
		||||
                  |  (1 << TPI_INIT_MAX_STREAMS_BIDI)
 | 
			
		||||
                  |  (1 << TPI_ACK_DELAY_EXPONENT)
 | 
			
		||||
                  |  (1 << TPI_MAX_IDLE_TIMEOUT)
 | 
			
		||||
                  |  (1 << TPI_MAX_ACK_DELAY)
 | 
			
		||||
                  |  (1 << TPI_ACTIVE_CONNECTION_ID_LIMIT)
 | 
			
		||||
                  ;
 | 
			
		||||
    if (settings->es_max_udp_payload_size_rx)
 | 
			
		||||
    {
 | 
			
		||||
        params.tp_max_udp_payload_size = settings->es_max_udp_payload_size_rx;
 | 
			
		||||
        params.tp_set |= 1 << TPI_MAX_UDP_PAYLOAD_SIZE;
 | 
			
		||||
    }
 | 
			
		||||
    if (!settings->es_allow_migration)
 | 
			
		||||
        params.tp_set |= 1 << TPI_DISABLE_ACTIVE_MIGRATION;
 | 
			
		||||
    if (settings->es_ql_bits)
 | 
			
		||||
    {
 | 
			
		||||
        params.tp_loss_bits = settings->es_ql_bits - 1;
 | 
			
		||||
        params.tp_set |= 1 << TPI_LOSS_BITS;
 | 
			
		||||
    }
 | 
			
		||||
    if (settings->es_delayed_acks)
 | 
			
		||||
    {
 | 
			
		||||
        params.tp_numerics[TPI_MIN_ACK_DELAY] = 10000;    /* TODO: make into a constant? make configurable? */
 | 
			
		||||
        params.tp_set |= 1 << TPI_MIN_ACK_DELAY;
 | 
			
		||||
    }
 | 
			
		||||
    if (settings->es_timestamps)
 | 
			
		||||
    {
 | 
			
		||||
        params.tp_numerics[TPI_TIMESTAMPS] = TS_GENERATE_THEM;
 | 
			
		||||
        params.tp_set |= 1 << TPI_TIMESTAMPS;
 | 
			
		||||
    }
 | 
			
		||||
    if (settings->es_datagrams)
 | 
			
		||||
    {
 | 
			
		||||
        if (params.tp_set & (1 << TPI_MAX_UDP_PAYLOAD_SIZE))
 | 
			
		||||
            params.tp_numerics[TPI_MAX_DATAGRAM_FRAME_SIZE]
 | 
			
		||||
                                            = params.tp_max_udp_payload_size;
 | 
			
		||||
        else
 | 
			
		||||
            params.tp_numerics[TPI_MAX_DATAGRAM_FRAME_SIZE]
 | 
			
		||||
                                            = TP_DEF_MAX_UDP_PAYLOAD_SIZE;
 | 
			
		||||
        params.tp_set |= 1 << TPI_MAX_DATAGRAM_FRAME_SIZE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    params.tp_set &= SERVER_0RTT_TPS;
 | 
			
		||||
 | 
			
		||||
    len = (version == LSQVER_ID27 ? lsquic_tp_encode_27 : lsquic_tp_encode)(
 | 
			
		||||
                        ¶ms, 1, buf, bufsz);
 | 
			
		||||
    if (len >= 0)
 | 
			
		||||
    {
 | 
			
		||||
        char str[MAX_TP_STR_SZ];
 | 
			
		||||
        LSQ_LOG1(LSQ_LOG_DEBUG, "generated QUIC server context of %d bytes "
 | 
			
		||||
            "for version %s", len, lsquic_ver2str[version]);
 | 
			
		||||
        LSQ_LOG1(LSQ_LOG_DEBUG, "%s", ((version == LSQVER_ID27
 | 
			
		||||
                ? lsquic_tp_to_str_27 : lsquic_tp_to_str)(¶ms, str,
 | 
			
		||||
                                                            sizeof(str)), str));
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        LSQ_LOG1(LSQ_LOG_WARN, "cannot generate QUIC server context: %d",
 | 
			
		||||
                                                                        errno);
 | 
			
		||||
    return len;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -631,6 +631,22 @@ lsquic_engine_new (unsigned flags,
 | 
			
		|||
    engine->pub.enp_tokgen = lsquic_tg_new(&engine->pub);
 | 
			
		||||
    if (!engine->pub.enp_tokgen)
 | 
			
		||||
        return NULL;
 | 
			
		||||
    if (engine->flags & ENG_SERVER)
 | 
			
		||||
        for (i = 0; i < sizeof(engine->pub.enp_quic_ctx_sz)
 | 
			
		||||
                                / sizeof(engine->pub.enp_quic_ctx_sz[0]); ++i)
 | 
			
		||||
        {
 | 
			
		||||
            int sz = lsquic_enc_sess_ietf_gen_quic_ctx(
 | 
			
		||||
                        &engine->pub.enp_settings,
 | 
			
		||||
                        i == 0 ? LSQVER_ID27 : LSQVER_ID28,
 | 
			
		||||
                        engine->pub.enp_quic_ctx_buf[i],
 | 
			
		||||
                        sizeof(engine->pub.enp_quic_ctx_buf));
 | 
			
		||||
            if (sz < 0)
 | 
			
		||||
            {
 | 
			
		||||
                free(engine);
 | 
			
		||||
                return NULL;
 | 
			
		||||
            }
 | 
			
		||||
            engine->pub.enp_quic_ctx_sz[i] = (unsigned) sz;
 | 
			
		||||
        }
 | 
			
		||||
    engine->pub.enp_crand = &engine->crand;
 | 
			
		||||
    if (engine->pub.enp_settings.es_noprogress_timeout)
 | 
			
		||||
        engine->pub.enp_noprog_timeout
 | 
			
		||||
| 
						 | 
				
			
			@ -1106,6 +1122,34 @@ find_conn_by_addr (struct lsquic_hash *hash, const struct sockaddr *sa)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* When connections are identified by the local address, we need to drop
 | 
			
		||||
 * packets that use DCIDs that do not correspond to any of SCIDs.  This
 | 
			
		||||
 * can happen when peer retires a SCID.  This mimics the normal behavior,
 | 
			
		||||
 * when connections are looked up in engine->conns_hash by ID: when there
 | 
			
		||||
 * is no match, the packet is dropped.
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
dcid_checks_out (const struct lsquic_conn *conn, const lsquic_cid_t *dcid)
 | 
			
		||||
{
 | 
			
		||||
    const struct conn_cid_elem *cce;
 | 
			
		||||
 | 
			
		||||
    if (LSQUIC_CIDS_EQ(CN_SCID(conn), dcid))
 | 
			
		||||
        return 1;
 | 
			
		||||
 | 
			
		||||
    /* Slow check for those rare cases */
 | 
			
		||||
    for (cce = conn->cn_cces; cce < END_OF_CCES(conn); ++cce)
 | 
			
		||||
        if ((conn->cn_cces_mask & (1 << (cce - conn->cn_cces)))
 | 
			
		||||
                        && !(cce->cce_flags & CCE_PORT)
 | 
			
		||||
                        && LSQUIC_CIDS_EQ(&cce->cce_cid, dcid))
 | 
			
		||||
        {
 | 
			
		||||
            LSQ_DEBUG("connection checks out");
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static lsquic_conn_t *
 | 
			
		||||
find_conn (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
 | 
			
		||||
         struct packin_parse_state *ppstate, const struct sockaddr *sa_local)
 | 
			
		||||
| 
						 | 
				
			
			@ -1114,7 +1158,17 @@ find_conn (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
 | 
			
		|||
    lsquic_conn_t *conn;
 | 
			
		||||
 | 
			
		||||
    if (engine->flags & ENG_CONNS_BY_ADDR)
 | 
			
		||||
    {
 | 
			
		||||
        el = find_conn_by_addr(engine->conns_hash, sa_local);
 | 
			
		||||
        if ((packet_in->pi_flags & PI_CONN_ID)
 | 
			
		||||
                && !dcid_checks_out(lsquic_hashelem_getdata(el),
 | 
			
		||||
                                                    &packet_in->pi_conn_id))
 | 
			
		||||
        {
 | 
			
		||||
            LSQ_DEBUGC("DCID matches no SCID in connection %"CID_FMT": drop it",
 | 
			
		||||
                CID_BITS(&packet_in->pi_conn_id));
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else if (packet_in->pi_flags & PI_CONN_ID)
 | 
			
		||||
        el = lsquic_hash_find(engine->conns_hash,
 | 
			
		||||
                    packet_in->pi_conn_id.idbuf, packet_in->pi_conn_id.len);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -78,6 +78,11 @@ struct lsquic_engine_public {
 | 
			
		|||
    struct lsquic_hash             *enp_server_certs;
 | 
			
		||||
    /* gQUIC server configuration: */
 | 
			
		||||
    struct lsquic_server_config    *enp_server_config;
 | 
			
		||||
    /* Serialized subset of server engine transport parameters that is used
 | 
			
		||||
     * as SSL QUIC context.  0 is for version <= LSQVER_ID27, 1 is for others.
 | 
			
		||||
     */
 | 
			
		||||
    unsigned char                   enp_quic_ctx_buf[2][200];
 | 
			
		||||
    unsigned                        enp_quic_ctx_sz[2];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Put connection onto the Tickable Queue if it is not already on it.  If
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,6 +30,8 @@
 | 
			
		|||
#include "lsquic_frab_list.h"
 | 
			
		||||
#include "lsquic_ev_log.h"
 | 
			
		||||
 | 
			
		||||
#include "fiu-local.h"
 | 
			
		||||
 | 
			
		||||
#define LSQUIC_LOGGER_MODULE LSQLM_FRAME_WRITER
 | 
			
		||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(\
 | 
			
		||||
                                        lsquic_stream_conn(fw->fw_stream))
 | 
			
		||||
| 
						 | 
				
			
			@ -497,6 +499,8 @@ lsquic_frame_writer_write_promise (struct lsquic_frame_writer *fw,
 | 
			
		|||
    unsigned char *buf;
 | 
			
		||||
    int s;
 | 
			
		||||
 | 
			
		||||
    fiu_return_on("frame_writer/writer_promise", -1);
 | 
			
		||||
 | 
			
		||||
    if (fw->fw_max_header_list_sz && 0 != check_headers_size(fw, headers))
 | 
			
		||||
        return -1;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4156,10 +4156,15 @@ full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
 | 
			
		|||
    if (0 != lsquic_headers_stream_push_promise(conn->fc_pub.u.gquic.hs, dep_stream->id,
 | 
			
		||||
                                        pushed_stream->id, headers))
 | 
			
		||||
    {
 | 
			
		||||
        /* Since the failure to write to HEADERS stream results in aborting
 | 
			
		||||
         * the connection, we do not bother rolling back.
 | 
			
		||||
         */
 | 
			
		||||
        LSQ_ERROR("could not send push promise");
 | 
			
		||||
        /* If forget we ever had the hset pointer: */
 | 
			
		||||
        lsquic_stream_drop_hset_ref(pushed_stream);
 | 
			
		||||
        /* Now roll back stream creation and return stream ID: */
 | 
			
		||||
        if (pushed_stream->sm_hash_el.qhe_flags & QHE_HASHED)
 | 
			
		||||
            lsquic_hash_erase(conn->fc_pub.all_streams,
 | 
			
		||||
                                                &pushed_stream->sm_hash_el);
 | 
			
		||||
        lsquic_stream_destroy(pushed_stream);
 | 
			
		||||
        conn->fc_last_stream_id -= 2;
 | 
			
		||||
        LSQ_INFO("could not send push promise");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -137,7 +137,7 @@ enum ifull_conn_flags
 | 
			
		|||
    IFC_IGNORE_HSK    = 1 << 25,
 | 
			
		||||
    IFC_PROC_CRYPTO   = 1 << 26,
 | 
			
		||||
    IFC_MIGRA         = 1 << 27,
 | 
			
		||||
    IFC_UNUSED28      = 1 << 28, /* Unused */
 | 
			
		||||
    IFC_HTTP_INITED   = 1 << 28, /* HTTP initialized */
 | 
			
		||||
    IFC_DELAYED_ACKS  = 1 << 29, /* Delayed ACKs are enabled */
 | 
			
		||||
    IFC_TIMESTAMPS    = 1 << 30, /* Timestamps are enabled */
 | 
			
		||||
    IFC_DATAGRAMS     = 1u<< 31, /* Datagrams are enabled */
 | 
			
		||||
| 
						 | 
				
			
			@ -153,6 +153,7 @@ enum more_flags
 | 
			
		|||
    MF_CONN_CLOSE_PACK  = 1 << 4,   /* CONNECTION_CLOSE has been packetized */
 | 
			
		||||
    MF_SEND_WRONG_COUNTS= 1 << 5,   /* Send wrong ECN counts to peer */
 | 
			
		||||
    MF_WANT_DATAGRAM_WRITE  = 1 << 6,
 | 
			
		||||
    MF_DOING_0RTT       = 1 << 7,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -568,6 +569,12 @@ find_cce_by_cid (struct ietf_full_conn *, const lsquic_cid_t *);
 | 
			
		|||
static void
 | 
			
		||||
mtu_probe_too_large (struct ietf_full_conn *, const struct lsquic_packet_out *);
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
apply_trans_params (struct ietf_full_conn *, const struct transport_params *);
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
init_http (struct ietf_full_conn *);
 | 
			
		||||
 | 
			
		||||
static unsigned
 | 
			
		||||
highest_bit_set (unsigned sz)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1252,7 +1259,7 @@ ietf_full_conn_init (struct ietf_full_conn *conn,
 | 
			
		|||
    conn->ifc_peer_hq_settings.header_table_size     = HQ_DF_QPACK_MAX_TABLE_CAPACITY;
 | 
			
		||||
    conn->ifc_peer_hq_settings.qpack_blocked_streams = HQ_DF_QPACK_BLOCKED_STREAMS;
 | 
			
		||||
 | 
			
		||||
    conn->ifc_flags = flags | IFC_CREATED_OK | IFC_FIRST_TICK;
 | 
			
		||||
    conn->ifc_flags = flags | IFC_FIRST_TICK;
 | 
			
		||||
    conn->ifc_max_ack_packno[PNS_INIT] = IQUIC_INVALID_PACKNO;
 | 
			
		||||
    conn->ifc_max_ack_packno[PNS_HSK] = IQUIC_INVALID_PACKNO;
 | 
			
		||||
    conn->ifc_max_ack_packno[PNS_APP] = IQUIC_INVALID_PACKNO;
 | 
			
		||||
| 
						 | 
				
			
			@ -1282,6 +1289,7 @@ lsquic_ietf_full_conn_client_new (struct lsquic_engine_public *enpub,
 | 
			
		|||
           const unsigned char *sess_resume, size_t sess_resume_sz,
 | 
			
		||||
           const unsigned char *token, size_t token_sz)
 | 
			
		||||
{
 | 
			
		||||
    const struct transport_params *params;
 | 
			
		||||
    const struct enc_session_funcs_iquic *esfi;
 | 
			
		||||
    struct ietf_full_conn *conn;
 | 
			
		||||
    enum lsquic_version ver, sess_resume_version;
 | 
			
		||||
| 
						 | 
				
			
			@ -1397,6 +1405,18 @@ lsquic_ietf_full_conn_client_new (struct lsquic_engine_public *enpub,
 | 
			
		|||
    conn->ifc_created = now;
 | 
			
		||||
    LSQ_DEBUG("logging using %s SCID",
 | 
			
		||||
        LSQUIC_LOG_CONN_ID == CN_SCID(&conn->ifc_conn) ? "client" : "server");
 | 
			
		||||
    if (sess_resume && (params
 | 
			
		||||
            = conn->ifc_conn.cn_esf.i->esfi_get_peer_transport_params(
 | 
			
		||||
                            conn->ifc_conn.cn_enc_session), params != NULL))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_DEBUG("initializing transport parameters for 0RTT");
 | 
			
		||||
        if (0 != apply_trans_params(conn, params))
 | 
			
		||||
            goto full_err;
 | 
			
		||||
        if ((conn->ifc_flags & IFC_HTTP) && 0 != init_http(conn))
 | 
			
		||||
            goto full_err;
 | 
			
		||||
        conn->ifc_mflags |= MF_DOING_0RTT;
 | 
			
		||||
    }
 | 
			
		||||
    conn->ifc_flags |= IFC_CREATED_OK;
 | 
			
		||||
    return &conn->ifc_conn;
 | 
			
		||||
 | 
			
		||||
  err4:
 | 
			
		||||
| 
						 | 
				
			
			@ -1411,6 +1431,10 @@ lsquic_ietf_full_conn_client_new (struct lsquic_engine_public *enpub,
 | 
			
		|||
    free(conn);
 | 
			
		||||
  err0:
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  full_err:
 | 
			
		||||
    ietf_full_conn_ci_destroy(&conn->ifc_conn);
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1635,6 +1659,7 @@ lsquic_ietf_full_conn_server_new (struct lsquic_engine_public *enpub,
 | 
			
		|||
 | 
			
		||||
    LSQ_DEBUG("logging using %s SCID",
 | 
			
		||||
        LSQUIC_LOG_CONN_ID == CN_SCID(&conn->ifc_conn) ? "server" : "client");
 | 
			
		||||
    conn->ifc_flags |= IFC_CREATED_OK;
 | 
			
		||||
    return &conn->ifc_conn;
 | 
			
		||||
 | 
			
		||||
  err3:
 | 
			
		||||
| 
						 | 
				
			
			@ -3317,35 +3342,13 @@ maybe_start_migration (struct ietf_full_conn *conn)
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handshake_ok (struct lsquic_conn *lconn)
 | 
			
		||||
apply_trans_params (struct ietf_full_conn *conn,
 | 
			
		||||
                                        const struct transport_params *params)
 | 
			
		||||
{
 | 
			
		||||
    struct ietf_full_conn *const conn = (struct ietf_full_conn *) lconn;
 | 
			
		||||
    struct lsquic_stream *stream;
 | 
			
		||||
    struct lsquic_hash_elem *el;
 | 
			
		||||
    struct dcid_elem *dce;
 | 
			
		||||
    const struct transport_params *params;
 | 
			
		||||
    enum stream_id_type sit;
 | 
			
		||||
    uint64_t limit;
 | 
			
		||||
    char buf[MAX_TP_STR_SZ];
 | 
			
		||||
 | 
			
		||||
    fiu_return_on("full_conn_ietf/handshake_ok", -1);
 | 
			
		||||
 | 
			
		||||
    /* Need to set this flag even we hit an error in the rest of this funciton.
 | 
			
		||||
     * This is because this flag is used to calculate packet out header size
 | 
			
		||||
     */
 | 
			
		||||
    lconn->cn_flags |= LSCONN_HANDSHAKE_DONE;
 | 
			
		||||
 | 
			
		||||
    params = lconn->cn_esf.i->esfi_get_peer_transport_params(
 | 
			
		||||
                                                        lconn->cn_enc_session);
 | 
			
		||||
    if (!params)
 | 
			
		||||
    {
 | 
			
		||||
        ABORT_WARN("could not get transport parameters");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LSQ_DEBUG("peer transport parameters: %s",
 | 
			
		||||
                    ((lconn->cn_version == LSQVER_ID27 ? lsquic_tp_to_str_27
 | 
			
		||||
                    : lsquic_tp_to_str)(params, buf, sizeof(buf)), buf));
 | 
			
		||||
 | 
			
		||||
    if ((params->tp_set & (1 << TPI_LOSS_BITS))
 | 
			
		||||
                                    && conn->ifc_settings->es_ql_bits == 2)
 | 
			
		||||
| 
						 | 
				
			
			@ -3487,6 +3490,104 @@ handshake_ok (struct lsquic_conn *lconn)
 | 
			
		|||
                                                CUR_NPATH(conn)->np_pack_size);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (params->tp_active_connection_id_limit > conn->ifc_conn.cn_n_cces)
 | 
			
		||||
        conn->ifc_active_cids_limit = conn->ifc_conn.cn_n_cces;
 | 
			
		||||
    else
 | 
			
		||||
        conn->ifc_active_cids_limit = params->tp_active_connection_id_limit;
 | 
			
		||||
    conn->ifc_first_active_cid_seqno = conn->ifc_scid_seqno;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
init_http (struct ietf_full_conn *conn)
 | 
			
		||||
{
 | 
			
		||||
    fiu_return_on("full_conn_ietf/init_http", -1);
 | 
			
		||||
    lsquic_qeh_init(&conn->ifc_qeh, &conn->ifc_conn);
 | 
			
		||||
    if (0 == avail_streams_count(conn, conn->ifc_flags & IFC_SERVER,
 | 
			
		||||
                                                                SD_UNI))
 | 
			
		||||
    {
 | 
			
		||||
        ABORT_QUIETLY(1, HEC_GENERAL_PROTOCOL_ERROR, "cannot create "
 | 
			
		||||
                            "control stream due to peer-imposed limit");
 | 
			
		||||
        conn->ifc_error = CONN_ERR(1, HEC_GENERAL_PROTOCOL_ERROR);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    if (0 != create_ctl_stream_out(conn))
 | 
			
		||||
    {
 | 
			
		||||
        ABORT_WARN("cannot create outgoing control stream");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    if (0 != lsquic_hcso_write_settings(&conn->ifc_hcso,
 | 
			
		||||
            &conn->ifc_enpub->enp_settings, conn->ifc_flags & IFC_SERVER))
 | 
			
		||||
    {
 | 
			
		||||
        ABORT_WARN("cannot write SETTINGS");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    if (!(conn->ifc_flags & IFC_SERVER)
 | 
			
		||||
        && (conn->ifc_u.cli.ifcli_flags & IFCLI_PUSH_ENABLED)
 | 
			
		||||
        && 0 != lsquic_hcso_write_max_push_id(&conn->ifc_hcso,
 | 
			
		||||
                                        conn->ifc_u.cli.ifcli_max_push_id))
 | 
			
		||||
    {
 | 
			
		||||
        ABORT_WARN("cannot write MAX_PUSH_ID");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    if (0 != lsquic_qdh_init(&conn->ifc_qdh, &conn->ifc_conn,
 | 
			
		||||
                            conn->ifc_flags & IFC_SERVER, conn->ifc_enpub,
 | 
			
		||||
                            conn->ifc_settings->es_qpack_dec_max_size,
 | 
			
		||||
                            conn->ifc_settings->es_qpack_dec_max_blocked))
 | 
			
		||||
    {
 | 
			
		||||
        ABORT_WARN("cannot initialize QPACK decoder");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    if (avail_streams_count(conn, conn->ifc_flags & IFC_SERVER, SD_UNI) > 0)
 | 
			
		||||
    {
 | 
			
		||||
        if (0 != create_qdec_stream_out(conn))
 | 
			
		||||
        {
 | 
			
		||||
            ABORT_WARN("cannot create outgoing QPACK decoder stream");
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        queue_streams_blocked_frame(conn, SD_UNI);
 | 
			
		||||
        LSQ_DEBUG("cannot create outgoing QPACK decoder stream due to "
 | 
			
		||||
            "unidir limits");
 | 
			
		||||
    }
 | 
			
		||||
    conn->ifc_flags |= IFC_HTTP_INITED;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handshake_ok (struct lsquic_conn *lconn)
 | 
			
		||||
{
 | 
			
		||||
    struct ietf_full_conn *const conn = (struct ietf_full_conn *) lconn;
 | 
			
		||||
    struct dcid_elem *dce;
 | 
			
		||||
    const struct transport_params *params;
 | 
			
		||||
    char buf[MAX_TP_STR_SZ];
 | 
			
		||||
 | 
			
		||||
    fiu_return_on("full_conn_ietf/handshake_ok", -1);
 | 
			
		||||
 | 
			
		||||
    /* Need to set this flag even we hit an error in the rest of this funciton.
 | 
			
		||||
     * This is because this flag is used to calculate packet out header size
 | 
			
		||||
     */
 | 
			
		||||
    lconn->cn_flags |= LSCONN_HANDSHAKE_DONE;
 | 
			
		||||
 | 
			
		||||
    params = lconn->cn_esf.i->esfi_get_peer_transport_params(
 | 
			
		||||
                                                        lconn->cn_enc_session);
 | 
			
		||||
    if (!params)
 | 
			
		||||
    {
 | 
			
		||||
        ABORT_WARN("could not get transport parameters");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LSQ_DEBUG("peer transport parameters: %s",
 | 
			
		||||
                    ((lconn->cn_version == LSQVER_ID27 ? lsquic_tp_to_str_27
 | 
			
		||||
                    : lsquic_tp_to_str)(params, buf, sizeof(buf)), buf));
 | 
			
		||||
    if (0 != apply_trans_params(conn, params))
 | 
			
		||||
        return -1;
 | 
			
		||||
 | 
			
		||||
    dce = get_new_dce(conn);
 | 
			
		||||
    if (!dce)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -3518,65 +3619,9 @@ handshake_ok (struct lsquic_conn *lconn)
 | 
			
		|||
 | 
			
		||||
    LSQ_INFO("applied peer transport parameters");
 | 
			
		||||
 | 
			
		||||
    if (conn->ifc_flags & IFC_HTTP)
 | 
			
		||||
    {
 | 
			
		||||
        lsquic_qeh_init(&conn->ifc_qeh, &conn->ifc_conn);
 | 
			
		||||
        if (0 == avail_streams_count(conn, conn->ifc_flags & IFC_SERVER,
 | 
			
		||||
                                                                    SD_UNI))
 | 
			
		||||
        {
 | 
			
		||||
            ABORT_QUIETLY(1, HEC_GENERAL_PROTOCOL_ERROR, "cannot create "
 | 
			
		||||
                                "control stream due to peer-imposed limit");
 | 
			
		||||
            conn->ifc_error = CONN_ERR(1, HEC_GENERAL_PROTOCOL_ERROR);
 | 
			
		||||
    if ((conn->ifc_flags & (IFC_HTTP|IFC_HTTP_INITED)) == IFC_HTTP)
 | 
			
		||||
        if (0 != init_http(conn))
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        if (0 != create_ctl_stream_out(conn))
 | 
			
		||||
        {
 | 
			
		||||
            ABORT_WARN("cannot create outgoing control stream");
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        if (0 != lsquic_hcso_write_settings(&conn->ifc_hcso,
 | 
			
		||||
                &conn->ifc_enpub->enp_settings, conn->ifc_flags & IFC_SERVER))
 | 
			
		||||
        {
 | 
			
		||||
            ABORT_WARN("cannot write SETTINGS");
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        if (!(conn->ifc_flags & IFC_SERVER)
 | 
			
		||||
            && (conn->ifc_u.cli.ifcli_flags & IFCLI_PUSH_ENABLED)
 | 
			
		||||
            && 0 != lsquic_hcso_write_max_push_id(&conn->ifc_hcso,
 | 
			
		||||
                                            conn->ifc_u.cli.ifcli_max_push_id))
 | 
			
		||||
        {
 | 
			
		||||
            ABORT_WARN("cannot write MAX_PUSH_ID");
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        if (0 != lsquic_qdh_init(&conn->ifc_qdh, &conn->ifc_conn,
 | 
			
		||||
                                conn->ifc_flags & IFC_SERVER, conn->ifc_enpub,
 | 
			
		||||
                                conn->ifc_settings->es_qpack_dec_max_size,
 | 
			
		||||
                                conn->ifc_settings->es_qpack_dec_max_blocked))
 | 
			
		||||
        {
 | 
			
		||||
            ABORT_WARN("cannot initialize QPACK decoder");
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        if (avail_streams_count(conn, conn->ifc_flags & IFC_SERVER, SD_UNI) > 0)
 | 
			
		||||
        {
 | 
			
		||||
            if (0 != create_qdec_stream_out(conn))
 | 
			
		||||
            {
 | 
			
		||||
                ABORT_WARN("cannot create outgoing QPACK decoder stream");
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            queue_streams_blocked_frame(conn, SD_UNI);
 | 
			
		||||
            LSQ_DEBUG("cannot create outgoing QPACK decoder stream due to "
 | 
			
		||||
                "unidir limits");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (params->tp_active_connection_id_limit > conn->ifc_conn.cn_n_cces)
 | 
			
		||||
        conn->ifc_active_cids_limit = conn->ifc_conn.cn_n_cces;
 | 
			
		||||
    else
 | 
			
		||||
        conn->ifc_active_cids_limit = params->tp_active_connection_id_limit;
 | 
			
		||||
    conn->ifc_first_active_cid_seqno = conn->ifc_scid_seqno;
 | 
			
		||||
 | 
			
		||||
    if (conn->ifc_settings->es_dplpmtud)
 | 
			
		||||
        conn->ifc_mflags |= MF_CHECK_MTU_PROBE;
 | 
			
		||||
| 
						 | 
				
			
			@ -3585,6 +3630,9 @@ handshake_ok (struct lsquic_conn *lconn)
 | 
			
		|||
        conn->ifc_send_flags |= SF_SEND_NEW_CID;
 | 
			
		||||
    maybe_create_delayed_streams(conn);
 | 
			
		||||
 | 
			
		||||
    if (!(conn->ifc_flags & IFC_SERVER))
 | 
			
		||||
        lsquic_send_ctl_0rtt_to_1rtt(&conn->ifc_send_ctl);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3615,10 +3663,10 @@ ietf_full_conn_ci_hsk_done (struct lsquic_conn *lconn,
 | 
			
		|||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
    case LSQ_HSK_RESUMED_FAIL:  /* IETF crypto never returns this */
 | 
			
		||||
        assert(0);
 | 
			
		||||
        /* fall-through */
 | 
			
		||||
    case LSQ_HSK_FAIL:
 | 
			
		||||
    case LSQ_HSK_RESUMED_FAIL:
 | 
			
		||||
        handshake_failed(lconn);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -7406,6 +7454,7 @@ check_or_schedule_mtu_probe (struct ietf_full_conn *conn, lsquic_time_t now)
 | 
			
		|||
 | 
			
		||||
    if (!(conn->ifc_conn.cn_flags & LSCONN_HANDSHAKE_DONE)
 | 
			
		||||
        || (conn->ifc_flags & IFC_CLOSING)
 | 
			
		||||
        || ~0ull == lsquic_senhist_largest(&conn->ifc_send_ctl.sc_senhist)
 | 
			
		||||
        || lsquic_senhist_largest(&conn->ifc_send_ctl.sc_senhist) < 30
 | 
			
		||||
        || lsquic_send_ctl_in_recovery(&conn->ifc_send_ctl)
 | 
			
		||||
        || !lsquic_send_ctl_can_send_probe(&conn->ifc_send_ctl,
 | 
			
		||||
| 
						 | 
				
			
			@ -7594,6 +7643,16 @@ ietf_full_conn_ci_retx_timeout (struct lsquic_conn *lconn)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
ietf_full_conn_ci_early_data_failed (struct lsquic_conn *lconn)
 | 
			
		||||
{
 | 
			
		||||
    struct ietf_full_conn *conn = (struct ietf_full_conn *) lconn;
 | 
			
		||||
 | 
			
		||||
    LSQ_DEBUG("early data failed");
 | 
			
		||||
    lsquic_send_ctl_stash_0rtt_packets(&conn->ifc_send_ctl);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static size_t
 | 
			
		||||
ietf_full_conn_ci_get_min_datagram_size (struct lsquic_conn *lconn)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -7830,7 +7889,8 @@ ietf_full_conn_ci_tick (struct lsquic_conn *lconn, lsquic_time_t now)
 | 
			
		|||
        conn->ifc_flags |= (s < 0) << IFC_BIT_ERROR;
 | 
			
		||||
        if (0 == s)
 | 
			
		||||
            process_crypto_stream_write_events(conn);
 | 
			
		||||
        goto end_write;
 | 
			
		||||
        if (!(conn->ifc_mflags & MF_DOING_0RTT))
 | 
			
		||||
            goto end_write;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    maybe_conn_flush_special_streams(conn);
 | 
			
		||||
| 
						 | 
				
			
			@ -8279,6 +8339,7 @@ ietf_full_conn_ci_count_garbage (struct lsquic_conn *lconn, size_t garbage_sz)
 | 
			
		|||
    .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_early_data_failed    =  ietf_full_conn_ci_early_data_failed, \
 | 
			
		||||
    .ci_get_engine           =  ietf_full_conn_ci_get_engine, \
 | 
			
		||||
    .ci_get_log_cid          =  ietf_full_conn_ci_get_log_cid, \
 | 
			
		||||
    .ci_get_min_datagram_size=  ietf_full_conn_ci_get_min_datagram_size, \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,7 +88,7 @@ is_valid_gquic_hs_packet (const unsigned char *buf, size_t bufsz,
 | 
			
		|||
 | 
			
		||||
int
 | 
			
		||||
lsquic_is_valid_hs_packet (struct lsquic_engine *engine,
 | 
			
		||||
                const unsigned char *buf, size_t bufsz, size_t packet_in_sz)
 | 
			
		||||
                                    const unsigned char *buf, size_t bufsz)
 | 
			
		||||
{
 | 
			
		||||
    lsquic_ver_tag_t tag;
 | 
			
		||||
    int is_valid;
 | 
			
		||||
| 
						 | 
				
			
			@ -104,7 +104,7 @@ lsquic_is_valid_hs_packet (struct lsquic_engine *engine,
 | 
			
		|||
    case 0x80|0x00|0x20|0x10|0x08:
 | 
			
		||||
    case 0x80|0x40|0x20|0x10|0x00:
 | 
			
		||||
    case 0x80|0x00|0x20|0x10|0x00:
 | 
			
		||||
        is_valid = packet_in_sz >= IQUIC_MIN_INIT_PACKET_SZ
 | 
			
		||||
        is_valid = bufsz >= IQUIC_MIN_INIT_PACKET_SZ
 | 
			
		||||
            && lsquic_is_valid_iquic_hs_packet(buf, bufsz, &tag);
 | 
			
		||||
        break;
 | 
			
		||||
    /* 1X00 XGGG: ID-22 long header */
 | 
			
		||||
| 
						 | 
				
			
			@ -122,7 +122,7 @@ 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 = packet_in_sz >= IQUIC_MIN_INIT_PACKET_SZ
 | 
			
		||||
        is_valid = bufsz >= IQUIC_MIN_INIT_PACKET_SZ
 | 
			
		||||
            && lsquic_is_valid_ietf_v1_or_Q046plus_hs_packet(buf, bufsz, &tag);
 | 
			
		||||
        break;
 | 
			
		||||
    /* 01XX XGGG: ID-22 short header */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@
 | 
			
		|||
#include <assert.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -560,6 +561,16 @@ lsquic_mini_conn_ietf_new (struct lsquic_engine_public *enpub,
 | 
			
		|||
    TAILQ_INIT(&conn->imc_crypto_frames);
 | 
			
		||||
    if (odcid)
 | 
			
		||||
        imico_peer_addr_validated(conn, "odcid");
 | 
			
		||||
#if LSQUIC_DEVEL
 | 
			
		||||
    {
 | 
			
		||||
        const char *const s = getenv("LSQUIC_LOSE_0RTT");
 | 
			
		||||
        if (s && atoi(s))
 | 
			
		||||
        {
 | 
			
		||||
            LSQ_DEBUG("will lose 0-RTT packets (via env variable)");
 | 
			
		||||
            conn->imc_delayed_packets_count = UCHAR_MAX;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    LSQ_DEBUG("created mini connection object %p; max packet size=%hu",
 | 
			
		||||
                                                conn, conn->imc_path.np_pack_size);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2163,11 +2163,11 @@ ietf_v1_parse_datagram_frame (const unsigned char *buf, size_t buf_len,
 | 
			
		|||
    if (buf[0] & 1)
 | 
			
		||||
    {
 | 
			
		||||
        s = vint_read(buf + 1, buf + buf_len, &len);
 | 
			
		||||
        if (s > 0 && 1 + s + len >= buf_len)
 | 
			
		||||
        if (s > 0 && 1 + s + len <= buf_len)
 | 
			
		||||
        {
 | 
			
		||||
            *data = buf + 1 + s;
 | 
			
		||||
            *data_len = len;
 | 
			
		||||
            return 1 + buf_len + len;
 | 
			
		||||
            return 1 + s + len;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            return -1;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -338,6 +338,7 @@ lsquic_send_ctl_init (lsquic_send_ctl_t *ctl, struct lsquic_alarmset *alset,
 | 
			
		|||
    TAILQ_INIT(&ctl->sc_unacked_packets[PNS_HSK]);
 | 
			
		||||
    TAILQ_INIT(&ctl->sc_unacked_packets[PNS_APP]);
 | 
			
		||||
    TAILQ_INIT(&ctl->sc_lost_packets);
 | 
			
		||||
    TAILQ_INIT(&ctl->sc_0rtt_stash);
 | 
			
		||||
    ctl->sc_enpub = enpub;
 | 
			
		||||
    ctl->sc_alset = alset;
 | 
			
		||||
    ctl->sc_ver_neg = ver_neg;
 | 
			
		||||
| 
						 | 
				
			
			@ -1463,6 +1464,11 @@ lsquic_send_ctl_cleanup (lsquic_send_ctl_t *ctl)
 | 
			
		|||
        packet_out->po_flags &= ~PO_LOST;
 | 
			
		||||
        send_ctl_destroy_packet(ctl, packet_out);
 | 
			
		||||
    }
 | 
			
		||||
    while ((packet_out = TAILQ_FIRST(&ctl->sc_0rtt_stash)))
 | 
			
		||||
    {
 | 
			
		||||
        TAILQ_REMOVE(&ctl->sc_0rtt_stash, packet_out, po_next);
 | 
			
		||||
        send_ctl_destroy_packet(ctl, packet_out);
 | 
			
		||||
    }
 | 
			
		||||
    for (n = 0; n < sizeof(ctl->sc_buffered_packets) /
 | 
			
		||||
                                sizeof(ctl->sc_buffered_packets[0]); ++n)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -3795,3 +3801,72 @@ lsquic_send_ctl_rollback (struct lsquic_send_ctl *ctl,
 | 
			
		|||
    if (buffered && (lost_types & QUIC_FTBIT_ACK))
 | 
			
		||||
        lconn->cn_if->ci_ack_rollback(lconn, &ctl_state->ack_state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Find 0-RTT packets and change them to 1-RTT packets */
 | 
			
		||||
void
 | 
			
		||||
lsquic_send_ctl_0rtt_to_1rtt (struct lsquic_send_ctl *ctl)
 | 
			
		||||
{
 | 
			
		||||
    struct lsquic_packet_out *packet_out;
 | 
			
		||||
    unsigned count;
 | 
			
		||||
    struct lsquic_packets_tailq *const *q;
 | 
			
		||||
    struct lsquic_packets_tailq *const queues[] = {
 | 
			
		||||
        &ctl->sc_scheduled_packets,
 | 
			
		||||
        &ctl->sc_unacked_packets[PNS_APP],
 | 
			
		||||
        &ctl->sc_lost_packets,
 | 
			
		||||
        &ctl->sc_buffered_packets[0].bpq_packets,
 | 
			
		||||
        &ctl->sc_buffered_packets[1].bpq_packets,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    assert(ctl->sc_flags & SC_IETF);
 | 
			
		||||
 | 
			
		||||
    while (packet_out = TAILQ_FIRST(&ctl->sc_0rtt_stash), packet_out != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        TAILQ_REMOVE(&ctl->sc_0rtt_stash, packet_out, po_next);
 | 
			
		||||
        TAILQ_INSERT_TAIL(&ctl->sc_lost_packets, packet_out, po_next);
 | 
			
		||||
        packet_out->po_flags |= PO_LOST;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    count = 0;
 | 
			
		||||
    for (q = queues; q < queues + sizeof(queues) / sizeof(queues[0]); ++q)
 | 
			
		||||
        TAILQ_FOREACH(packet_out, *q, po_next)
 | 
			
		||||
            if (packet_out->po_header_type == HETY_0RTT)
 | 
			
		||||
            {
 | 
			
		||||
                ++count;
 | 
			
		||||
                packet_out->po_header_type = HETY_NOT_SET;
 | 
			
		||||
                if (packet_out->po_flags & PO_ENCRYPTED)
 | 
			
		||||
                    send_ctl_return_enc_data(ctl, packet_out);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
    LSQ_DEBUG("handshake ok: changed %u packet%.*s from 0-RTT to 1-RTT",
 | 
			
		||||
                                                    count, count != 1, "s");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Remove 0-RTT packets from the unacked queue and wait to retransmit them
 | 
			
		||||
 * after handshake succeeds.  This is the most common case.  There could
 | 
			
		||||
 * (theoretically) be some corner cases where 0-RTT packets are in the
 | 
			
		||||
 * scheduled queue, but we let those be lost naturally if that occurs.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
lsquic_send_ctl_stash_0rtt_packets (struct lsquic_send_ctl *ctl)
 | 
			
		||||
{
 | 
			
		||||
    struct lsquic_packet_out *packet_out, *next;
 | 
			
		||||
    unsigned count, packet_sz;
 | 
			
		||||
 | 
			
		||||
    count = 0;
 | 
			
		||||
    for (packet_out = TAILQ_FIRST(&ctl->sc_unacked_packets[PNS_APP]);
 | 
			
		||||
                                                packet_out; packet_out = next)
 | 
			
		||||
    {
 | 
			
		||||
        next = TAILQ_NEXT(packet_out, po_next);
 | 
			
		||||
        if (packet_out->po_header_type == HETY_0RTT)
 | 
			
		||||
        {
 | 
			
		||||
            packet_sz = packet_out_sent_sz(packet_out);
 | 
			
		||||
            send_ctl_unacked_remove(ctl, packet_out, packet_sz);
 | 
			
		||||
            TAILQ_INSERT_TAIL(&ctl->sc_0rtt_stash, packet_out, po_next);
 | 
			
		||||
            ++count;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LSQ_DEBUG("stashed %u 0-RTT packet%.*s", count, count != 1, "s");
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -87,6 +87,7 @@ typedef struct lsquic_send_ctl {
 | 
			
		|||
 | 
			
		||||
    /* Second section: everything else. */
 | 
			
		||||
    struct lsquic_packets_tailq     sc_scheduled_packets,
 | 
			
		||||
                                    sc_0rtt_stash,
 | 
			
		||||
                                    sc_lost_packets;
 | 
			
		||||
    struct buf_packet_q             sc_buffered_packets[BPT_OTHER_PRIO + 1];
 | 
			
		||||
    const struct ver_neg           *sc_ver_neg;
 | 
			
		||||
| 
						 | 
				
			
			@ -431,4 +432,10 @@ void
 | 
			
		|||
lsquic_send_ctl_rollback (struct lsquic_send_ctl *, struct send_ctl_state *,
 | 
			
		||||
                                                const struct iovec *, size_t);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_send_ctl_0rtt_to_1rtt (struct lsquic_send_ctl *);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_send_ctl_stash_0rtt_packets (struct lsquic_send_ctl *);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -373,6 +373,39 @@ stream_is_hsk (const struct lsquic_stream *stream)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* This function's only job is to change the allocated packet's header
 | 
			
		||||
 * type to HETY_0RTT when stream frames are written before handshake
 | 
			
		||||
 * is complete.
 | 
			
		||||
 */
 | 
			
		||||
static struct lsquic_packet_out *
 | 
			
		||||
stream_get_packet_for_stream_0rtt (struct lsquic_send_ctl *ctl,
 | 
			
		||||
                unsigned need_at_least, const struct network_path *path,
 | 
			
		||||
                const struct lsquic_stream *stream)
 | 
			
		||||
{
 | 
			
		||||
    struct lsquic_packet_out *packet_out;
 | 
			
		||||
 | 
			
		||||
    if (stream->conn_pub->lconn->cn_flags & LSCONN_HANDSHAKE_DONE)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_DEBUG("switch to regular \"get packet for stream\" function");
 | 
			
		||||
        /* Here we drop the "const" because this is a static function.
 | 
			
		||||
         * Otherwise, we would not condone such sorcery.
 | 
			
		||||
         */
 | 
			
		||||
        ((struct lsquic_stream *) stream)->sm_get_packet_for_stream
 | 
			
		||||
                                = lsquic_send_ctl_get_packet_for_stream;
 | 
			
		||||
        return lsquic_send_ctl_get_packet_for_stream(ctl, need_at_least,
 | 
			
		||||
                                                            path, stream);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        packet_out = lsquic_send_ctl_get_packet_for_stream(ctl, need_at_least,
 | 
			
		||||
                                                            path, stream);
 | 
			
		||||
        if (packet_out)
 | 
			
		||||
            packet_out->po_header_type = HETY_0RTT;
 | 
			
		||||
        return packet_out;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static struct lsquic_stream *
 | 
			
		||||
stream_new_common (lsquic_stream_id_t id, struct lsquic_conn_public *conn_pub,
 | 
			
		||||
           const struct lsquic_stream_if *stream_if, void *stream_if_ctx,
 | 
			
		||||
| 
						 | 
				
			
			@ -405,6 +438,7 @@ stream_new_common (lsquic_stream_id_t id, struct lsquic_conn_public *conn_pub,
 | 
			
		|||
    stream->sm_bflags |= ctor_flags & ((1 << N_SMBF_FLAGS) - 1);
 | 
			
		||||
    if (conn_pub->lconn->cn_flags & LSCONN_SERVER)
 | 
			
		||||
        stream->sm_bflags |= SMBF_SERVER;
 | 
			
		||||
    stream->sm_get_packet_for_stream = lsquic_send_ctl_get_packet_for_stream;
 | 
			
		||||
 | 
			
		||||
    return stream;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -479,6 +513,13 @@ lsquic_stream_new (lsquic_stream_id_t id,
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((stream->sm_bflags & (SMBF_SERVER|SMBF_IETF)) == SMBF_IETF
 | 
			
		||||
                    && !(conn_pub->lconn->cn_flags & LSCONN_HANDSHAKE_DONE))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_DEBUG("use wrapper \"get packet for stream\" function");
 | 
			
		||||
        stream->sm_get_packet_for_stream = stream_get_packet_for_stream_0rtt;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    lsquic_sfcw_init(&stream->fc, initial_window, cfcw, conn_pub, id);
 | 
			
		||||
    stream->max_send_off = initial_send_off;
 | 
			
		||||
    LSQ_DEBUG("created stream");
 | 
			
		||||
| 
						 | 
				
			
			@ -584,6 +625,14 @@ drop_buffered_data (struct lsquic_stream *stream)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_stream_drop_hset_ref (struct lsquic_stream *stream)
 | 
			
		||||
{
 | 
			
		||||
    if (stream->uh)
 | 
			
		||||
        stream->uh->uh_hset = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
destroy_uh (struct lsquic_stream *stream)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -3087,7 +3136,7 @@ stream_write_to_packet_std (struct frame_gen_ctx *fg_ctx, const size_t size)
 | 
			
		|||
    else
 | 
			
		||||
        need_at_least += size > 0;
 | 
			
		||||
  get_packet:
 | 
			
		||||
    packet_out = lsquic_send_ctl_get_packet_for_stream(send_ctl,
 | 
			
		||||
    packet_out = stream->sm_get_packet_for_stream(send_ctl,
 | 
			
		||||
                                need_at_least, stream->conn_pub->path, stream);
 | 
			
		||||
    if (packet_out)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,6 +17,9 @@ struct data_frame;
 | 
			
		|||
enum quic_frame_type;
 | 
			
		||||
struct push_promise;
 | 
			
		||||
union hblock_ctx;
 | 
			
		||||
struct lsquic_packet_out;
 | 
			
		||||
struct lsquic_send_ctl;
 | 
			
		||||
struct network_path;
 | 
			
		||||
 | 
			
		||||
TAILQ_HEAD(lsquic_streams_tailq, lsquic_stream);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -311,6 +314,11 @@ struct lsquic_stream
 | 
			
		|||
    size_t                        (*sm_write_avail)(struct lsquic_stream *);
 | 
			
		||||
    int                           (*sm_readable)(struct lsquic_stream *);
 | 
			
		||||
 | 
			
		||||
    struct lsquic_packet_out *    (*sm_get_packet_for_stream)(
 | 
			
		||||
                                        struct lsquic_send_ctl *,
 | 
			
		||||
                                        unsigned, const struct network_path *,
 | 
			
		||||
                                        const struct lsquic_stream *);
 | 
			
		||||
 | 
			
		||||
    /* This element is optional */
 | 
			
		||||
    const struct stream_filter_if  *sm_sfi;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -622,4 +630,7 @@ void
 | 
			
		|||
lsquic_stream_set_pwritev_params (unsigned iovecs, unsigned frames);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_stream_drop_hset_ref (struct lsquic_stream *);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -184,4 +184,26 @@ size_t
 | 
			
		|||
lsquic_tp_get_quantum_sz (void);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define SERVER_0RTT_TPS                                              (0 \
 | 
			
		||||
    /* [draft-ietf-quic-transport-31] Section 7.4.1: */                 \
 | 
			
		||||
    | (1 << TPI_ACTIVE_CONNECTION_ID_LIMIT)                             \
 | 
			
		||||
    | (1 << TPI_INIT_MAX_DATA)                                          \
 | 
			
		||||
    | (1 << TPI_INIT_MAX_STREAMS_UNI)                                   \
 | 
			
		||||
    | (1 << TPI_INIT_MAX_STREAMS_BIDI)                                  \
 | 
			
		||||
    | (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL)                        \
 | 
			
		||||
    | (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE)                       \
 | 
			
		||||
    | (1 << TPI_INIT_MAX_STREAM_DATA_UNI)                               \
 | 
			
		||||
    | (1 << TPI_MAX_IDLE_TIMEOUT)                                       \
 | 
			
		||||
    | (1 << TPI_MAX_UDP_PAYLOAD_SIZE)                                   \
 | 
			
		||||
    | (1 << TPI_DISABLE_ACTIVE_MIGRATION)                               \
 | 
			
		||||
    /* Not including TPI_LOSS_BITS, see                              */ \
 | 
			
		||||
    /* draft-ferrieuxhamchaoui-quic-lossbits-03, Section 5.1         */ \
 | 
			
		||||
    /* [draft-ietf-quic-datagram-01] Section 3:                      */ \
 | 
			
		||||
    | (1 << TPI_MAX_DATAGRAM_FRAME_SIZE)                                \
 | 
			
		||||
    /* [draft-iyengar-quic-delayed-ack-01] does not specfiy, store:  */ \
 | 
			
		||||
    | (1 << TPI_MIN_ACK_DELAY)                                          \
 | 
			
		||||
    /* [draft-huitema-quic-ts-03] does not specfiy, store:           */ \
 | 
			
		||||
    | (1 << TPI_TIMESTAMPS)                                             \
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue