mirror of
https://gitea.invidious.io/iv-org/litespeed-quic.git
synced 2024-08-15 00:53:43 +00:00
Release 2.7.2
- [BUGFIX] Send controller: update scheduled bytes when DCID length changes (IETF client). - [BUGFIX] Drop alarm check from sanity test. It no longer works now that we use loss chains. - [PORTABILITY] Fix build on Alpine Linux. - [PORTABILITY] Fix build using XCode. - Client initial DCID length: use RAND_bytes() instead of rand(3). - Add unit tests for connection min heap. - [DEBUG] Log CID in gQUIC handshake module - [DEBUG] Turn on extra checks for IETF client send controller. - [DEBUG] Dedup next advisory tick messages when reason is IDLE timer. - [DEBUG] QPACK decoder handler: log header error code.
This commit is contained in:
parent
d6937ddce0
commit
a137764bf2
22 changed files with 369 additions and 76 deletions
15
CHANGELOG
15
CHANGELOG
|
@ -1,3 +1,18 @@
|
|||
2019-12-11
|
||||
- 2.7.2
|
||||
- [BUGFIX] Send controller: update scheduled bytes when DCID length
|
||||
changes (IETF client).
|
||||
- [BUGFIX] Drop alarm check from sanity test. It no longer works now
|
||||
that we use loss chains.
|
||||
- [PORTABILITY] Fix build on Alpine Linux.
|
||||
- [PORTABILITY] Fix build using XCode.
|
||||
- Client initial DCID length: use RAND_bytes() instead of rand(3).
|
||||
- Add unit tests for connection min heap.
|
||||
- [DEBUG] Log CID in gQUIC handshake module
|
||||
- [DEBUG] Turn on extra checks for IETF client send controller.
|
||||
- [DEBUG] Dedup next advisory tick messages when reason is IDLE timer.
|
||||
- [DEBUG] QPACK decoder handler: log header error code.
|
||||
|
||||
2019-12-05
|
||||
- 2.7.1
|
||||
- [BUGFIX] client: don't call ignore_init() in middle of batch send.
|
||||
|
|
|
@ -7,6 +7,8 @@ to the LiteSpeed Client Library:
|
|||
- Alexis La Goutte -- Travis-CI integration
|
||||
- Bernhard Jaeger -- DNS Resolution
|
||||
- Zhang Chi -- libevent build fix on Darwin
|
||||
- Omar Roth -- Alpine Linux build and Crystal language bindings
|
||||
- initlife (?) -- XCode build
|
||||
|
||||
Thank you!
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ extern "C" {
|
|||
|
||||
#define LSQUIC_MAJOR_VERSION 2
|
||||
#define LSQUIC_MINOR_VERSION 7
|
||||
#define LSQUIC_PATCH_VERSION 1
|
||||
#define LSQUIC_PATCH_VERSION 2
|
||||
|
||||
/**
|
||||
* Engine flags:
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <openssl/rand.h>
|
||||
|
||||
|
@ -238,8 +237,12 @@ void
|
|||
lsquic_generate_cid (lsquic_cid_t *cid, size_t len)
|
||||
{
|
||||
if (!len)
|
||||
{
|
||||
/* If not set, generate ID between 8 and MAX_CID_LEN bytes in length */
|
||||
len = 8 + rand() % (MAX_CID_LEN - 7);
|
||||
RAND_bytes((uint8_t *) &len, sizeof(len));
|
||||
len %= MAX_CID_LEN - 7;
|
||||
len += 8;
|
||||
}
|
||||
RAND_bytes(cid->idbuf, len);
|
||||
cid->len = len;
|
||||
}
|
||||
|
|
|
@ -99,6 +99,9 @@ struct enc_session_funcs_common
|
|||
int
|
||||
(*esf_alg_keysize) (enc_session_t *);
|
||||
|
||||
/* Need to pass lconn in encrypt and decrypt methods because enc_session
|
||||
* is allowed to be NULL for gQUIC.
|
||||
*/
|
||||
enum enc_packout
|
||||
(*esf_encrypt_packet) (enc_session_t *, const struct lsquic_engine_public *,
|
||||
struct lsquic_conn *, struct lsquic_packet_out *);
|
||||
|
@ -119,6 +122,9 @@ struct enc_session_funcs_common
|
|||
int
|
||||
(*esf_is_zero_rtt_enabled) (enc_session_t *);
|
||||
|
||||
void
|
||||
(*esf_set_conn) (enc_session_t *, struct lsquic_conn *);
|
||||
|
||||
unsigned
|
||||
esf_tag_len;
|
||||
};
|
||||
|
@ -147,7 +153,8 @@ struct enc_session_funcs_gquic
|
|||
|
||||
/* Create server session */
|
||||
enc_session_t *
|
||||
(*esf_create_server) (lsquic_cid_t cid, const struct lsquic_engine_public *);
|
||||
(*esf_create_server) (struct lsquic_conn *,
|
||||
lsquic_cid_t cid, const struct lsquic_engine_public *);
|
||||
|
||||
/* out_len should have init value as the max length of out */
|
||||
enum handshake_error
|
||||
|
@ -208,7 +215,8 @@ struct enc_session_funcs_gquic
|
|||
|
||||
/* Create client session */
|
||||
enc_session_t *
|
||||
(*esf_create_client) (const char *domain, lsquic_cid_t cid,
|
||||
(*esf_create_client) (struct lsquic_conn *, const char *domain,
|
||||
lsquic_cid_t cid,
|
||||
const struct lsquic_engine_public *,
|
||||
const unsigned char *, size_t);
|
||||
|
||||
|
@ -229,7 +237,6 @@ struct enc_session_funcs_gquic
|
|||
* call it after the "handshake is done" callback is called.
|
||||
*/
|
||||
void (*esf_maybe_dispatch_zero_rtt) (enc_session_t *,
|
||||
struct lsquic_conn *conn,
|
||||
void (*cb)(struct lsquic_conn *, const unsigned char *, size_t));
|
||||
|
||||
void (*esf_reset_cid) (enc_session_t *, const lsquic_cid_t *);
|
||||
|
@ -279,9 +286,6 @@ struct enc_session_funcs_iquic
|
|||
int
|
||||
(*esfi_init_server) (enc_session_t *);
|
||||
|
||||
void
|
||||
(*esfi_set_conn) (enc_session_t *, struct lsquic_conn *);
|
||||
|
||||
void
|
||||
(*esfi_set_streams) (enc_session_t *, void *(crypto_streams)[4],
|
||||
const struct crypto_stream_if *);
|
||||
|
|
|
@ -1064,7 +1064,7 @@ iquic_lookup_cert (SSL *ssl, void *arg)
|
|||
|
||||
|
||||
static void
|
||||
iquic_esfi_set_conn (enc_session_t *enc_session_p, struct lsquic_conn *lconn)
|
||||
iquic_esf_set_conn (enc_session_t *enc_session_p, struct lsquic_conn *lconn)
|
||||
{
|
||||
struct enc_sess_iquic *const enc_sess = enc_session_p;
|
||||
enc_sess->esi_conn = lconn;
|
||||
|
@ -1657,10 +1657,11 @@ static const enum enc_level pns2enc_level[] =
|
|||
|
||||
static enum enc_packout
|
||||
iquic_esf_encrypt_packet (enc_session_t *enc_session_p,
|
||||
const struct lsquic_engine_public *enpub, struct lsquic_conn *lconn,
|
||||
const struct lsquic_engine_public *enpub, struct lsquic_conn *lconn_UNUSED,
|
||||
struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
struct enc_sess_iquic *const enc_sess = enc_session_p;
|
||||
struct lsquic_conn *const lconn = enc_sess->esi_conn;
|
||||
unsigned char *dst;
|
||||
const struct crypto_ctx_pair *pair;
|
||||
const struct crypto_ctx *crypto_ctx;
|
||||
|
@ -1676,8 +1677,6 @@ iquic_esf_encrypt_packet (enc_session_t *enc_session_p,
|
|||
enum packnum_space pns;
|
||||
char errbuf[ERR_ERROR_STRING_BUF_LEN];
|
||||
|
||||
assert(lconn == enc_sess->esi_conn);
|
||||
|
||||
if (packet_out->po_flags & PO_MINI)
|
||||
{
|
||||
/* XXX TODO Don't rely on PO_MINI, generalize this logic */
|
||||
|
@ -2232,7 +2231,6 @@ const struct enc_session_funcs_iquic lsquic_enc_session_iquic_ietf_v1 =
|
|||
= iquic_esfi_get_peer_transport_params,
|
||||
.esfi_reset_dcid = iquic_esfi_reset_dcid,
|
||||
.esfi_init_server = iquic_esfi_init_server,
|
||||
.esfi_set_conn = iquic_esfi_set_conn,
|
||||
.esfi_set_streams = iquic_esfi_set_streams,
|
||||
.esfi_create_server = iquic_esfi_create_server,
|
||||
.esfi_shake_stream = iquic_esfi_shake_stream,
|
||||
|
@ -2253,6 +2251,7 @@ const struct enc_session_funcs_common lsquic_enc_session_common_ietf_v1 =
|
|||
.esf_keysize = iquic_esf_keysize,
|
||||
.esf_alg_keysize = iquic_esf_alg_keysize,
|
||||
.esf_is_zero_rtt_enabled = iquic_esf_zero_rtt_enabled,
|
||||
.esf_set_conn = iquic_esf_set_conn,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -84,6 +84,10 @@
|
|||
#define LSQUIC_DEBUG_NEXT_ADV_TICK 1
|
||||
#endif
|
||||
|
||||
#if LSQUIC_DEBUG_NEXT_ADV_TICK
|
||||
#include "lsquic_alarmset.h"
|
||||
#endif
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
/* The batch of outgoing packets grows and shrinks dynamically */
|
||||
|
@ -248,6 +252,9 @@ struct lsquic_engine
|
|||
#if LSQUIC_COUNT_ENGINE_CALLS
|
||||
unsigned long n_engine_calls;
|
||||
#endif
|
||||
#if LSQUIC_DEBUG_NEXT_ADV_TICK
|
||||
uintptr_t last_logged_idle_conn;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
@ -2543,9 +2550,6 @@ process_connections (lsquic_engine_t *engine, conn_iter_f next_conn,
|
|||
(void) engine_decref_conn(engine, conn, LSCONN_CLOSING);
|
||||
}
|
||||
|
||||
/* TODO Heapification can be optimized by switching to the Floyd method:
|
||||
* https://en.wikipedia.org/wiki/Binary_heap#Building_a_heap
|
||||
*/
|
||||
while ((conn = TAILQ_FIRST(&ticked_conns)))
|
||||
{
|
||||
TAILQ_REMOVE(&ticked_conns, conn, cn_next_ticked);
|
||||
|
@ -2553,6 +2557,7 @@ process_connections (lsquic_engine_t *engine, conn_iter_f next_conn,
|
|||
if (!(conn->cn_flags & LSCONN_TICKABLE)
|
||||
&& conn->cn_if->ci_is_tickable(conn))
|
||||
{
|
||||
/* Floyd heapification is not faster, don't bother. */
|
||||
lsquic_mh_insert(&engine->conns_tickable, conn, conn->cn_last_ticked);
|
||||
engine_incref_conn(conn, LSCONN_TICKABLE);
|
||||
}
|
||||
|
@ -2709,6 +2714,7 @@ lsquic_engine_earliest_adv_tick (lsquic_engine_t *engine, int *diff)
|
|||
{
|
||||
#if LSQUIC_DEBUG_NEXT_ADV_TICK
|
||||
conn = lsquic_mh_peek(&engine->conns_out);
|
||||
engine->last_logged_idle_conn = 0;
|
||||
LSQ_LOGC(L, "next advisory tick is now: went past deadline last time "
|
||||
"and have %u outgoing connection%.*s (%"CID_FMT" first)",
|
||||
lsquic_mh_count(&engine->conns_out),
|
||||
|
@ -2722,6 +2728,7 @@ lsquic_engine_earliest_adv_tick (lsquic_engine_t *engine, int *diff)
|
|||
if (engine->pr_queue && prq_have_pending(engine->pr_queue))
|
||||
{
|
||||
#if LSQUIC_DEBUG_NEXT_ADV_TICK
|
||||
engine->last_logged_idle_conn = 0;
|
||||
LSQ_LOG(L, "next advisory tick is now: have pending PRQ elements");
|
||||
#endif
|
||||
*diff = 0;
|
||||
|
@ -2732,6 +2739,7 @@ lsquic_engine_earliest_adv_tick (lsquic_engine_t *engine, int *diff)
|
|||
{
|
||||
#if LSQUIC_DEBUG_NEXT_ADV_TICK
|
||||
conn = lsquic_mh_peek(&engine->conns_tickable);
|
||||
engine->last_logged_idle_conn = 0;
|
||||
LSQ_LOGC(L, "next advisory tick is now: have %u tickable "
|
||||
"connection%.*s (%"CID_FMT" first)",
|
||||
lsquic_mh_count(&engine->conns_tickable),
|
||||
|
@ -2769,9 +2777,21 @@ lsquic_engine_earliest_adv_tick (lsquic_engine_t *engine, int *diff)
|
|||
*diff = (int) ((int64_t) next_time - (int64_t) now);
|
||||
#if LSQUIC_DEBUG_NEXT_ADV_TICK
|
||||
if (next_attq)
|
||||
LSQ_LOGC(L, "next advisory tick is %d usec away: conn %"CID_FMT
|
||||
": %s", *diff, CID_BITS(lsquic_conn_log_cid(next_attq->ae_conn)),
|
||||
lsquic_attq_why2str(next_attq->ae_why));
|
||||
{
|
||||
/* Deduplicate consecutive log messages about IDLE timer for the
|
||||
* same connection.
|
||||
*/
|
||||
if (!((unsigned) next_attq->ae_why == (unsigned) (N_AEWS + AL_IDLE)
|
||||
&& (uintptr_t) next_attq->ae_conn
|
||||
== engine->last_logged_idle_conn))
|
||||
{
|
||||
if ((unsigned) next_attq->ae_why == (unsigned) (N_AEWS + AL_IDLE))
|
||||
engine->last_logged_idle_conn = (uintptr_t) next_attq->ae_conn;
|
||||
LSQ_LOGC(L, "next advisory tick is %d usec away: conn %"CID_FMT
|
||||
": %s", *diff, CID_BITS(lsquic_conn_log_cid(next_attq->ae_conn)),
|
||||
lsquic_attq_why2str(next_attq->ae_why));
|
||||
}
|
||||
}
|
||||
else
|
||||
LSQ_LOG(L, "next advisory tick is %d usec away: resume sending", *diff);
|
||||
#endif
|
||||
|
|
|
@ -708,8 +708,8 @@ lsquic_gquic_full_conn_client_new (struct lsquic_engine_public *enpub,
|
|||
conn->fc_conn.cn_esf_c = select_esf_common_by_ver(version);
|
||||
conn->fc_conn.cn_esf.g = esf_g;
|
||||
conn->fc_conn.cn_enc_session =
|
||||
conn->fc_conn.cn_esf.g->esf_create_client(hostname, cid, conn->fc_enpub,
|
||||
zero_rtt, zero_rtt_len);
|
||||
conn->fc_conn.cn_esf.g->esf_create_client(&conn->fc_conn, hostname,
|
||||
cid, conn->fc_enpub, zero_rtt, zero_rtt_len);
|
||||
if (!conn->fc_conn.cn_enc_session)
|
||||
{
|
||||
LSQ_WARN("could not create enc session: %s", strerror(errno));
|
||||
|
@ -818,6 +818,8 @@ lsquic_gquic_full_conn_server_new (struct lsquic_engine_public *enpub,
|
|||
assert(lconn_full->cn_enc_session == NULL);
|
||||
lconn_full->cn_enc_session = lconn_mini->cn_enc_session;
|
||||
lconn_mini->cn_enc_session = NULL;
|
||||
lconn_full->cn_esf_c->esf_set_conn(lconn_full->cn_enc_session,
|
||||
&conn->fc_conn);
|
||||
|
||||
lsquic_send_ctl_verneg_done(&conn->fc_send_ctl);
|
||||
conn->fc_send_ctl.sc_cur_packno = mc->mc_cur_packno;
|
||||
|
@ -3640,7 +3642,7 @@ full_conn_ci_hsk_done (lsquic_conn_t *lconn, enum lsquic_hsk_status status)
|
|||
{
|
||||
if (conn->fc_stream_ifs[STREAM_IF_STD].stream_if->on_zero_rtt_info)
|
||||
conn->fc_conn.cn_esf.g->esf_maybe_dispatch_zero_rtt(
|
||||
conn->fc_conn.cn_enc_session, &conn->fc_conn,
|
||||
conn->fc_conn.cn_enc_session,
|
||||
conn->fc_stream_ifs[STREAM_IF_STD].stream_if->on_zero_rtt_info);
|
||||
if (conn->fc_n_delayed_streams)
|
||||
create_delayed_streams(conn);
|
||||
|
|
|
@ -1209,7 +1209,7 @@ lsquic_ietf_full_conn_server_new (struct lsquic_engine_public *enpub,
|
|||
|
||||
conn->ifc_conn.cn_enc_session = mini_conn->cn_enc_session;
|
||||
mini_conn->cn_enc_session = NULL;
|
||||
conn->ifc_conn.cn_esf.i->esfi_set_conn(conn->ifc_conn.cn_enc_session,
|
||||
conn->ifc_conn.cn_esf_c->esf_set_conn(conn->ifc_conn.cn_enc_session,
|
||||
&conn->ifc_conn);
|
||||
conn->ifc_process_incoming_packet = process_incoming_packet_fast;
|
||||
|
||||
|
@ -5672,6 +5672,21 @@ sockaddr_eq (const struct sockaddr *a, const struct sockaddr *b)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
record_dcid (struct ietf_full_conn *conn,
|
||||
const struct lsquic_packet_in *packet_in)
|
||||
{
|
||||
unsigned orig_cid_len;
|
||||
|
||||
orig_cid_len = CUR_DCID(conn)->len;
|
||||
conn->ifc_flags |= IFC_DCID_SET;
|
||||
lsquic_scid_from_packet_in(packet_in, CUR_DCID(conn));
|
||||
LSQ_DEBUGC("set DCID to %"CID_FMT, CID_BITS(CUR_DCID(conn)));
|
||||
lsquic_send_ctl_cidlen_change(&conn->ifc_send_ctl, orig_cid_len,
|
||||
CUR_DCID(conn)->len);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
process_regular_packet (struct ietf_full_conn *conn,
|
||||
struct lsquic_packet_in *packet_in)
|
||||
|
@ -5732,8 +5747,8 @@ process_regular_packet (struct ietf_full_conn *conn,
|
|||
if (0 == (packet_in->pi_flags & PI_DECRYPTED))
|
||||
{
|
||||
dec_packin = conn->ifc_conn.cn_esf_c->esf_decrypt_packet(
|
||||
conn->ifc_conn.cn_enc_session, conn->ifc_enpub,
|
||||
&conn->ifc_conn, packet_in);
|
||||
conn->ifc_conn.cn_enc_session, conn->ifc_enpub,
|
||||
&conn->ifc_conn, packet_in);
|
||||
switch (dec_packin)
|
||||
{
|
||||
case DECPI_BADCRYPT:
|
||||
|
@ -5784,12 +5799,7 @@ process_regular_packet (struct ietf_full_conn *conn,
|
|||
case REC_ST_OK:
|
||||
if (!(conn->ifc_flags & (IFC_SERVER|IFC_DCID_SET))
|
||||
&& (packet_in->pi_scid_len))
|
||||
{
|
||||
conn->ifc_flags |= IFC_DCID_SET;
|
||||
lsquic_scid_from_packet_in(packet_in, CUR_DCID(conn));
|
||||
LSQ_DEBUGC("set DCID to %"CID_FMT,
|
||||
CID_BITS(CUR_DCID(conn)));
|
||||
}
|
||||
record_dcid(conn, packet_in);
|
||||
saved_path_id = conn->ifc_cur_path_id;
|
||||
parse_regular_packet(conn, packet_in);
|
||||
if (saved_path_id == conn->ifc_cur_path_id)
|
||||
|
|
|
@ -56,8 +56,19 @@
|
|||
#define MAX_SPUBS_LENGTH 32
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_HANDSHAKE
|
||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid( \
|
||||
enc_session && enc_session->es_conn ? enc_session->es_conn : \
|
||||
lconn && lconn != &dummy_lsquic_conn ? lconn : \
|
||||
&dummy_lsquic_conn)
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
/* enc_session may be NULL when encrypt and decrypt packet functions are
|
||||
* called. This is a workaround.
|
||||
*/
|
||||
static struct conn_cid_elem dummy_cce;
|
||||
static const struct lsquic_conn dummy_lsquic_conn = { .cn_cces = &dummy_cce, };
|
||||
static const struct lsquic_conn *const lconn = &dummy_lsquic_conn;
|
||||
|
||||
enum handshake_state
|
||||
{
|
||||
HSK_CHLO_REJ = 0,
|
||||
|
@ -200,6 +211,7 @@ struct lsquic_zero_rtt_storage
|
|||
|
||||
struct lsquic_enc_session
|
||||
{
|
||||
struct lsquic_conn *es_conn;
|
||||
enum handshake_state hsk_state;
|
||||
enum {
|
||||
ES_SERVER = 1 << 0,
|
||||
|
@ -674,8 +686,8 @@ lsquic_enc_session_deserialize_zero_rtt(
|
|||
|
||||
|
||||
static enc_session_t *
|
||||
lsquic_enc_session_create_client (const char *domain, lsquic_cid_t cid,
|
||||
const struct lsquic_engine_public *enpub,
|
||||
lsquic_enc_session_create_client (struct lsquic_conn *lconn, const char *domain,
|
||||
lsquic_cid_t cid, const struct lsquic_engine_public *enpub,
|
||||
const unsigned char *zero_rtt, size_t zero_rtt_len)
|
||||
{
|
||||
lsquic_session_cache_info_t *info;
|
||||
|
@ -734,6 +746,7 @@ lsquic_enc_session_create_client (const char *domain, lsquic_cid_t cid,
|
|||
break;
|
||||
}
|
||||
}
|
||||
enc_session->es_conn = lconn;
|
||||
enc_session->enpub = enpub;
|
||||
enc_session->cid = cid;
|
||||
enc_session->info = info;
|
||||
|
@ -745,7 +758,7 @@ lsquic_enc_session_create_client (const char *domain, lsquic_cid_t cid,
|
|||
|
||||
/* Server side: Session_cache_entry can be saved for 0rtt */
|
||||
static enc_session_t *
|
||||
lsquic_enc_session_create_server (lsquic_cid_t cid,
|
||||
lsquic_enc_session_create_server (struct lsquic_conn *lconn, lsquic_cid_t cid,
|
||||
const struct lsquic_engine_public *enpub)
|
||||
{
|
||||
fiu_return_on("handshake/new_enc_session", NULL);
|
||||
|
@ -756,6 +769,7 @@ lsquic_enc_session_create_server (lsquic_cid_t cid,
|
|||
if (!enc_session)
|
||||
return NULL;
|
||||
|
||||
enc_session->es_conn = lconn;
|
||||
enc_session->enpub = enpub;
|
||||
enc_session->cid = cid;
|
||||
enc_session->es_flags |= ES_SERVER;
|
||||
|
@ -1575,7 +1589,8 @@ determine_rtts (struct lsquic_enc_session *enc_session,
|
|||
|
||||
|
||||
static int
|
||||
config_has_correct_size (const void *data, unsigned shm_len)
|
||||
config_has_correct_size (const struct lsquic_enc_session *enc_session,
|
||||
const void *data, unsigned shm_len)
|
||||
{
|
||||
/* EVP_AEAD_CTX from boringssl after-18d9f28f0df9f95570. */
|
||||
struct new_evp_aead_ctx_st {
|
||||
|
@ -1620,7 +1635,8 @@ config_has_correct_size (const void *data, unsigned shm_len)
|
|||
|
||||
|
||||
static lsquic_server_config_t *
|
||||
get_valid_scfg (const struct lsquic_engine_public *enpub)
|
||||
get_valid_scfg (const struct lsquic_enc_session *enc_session,
|
||||
const struct lsquic_engine_public *enpub)
|
||||
{
|
||||
#define SERVER_SCFG_KEY "SERVER_SCFG"
|
||||
#define SERVER_SCFG_KEY_SIZE (sizeof(SERVER_SCFG_KEY) - 1)
|
||||
|
@ -1644,7 +1660,7 @@ get_valid_scfg (const struct lsquic_engine_public *enpub)
|
|||
&scfg_ptr, &real_len);
|
||||
if (ret == 1)
|
||||
{
|
||||
if (config_has_correct_size(scfg_ptr, real_len) &&
|
||||
if (config_has_correct_size(enc_session, scfg_ptr, real_len) &&
|
||||
(s_server_config.lsc_scfg = scfg_ptr,
|
||||
s_server_config.lsc_scfg->info.expy > (uint64_t)t))
|
||||
{
|
||||
|
@ -2621,7 +2637,8 @@ gen_stk (lsquic_server_config_t *server_config, const struct sockaddr *ip_addr,
|
|||
static
|
||||
#endif
|
||||
enum hsk_failure_reason
|
||||
verify_stk0 (lsquic_server_config_t *server_config,
|
||||
verify_stk0 (const struct lsquic_enc_session *enc_session,
|
||||
lsquic_server_config_t *server_config,
|
||||
const struct sockaddr *ip_addr, uint64_t tm, lsquic_str_t *stk,
|
||||
unsigned secs_since_stk_generated)
|
||||
{
|
||||
|
@ -2701,7 +2718,8 @@ verify_stk (enc_session_t *enc_session_p,
|
|||
return HFR_SRC_ADDR_TOKEN_INVALID;
|
||||
}
|
||||
else
|
||||
return verify_stk0(enc_session->server_config, ip_addr, tm, stk, 0);
|
||||
return verify_stk0(enc_session, enc_session->server_config, ip_addr,
|
||||
tm, stk, 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2850,14 +2868,13 @@ lsquic_enc_session_have_key_gt_one (enc_session_t *enc_session_p)
|
|||
* buffer correspond to the header and the payload of incoming QUIC packet.
|
||||
*/
|
||||
static enum enc_level
|
||||
lsquic_enc_session_decrypt (enc_session_t *enc_session_p,
|
||||
lsquic_enc_session_decrypt (struct lsquic_enc_session *enc_session,
|
||||
enum lsquic_version version,
|
||||
uint8_t path_id, uint64_t pack_num,
|
||||
unsigned char *buf, size_t *header_len, size_t data_len,
|
||||
unsigned char *diversification_nonce,
|
||||
unsigned char *buf_out, size_t max_out_len, size_t *out_len)
|
||||
{
|
||||
struct lsquic_enc_session *const enc_session = enc_session_p;
|
||||
/* Client: got SHLO which should have diversification_nonce */
|
||||
if (diversification_nonce && enc_session && enc_session->have_key == 1)
|
||||
{
|
||||
|
@ -2882,6 +2899,7 @@ gquic_decrypt_packet (enc_session_t *enc_session_p,
|
|||
const struct lsquic_conn *lconn,
|
||||
struct lsquic_packet_in *packet_in)
|
||||
{
|
||||
struct lsquic_enc_session *const enc_session = enc_session_p;
|
||||
size_t header_len, data_len;
|
||||
enum enc_level enc_level;
|
||||
size_t out_len = 0;
|
||||
|
@ -2895,7 +2913,7 @@ gquic_decrypt_packet (enc_session_t *enc_session_p,
|
|||
assert(packet_in->pi_data);
|
||||
header_len = packet_in->pi_header_sz;
|
||||
data_len = packet_in->pi_data_sz - packet_in->pi_header_sz;
|
||||
enc_level = lsquic_enc_session_decrypt(enc_session_p,
|
||||
enc_level = lsquic_enc_session_decrypt(enc_session,
|
||||
lconn->cn_version, 0,
|
||||
packet_in->pi_packno, packet_in->pi_data,
|
||||
&header_len, data_len,
|
||||
|
@ -3030,7 +3048,7 @@ lsquic_enc_session_handle_chlo(enc_session_t *enc_session_p,
|
|||
const struct lsquic_shared_hash_if *const shi = enpub->enp_shi;
|
||||
void *const shi_ctx = enpub->enp_shi_ctx;
|
||||
|
||||
server_config = get_valid_scfg(enpub);
|
||||
server_config = get_valid_scfg(enc_session, enpub);
|
||||
if (!server_config)
|
||||
return HS_ERROR;
|
||||
assert(server_config->lsc_scfg);
|
||||
|
@ -3493,10 +3511,10 @@ lsquic_enc_session_get_server_cert_chain (enc_session_t *enc_session_p)
|
|||
|
||||
static void
|
||||
maybe_dispatch_zero_rtt (enc_session_t *enc_session_p,
|
||||
struct lsquic_conn *lconn,
|
||||
void (*cb)(struct lsquic_conn *, const unsigned char *, size_t))
|
||||
{
|
||||
struct lsquic_enc_session *const enc_session = enc_session_p;
|
||||
struct lsquic_conn *const lconn = enc_session->es_conn;
|
||||
void *buf;
|
||||
size_t sz;
|
||||
int i;
|
||||
|
@ -3570,6 +3588,8 @@ gquic_encrypt_packet (enc_session_t *enc_session_p,
|
|||
unsigned char *buf;
|
||||
int ipv6;
|
||||
|
||||
assert(!enc_session || lconn == enc_session->es_conn);
|
||||
|
||||
bufsz = lconn->cn_pf->pf_packout_size(lconn, packet_out);
|
||||
if (bufsz > USHRT_MAX)
|
||||
return ENCPA_BADCRYPT; /* To cause connection to close */
|
||||
|
@ -3614,6 +3634,15 @@ gquic_encrypt_packet (enc_session_t *enc_session_p,
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
gquic_esf_set_conn (enc_session_t *enc_session_p, struct lsquic_conn *lconn)
|
||||
{
|
||||
struct lsquic_enc_session *const enc_session = enc_session_p;
|
||||
enc_session->es_conn = lconn;
|
||||
LSQ_DEBUG("updated conn reference");
|
||||
}
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
const
|
||||
#endif
|
||||
|
@ -3631,6 +3660,7 @@ struct enc_session_funcs_common lsquic_enc_session_common_gquic_1 =
|
|||
.esf_verify_reset_token = lsquic_enc_session_verify_reset_token,
|
||||
.esf_did_zero_rtt_succeed = lsquic_enc_session_did_zero_rtt_succeed,
|
||||
.esf_is_zero_rtt_enabled = lsquic_enc_session_is_zero_rtt_enabled,
|
||||
.esf_set_conn = gquic_esf_set_conn,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ struct sockaddr;
|
|||
struct lsquic_str;
|
||||
struct lsquic_packet_in;
|
||||
struct lsquic_cid;
|
||||
struct lsquic_enc_session;
|
||||
|
||||
/* client side, certs and hashs
|
||||
*/
|
||||
|
@ -28,7 +29,8 @@ typedef struct cert_hash_item_st
|
|||
void gen_stk(struct lsquic_server_config *, const struct sockaddr *ip_addr, uint64_t tm,
|
||||
unsigned char stk_out[STK_LENGTH]);
|
||||
enum hsk_failure_reason
|
||||
verify_stk0(struct lsquic_server_config *, const struct sockaddr *ip_addr, uint64_t tm,
|
||||
verify_stk0(const struct lsquic_enc_session *,
|
||||
struct lsquic_server_config *, const struct sockaddr *ip_addr, uint64_t tm,
|
||||
struct lsquic_str *stk,
|
||||
unsigned secs_since_stk_generated);
|
||||
enum hsk_failure_reason
|
||||
|
|
|
@ -82,7 +82,6 @@ enum lsq_log_level lsq_log_levels[N_LSQUIC_LOGGER_MODULES] = {
|
|||
[LSQLM_DI] = LSQ_LOG_WARN,
|
||||
[LSQLM_PRQ] = LSQ_LOG_WARN,
|
||||
[LSQLM_PACER] = LSQ_LOG_WARN,
|
||||
[LSQLM_MIN_HEAP] = LSQ_LOG_WARN,
|
||||
[LSQLM_HTTP1X] = LSQ_LOG_WARN,
|
||||
[LSQLM_QLOG] = LSQ_LOG_WARN,
|
||||
[LSQLM_TRAPA] = LSQ_LOG_WARN,
|
||||
|
@ -125,7 +124,6 @@ const char *const lsqlm_to_str[N_LSQUIC_LOGGER_MODULES] = {
|
|||
[LSQLM_DI] = "di",
|
||||
[LSQLM_PRQ] = "prq",
|
||||
[LSQLM_PACER] = "pacer",
|
||||
[LSQLM_MIN_HEAP] = "min-heap",
|
||||
[LSQLM_HTTP1X] = "http1x",
|
||||
[LSQLM_QLOG] = "qlog",
|
||||
[LSQLM_TRAPA] = "trapa",
|
||||
|
|
|
@ -73,7 +73,6 @@ enum lsquic_logger_module {
|
|||
LSQLM_DI,
|
||||
LSQLM_PRQ,
|
||||
LSQLM_PACER,
|
||||
LSQLM_MIN_HEAP,
|
||||
LSQLM_HTTP1X,
|
||||
LSQLM_QLOG,
|
||||
LSQLM_TRAPA,
|
||||
|
|
|
@ -4,16 +4,10 @@
|
|||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lsquic_min_heap.h"
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_MIN_HEAP
|
||||
#include "lsquic_types.h"
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
#define MHE_PARENT(i) ((i - 1) / 2)
|
||||
#define MHE_LCHILD(i) (2 * i + 1)
|
||||
#define MHE_RCHILD(i) (2 * i + 2)
|
||||
|
||||
|
||||
static void
|
||||
|
|
|
@ -35,4 +35,8 @@ lsquic_mh_pop (struct min_heap *);
|
|||
|
||||
#define lsquic_mh_nalloc(heap) (+(heap)->mh_nalloc)
|
||||
|
||||
#define MHE_PARENT(i) ((i - 1) / 2)
|
||||
#define MHE_LCHILD(i) (2 * i + 1)
|
||||
#define MHE_RCHILD(i) (2 * i + 2)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1005,8 +1005,8 @@ continue_handshake (struct mini_conn *mc)
|
|||
if (!mc->mc_conn.cn_enc_session)
|
||||
{
|
||||
mc->mc_conn.cn_enc_session =
|
||||
mc->mc_conn.cn_esf.g->esf_create_server(mc->mc_conn.cn_cid,
|
||||
mc->mc_enpub);
|
||||
mc->mc_conn.cn_esf.g->esf_create_server(&mc->mc_conn,
|
||||
mc->mc_conn.cn_cid, mc->mc_enpub);
|
||||
if (!mc->mc_conn.cn_enc_session)
|
||||
{
|
||||
LSQ_WARN("cannot create new enc session");
|
||||
|
|
|
@ -1154,7 +1154,7 @@ ietf_mini_conn_ci_packet_in (struct lsquic_conn *lconn,
|
|||
}
|
||||
|
||||
dec_packin = lconn->cn_esf_c->esf_decrypt_packet(lconn->cn_enc_session,
|
||||
conn->imc_enpub, lconn, packet_in);
|
||||
conn->imc_enpub, &conn->imc_conn, packet_in);
|
||||
if (dec_packin != DECPI_OK)
|
||||
{
|
||||
/* TODO: handle reordering perhaps? */
|
||||
|
|
|
@ -408,7 +408,10 @@ qdh_supply_hset_to_stream (struct qpack_dec_hdl *qdh,
|
|||
header->qh_name, header->qh_name_len,
|
||||
header->qh_value, header->qh_value_len);
|
||||
if (st != LSQUIC_HDR_OK)
|
||||
{
|
||||
LSQ_INFO("header process returned non-OK code %u", (unsigned) st);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
lsqpack_dec_destroy_header_list(qlist);
|
||||
|
|
|
@ -347,6 +347,13 @@ lsquic_send_ctl_init (lsquic_send_ctl_t *ctl, struct lsquic_alarmset *alset,
|
|||
TAILQ_INIT(&ctl->sc_buffered_packets[i].bpq_packets);
|
||||
ctl->sc_max_packno_bits = PACKNO_BITS_2; /* Safe value before verneg */
|
||||
ctl->sc_cached_bpt.stream_id = UINT64_MAX;
|
||||
#if LSQUIC_EXTRA_CHECKS
|
||||
ctl->sc_flags |= SC_SANITY_CHECK;
|
||||
#else
|
||||
if ((ctl->sc_conn_pub->lconn->cn_flags & (LSCONN_IETF|LSCONN_SERVER))
|
||||
== LSCONN_IETF)
|
||||
ctl->sc_flags |= SC_SANITY_CHECK;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -1404,9 +1411,8 @@ lsquic_send_ctl_expire_all (lsquic_send_ctl_t *ctl)
|
|||
}
|
||||
|
||||
|
||||
#if LSQUIC_EXTRA_CHECKS
|
||||
void
|
||||
lsquic_send_ctl_sanity_check (const lsquic_send_ctl_t *ctl)
|
||||
lsquic_send_ctl_do_sanity_check (const struct lsquic_send_ctl *ctl)
|
||||
{
|
||||
const struct lsquic_packet_out *packet_out;
|
||||
lsquic_packno_t prev_packno;
|
||||
|
@ -1414,15 +1420,6 @@ lsquic_send_ctl_sanity_check (const lsquic_send_ctl_t *ctl)
|
|||
unsigned count, bytes;
|
||||
enum packnum_space pns;
|
||||
|
||||
assert(!send_ctl_first_unacked_retx_packet(ctl, PNS_APP) ||
|
||||
lsquic_alarmset_is_set(ctl->sc_alset, AL_RETX_APP));
|
||||
if (lsquic_alarmset_is_set(ctl->sc_alset, AL_RETX_APP))
|
||||
{
|
||||
assert(send_ctl_first_unacked_retx_packet(ctl, PNS_APP));
|
||||
assert(lsquic_time_now()
|
||||
< ctl->sc_alset->as_expiry[AL_RETX_APP] + MAX_RTO_DELAY);
|
||||
}
|
||||
|
||||
count = 0, bytes = 0;
|
||||
for (pns = PNS_INIT; pns <= PNS_APP; ++pns)
|
||||
{
|
||||
|
@ -1456,7 +1453,6 @@ lsquic_send_ctl_sanity_check (const lsquic_send_ctl_t *ctl)
|
|||
assert(count == ctl->sc_n_scheduled);
|
||||
assert(bytes == ctl->sc_bytes_scheduled);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
|
@ -2814,3 +2810,42 @@ lsquic_send_ctl_return_enc_data (struct lsquic_send_ctl *ctl)
|
|||
if (packet_out->po_flags & PO_ENCRYPTED)
|
||||
send_ctl_return_enc_data(ctl, packet_out);
|
||||
}
|
||||
|
||||
|
||||
/* When client updated DCID based on the first packet returned by the server,
|
||||
* we must update the number of bytes scheduled if the DCID length changed
|
||||
* because this length is used to calculate packet size.
|
||||
*/
|
||||
void
|
||||
lsquic_send_ctl_cidlen_change (struct lsquic_send_ctl *ctl,
|
||||
unsigned orig_cid_len, unsigned new_cid_len)
|
||||
{
|
||||
unsigned diff;
|
||||
|
||||
assert(!(ctl->sc_conn_pub->lconn->cn_flags & LSCONN_SERVER));
|
||||
if (ctl->sc_n_scheduled)
|
||||
{
|
||||
ctl->sc_flags |= SC_CIDLEN;
|
||||
ctl->sc_cidlen = (signed char) new_cid_len - (signed char) orig_cid_len;
|
||||
if (new_cid_len > orig_cid_len)
|
||||
{
|
||||
diff = new_cid_len - orig_cid_len;
|
||||
diff *= ctl->sc_n_scheduled;
|
||||
ctl->sc_bytes_scheduled += diff;
|
||||
LSQ_DEBUG("increased bytes scheduled by %u bytes to %u",
|
||||
diff, ctl->sc_bytes_scheduled);
|
||||
}
|
||||
else if (new_cid_len < orig_cid_len)
|
||||
{
|
||||
diff = orig_cid_len - new_cid_len;
|
||||
diff *= ctl->sc_n_scheduled;
|
||||
ctl->sc_bytes_scheduled -= diff;
|
||||
LSQ_DEBUG("decreased bytes scheduled by %u bytes to %u",
|
||||
diff, ctl->sc_bytes_scheduled);
|
||||
}
|
||||
else
|
||||
LSQ_DEBUG("DCID length did not change");
|
||||
}
|
||||
else
|
||||
LSQ_DEBUG("no scheduled packets at the time of DCID change");
|
||||
}
|
||||
|
|
|
@ -45,6 +45,8 @@ enum send_ctl_flags {
|
|||
SC_APP_LIMITED = 1 << 12,
|
||||
SC_ECN = 1 << 13,
|
||||
SC_QL_BITS = 1 << 14,
|
||||
SC_SANITY_CHECK = 1 << 15,
|
||||
SC_CIDLEN = 1 << 16, /* sc_cidlen is set */
|
||||
};
|
||||
|
||||
typedef struct lsquic_send_ctl {
|
||||
|
@ -127,6 +129,7 @@ typedef struct lsquic_send_ctl {
|
|||
lsquic_packno_t sc_cur_rt_end;
|
||||
unsigned sc_loss_count; /* Used to set loss bit */
|
||||
unsigned sc_square_count;/* Used to set square bit */
|
||||
signed char sc_cidlen; /* For debug purposes */
|
||||
} lsquic_send_ctl_t;
|
||||
|
||||
void
|
||||
|
@ -172,12 +175,13 @@ lsquic_send_ctl_expire_all (lsquic_send_ctl_t *ctl);
|
|||
#define lsquic_send_ctl_largest_ack2ed(ctl, pns) \
|
||||
(+(ctl)->sc_largest_ack2ed[pns])
|
||||
|
||||
#if LSQUIC_EXTRA_CHECKS
|
||||
void
|
||||
lsquic_send_ctl_sanity_check (const lsquic_send_ctl_t *ctl);
|
||||
#else
|
||||
# define lsquic_send_ctl_sanity_check(ctl)
|
||||
#endif
|
||||
lsquic_send_ctl_do_sanity_check (const struct lsquic_send_ctl *ctl);
|
||||
|
||||
#define lsquic_send_ctl_sanity_check(ctl) do { \
|
||||
if ((ctl)->sc_flags & SC_SANITY_CHECK) \
|
||||
lsquic_send_ctl_do_sanity_check(ctl); \
|
||||
} while (0)
|
||||
|
||||
int
|
||||
lsquic_send_ctl_have_outgoing_stream_frames (const lsquic_send_ctl_t *);
|
||||
|
@ -364,4 +368,8 @@ lsquic_send_ctl_maybe_app_limited (struct lsquic_send_ctl *,
|
|||
(ctl)->sc_flags |= SC_QL_BITS; \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_send_ctl_cidlen_change (struct lsquic_send_ctl *,
|
||||
unsigned orig_cid_len, unsigned new_cid_len);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -99,6 +99,9 @@ TARGET_LINK_LIBRARIES(graph_cubic ${LIBS})
|
|||
ADD_EXECUTABLE(mini_parse mini_parse.c ${ADDL_SOURCES})
|
||||
TARGET_LINK_LIBRARIES(mini_parse ${LIBS})
|
||||
|
||||
ADD_EXECUTABLE(test_min_heap test_min_heap.c ../../src/liblsquic/lsquic_min_heap.c)
|
||||
ADD_TEST(min_heap test_min_heap)
|
||||
|
||||
ADD_EXECUTABLE(test_malo_pooled test_malo.c ../../src/liblsquic/lsquic_malo.c)
|
||||
SET_TARGET_PROPERTIES(test_malo_pooled
|
||||
PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS} -DLSQUIC_USE_POOLS=1")
|
||||
|
|
162
test/unittests/test_min_heap.c
Normal file
162
test/unittests/test_min_heap.c
Normal file
|
@ -0,0 +1,162 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
/* Test min heap or benchmark heap creation */
|
||||
|
||||
/* Floyd mechanism has been removed. It's not faster. */
|
||||
#define FLOYD 0
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lsquic_min_heap.h"
|
||||
|
||||
static void
|
||||
verify_min_heap (const struct min_heap *heap)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < heap->mh_nelem; ++i)
|
||||
{
|
||||
if (MHE_LCHILD(i) < heap->mh_nelem)
|
||||
assert(heap->mh_elems[i].mhe_val <=
|
||||
heap->mh_elems[MHE_LCHILD(i)].mhe_val);
|
||||
if (MHE_RCHILD(i) < heap->mh_nelem)
|
||||
assert(heap->mh_elems[i].mhe_val <=
|
||||
heap->mh_elems[MHE_RCHILD(i)].mhe_val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define MAX_ELEMS 1000
|
||||
|
||||
static void
|
||||
test_min_heap (void)
|
||||
{
|
||||
struct min_heap heap;
|
||||
uint64_t i, prev_val;
|
||||
void *p;
|
||||
struct min_heap_elem els[MAX_ELEMS];
|
||||
|
||||
heap.mh_elems = els;
|
||||
heap.mh_nalloc = MAX_ELEMS;
|
||||
|
||||
heap.mh_nelem = 0;
|
||||
for (i = 0; i < MAX_ELEMS; ++i)
|
||||
lsquic_mh_insert(&heap, (void *) i, i);
|
||||
verify_min_heap(&heap);
|
||||
for (i = 0; i < MAX_ELEMS; ++i)
|
||||
{
|
||||
p = lsquic_mh_pop(&heap);
|
||||
if (i)
|
||||
assert((uintptr_t) p >= prev_val);
|
||||
prev_val = (uintptr_t) p;
|
||||
}
|
||||
|
||||
heap.mh_nelem = 0;
|
||||
for (i = MAX_ELEMS; i > 0; --i)
|
||||
lsquic_mh_insert(&heap, (void *) i, i);
|
||||
verify_min_heap(&heap);
|
||||
for (i = 0; i < MAX_ELEMS; ++i)
|
||||
{
|
||||
p = lsquic_mh_pop(&heap);
|
||||
if (i)
|
||||
assert((uintptr_t) p >= prev_val);
|
||||
prev_val = (uintptr_t) p;
|
||||
}
|
||||
|
||||
heap.mh_nelem = 0;
|
||||
|
||||
#if FLOYD
|
||||
/* Now use Floyd method */
|
||||
heap.mh_nelem = 0;
|
||||
for (i = 0; i < MAX_ELEMS; ++i)
|
||||
lsquic_mh_push(&heap, NULL, i);
|
||||
lsquic_mh_heapify(&heap);
|
||||
verify_min_heap(&heap);
|
||||
|
||||
heap.mh_nelem = 0;
|
||||
for (i = MAX_ELEMS; i > 0; --i)
|
||||
lsquic_mh_push(&heap, NULL, i);
|
||||
lsquic_mh_heapify(&heap);
|
||||
verify_min_heap(&heap);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
if (argc == 1)
|
||||
{
|
||||
test_min_heap();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc != 4)
|
||||
{
|
||||
fprintf(stderr, "usage: %s nelems iters method\n"
|
||||
" method is 0: insert; 1: floyd\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned i, j, n_iters, nelems;
|
||||
struct min_heap_elem *els;
|
||||
unsigned *vals;
|
||||
struct min_heap heap;
|
||||
|
||||
nelems = atoi(argv[1]);
|
||||
n_iters = atoi(argv[2]);
|
||||
#if FLOYD
|
||||
const int floyd = atoi(argv[3]);
|
||||
#endif
|
||||
|
||||
vals = malloc(sizeof(vals[0]) * nelems);
|
||||
assert(vals);
|
||||
for (i = 0; i < nelems; ++i)
|
||||
vals[i] = rand();
|
||||
els = malloc(sizeof(els[0]) * nelems);
|
||||
assert(els);
|
||||
heap.mh_elems = els;
|
||||
heap.mh_nalloc = nelems;
|
||||
heap.mh_nelem = 0;
|
||||
#if FLOYD
|
||||
if (floyd)
|
||||
{
|
||||
for (i = 0; i < nelems; ++i)
|
||||
lsquic_mh_push(&heap, NULL, vals[i]);
|
||||
lsquic_mh_heapify(&heap);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
for (i = 0; i < nelems; ++i)
|
||||
lsquic_mh_insert(&heap, NULL, vals[i]);
|
||||
verify_min_heap(&heap);
|
||||
|
||||
#if FLOYD
|
||||
if (floyd)
|
||||
{
|
||||
for (j = 0; j < n_iters; ++j)
|
||||
{
|
||||
heap.mh_nelem = 0;
|
||||
for (i = 0; i < nelems; ++i)
|
||||
lsquic_mh_push(&heap, NULL, vals[i]);
|
||||
lsquic_mh_heapify(&heap);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
for (j = 0; j < n_iters; ++j)
|
||||
{
|
||||
heap.mh_nelem = 0;
|
||||
for (i = 0; i < nelems; ++i)
|
||||
lsquic_mh_insert(&heap, NULL, vals[i]);
|
||||
}
|
||||
}
|
||||
|
||||
free(els);
|
||||
free(vals);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue