Release 1.17.14

- [FEATURE] http_client can now collect stats: time to connect, TTFB,
  time to download, requests per seconds, and bandwidth.  See -t flag.

- [BUGFIX] http_client: -B, -K, and -r can be used at the same time.

- [BUGFIX] http_client: do not display cert chain before each request.
  Now this is only done once per connection, if the handshake is
  successful and -a option is given.

- [BUGFIX] Do not wait to dispatch on_close() after reading.  If a
  stream is scheduled to be closed after on_read() callback returns,
  close it immediately instead of waiting until the end of the tick.
  If client creates new request from on_close() event, they will be
  processed in the same tick instead of waiting for the next one.

- [BUGFIX] HEADERS stream is critical: always treat it with highest
  priority.
This commit is contained in:
Dmitri Tikhonov 2019-01-16 15:13:59 -05:00
parent 2815666c2e
commit 19f667fba5
24 changed files with 710 additions and 111 deletions

View file

@ -1,3 +1,19 @@
2019-01-16
- 1.17.14
- [FEATURE] http_client can now collect stats: time to connect, TTFB,
time to download, requests per seconds, and bandwidth. See -t flag.
- [BUGFIX] http_client: -B, -K, and -r can be used at the same time.
- [BUGFIX] http_client: do not display cert chain before each request.
Now this is only done once per connection, if the handshake is
successful and -a option is given.
- [BUGFIX] Do not wait to dispatch on_close() after reading. If a
stream is scheduled to be closed after on_read() callback returns,
close it immediately instead of waiting until the end of the tick.
If client creates new request from on_close() event, they will be
processed in the same tick instead of waiting for the next one.
- [BUGFIX] HEADERS stream is critical: always treat it with highest
priority.
2019-01-10 2019-01-10
- 1.17.12 - 1.17.12
- [FEATURE] http_client can now issue parallel requests in the context - [FEATURE] http_client can now issue parallel requests in the context

View file

@ -119,15 +119,15 @@ Control Network-Related Stuff
More Compilation Options More Compilation Options
------------------------ ------------------------
-DFULL_CONN_STATS=1 -DLSQUIC_CONN_STATS=1
Track some statistics about full connection -- packets in, sent, delayed, Track some statistics about connections -- packets in, sent, delayed,
stream payload per packet size ratio, and some others -- and print them stream payload per packet size ratio, and some others -- and print them
at NOTICE level when connection is destroyed. at NOTICE level when connection is destroyed.
This is useful when performing network testing and especially analyzing Cumulative connections statistics are printed by the engine when it is
the effects of changing send buffer size (see -S sndbuf= in the previous destroyed if lsquic_engine_api.ea_stats_fh is set. The HTTP client
section). programs sets it when -t or -T command-line option is used.
-DLSQUIC_PACKINTS_SANITY_CHECK=1 -DLSQUIC_PACKINTS_SANITY_CHECK=1

View file

@ -25,7 +25,7 @@ extern "C" {
#define LSQUIC_MAJOR_VERSION 1 #define LSQUIC_MAJOR_VERSION 1
#define LSQUIC_MINOR_VERSION 17 #define LSQUIC_MINOR_VERSION 17
#define LSQUIC_PATCH_VERSION 12 #define LSQUIC_PATCH_VERSION 14
/** /**
* Engine flags: * Engine flags:
@ -614,6 +614,13 @@ typedef struct lsquic_engine_api
*/ */
const struct lsquic_hset_if *ea_hsi_if; const struct lsquic_hset_if *ea_hsi_if;
void *ea_hsi_ctx; void *ea_hsi_ctx;
#if LSQUIC_CONN_STATS
/**
* If set, engine will print cumulative connection statistics to this
* file just before it is destroyed.
*/
void /* FILE, really */ *ea_stats_fh;
#endif
} lsquic_engine_api_t; } lsquic_engine_api_t;
/** /**

View file

@ -22,6 +22,9 @@ struct lsquic_packet_in;
struct sockaddr; struct sockaddr;
struct parse_funcs; struct parse_funcs;
struct attq_elem; struct attq_elem;
#if LSQUIC_CONN_STATS
struct conn_stats;
#endif
enum lsquic_conn_flags { enum lsquic_conn_flags {
LSCONN_TICKED = (1 << 0), LSCONN_TICKED = (1 << 0),
@ -83,6 +86,11 @@ struct conn_iface
lsquic_time_t lsquic_time_t
(*ci_next_tick_time) (struct lsquic_conn *); (*ci_next_tick_time) (struct lsquic_conn *);
#if LSQUIC_CONN_STATS
const struct conn_stats *
(*ci_get_stats) (struct lsquic_conn *);
#endif
}; };
struct lsquic_conn struct lsquic_conn
@ -127,4 +135,37 @@ lsquic_conn_copy_and_release_pi_data (const lsquic_conn_t *conn,
#define lsquic_conn_adv_time(c) ((c)->cn_attq_elem->ae_adv_time) #define lsquic_conn_adv_time(c) ((c)->cn_attq_elem->ae_adv_time)
#if LSQUIC_CONN_STATS
struct conn_stats {
/* All counters are of the same type, unsigned long, because we cast the
* struct to an array to update the aggregate.
*/
unsigned long n_ticks; /* How many time connection was ticked */
struct {
unsigned long stream_data_sz; /* Sum of all STREAM frames payload */
unsigned long stream_frames; /* Number of STREAM frames */
unsigned long packets, /* Incoming packets */
undec_packets, /* Undecryptable packets */
dup_packets, /* Duplicate packets */
err_packets; /* Error packets(?) */
unsigned long n_acks,
n_acks_proc,
n_acks_merged[2];
unsigned long bytes; /* Overall bytes in */
unsigned long headers_uncomp; /* Sum of uncompressed header bytes */
unsigned long headers_comp; /* Sum of compressed header bytes */
} in;
struct {
unsigned long stream_data_sz;
unsigned long stream_frames;
unsigned long acks;
unsigned long packets; /* Number of sent packets */
unsigned long retx_packets; /* Number of retransmitted packets */
unsigned long bytes; /* Overall bytes out */
unsigned long headers_uncomp; /* Sum of uncompressed header bytes */
unsigned long headers_comp; /* Sum of compressed header bytes */
} out;
};
#endif
#endif #endif

View file

@ -16,6 +16,9 @@ struct lsquic_mm;
struct lsquic_hash; struct lsquic_hash;
struct headers_stream; struct headers_stream;
struct lsquic_send_ctl; struct lsquic_send_ctl;
#if LSQUIC_CONN_STATS
struct conn_stats;
#endif
struct lsquic_conn_public { struct lsquic_conn_public {
struct lsquic_streams_tailq sending_streams, /* Send RST_STREAM, BLOCKED, and WUF frames */ struct lsquic_streams_tailq sending_streams, /* Send RST_STREAM, BLOCKED, and WUF frames */
@ -32,6 +35,9 @@ struct lsquic_conn_public {
struct lsquic_mm *mm; struct lsquic_mm *mm;
struct headers_stream *hs; struct headers_stream *hs;
struct lsquic_send_ctl *send_ctl; struct lsquic_send_ctl *send_ctl;
#if LSQUIC_CONN_STATS
struct conn_stats *conn_stats;
#endif
}; };
#endif #endif

View file

@ -171,6 +171,13 @@ struct lsquic_engine
unsigned n_conns; unsigned n_conns;
lsquic_time_t deadline; lsquic_time_t deadline;
lsquic_time_t resume_sending_at; lsquic_time_t resume_sending_at;
#if LSQUIC_CONN_STATS
struct {
unsigned conns;
} stats;
struct conn_stats conn_stats_sum;
FILE *stats_fh;
#endif
struct out_batch out_batch; struct out_batch out_batch;
}; };
@ -348,6 +355,9 @@ lsquic_engine_new (unsigned flags,
eng_hist_init(&engine->history); eng_hist_init(&engine->history);
engine->batch_size = INITIAL_OUT_BATCH_SIZE; engine->batch_size = INITIAL_OUT_BATCH_SIZE;
#if LSQUIC_CONN_STATS
engine->stats_fh = api->ea_stats_fh;
#endif
LSQ_INFO("instantiated engine"); LSQ_INFO("instantiated engine");
return engine; return engine;
@ -368,12 +378,37 @@ shrink_batch_size (struct lsquic_engine *engine)
} }
#if LSQUIC_CONN_STATS
void
update_stats_sum (struct lsquic_engine *engine, struct lsquic_conn *conn)
{
unsigned long *const dst = (unsigned long *) &engine->conn_stats_sum;
const unsigned long *src;
const struct conn_stats *stats;
unsigned i;
if (conn->cn_if->ci_get_stats && (stats = conn->cn_if->ci_get_stats(conn)))
{
++engine->stats.conns;
src = (unsigned long *) stats;
for (i = 0; i < sizeof(*stats) / sizeof(unsigned long); ++i)
dst[i] += src[i];
}
}
#endif
/* Wrapper to make sure important things occur before the connection is /* Wrapper to make sure important things occur before the connection is
* really destroyed. * really destroyed.
*/ */
static void static void
destroy_conn (struct lsquic_engine *engine, lsquic_conn_t *conn) destroy_conn (struct lsquic_engine *engine, lsquic_conn_t *conn)
{ {
#if LSQUIC_CONN_STATS
update_stats_sum(engine, conn);
#endif
--engine->n_conns; --engine->n_conns;
conn->cn_flags |= LSCONN_NEVER_TICKABLE; conn->cn_flags |= LSCONN_NEVER_TICKABLE;
conn->cn_if->ci_destroy(conn); conn->cn_if->ci_destroy(conn);
@ -580,6 +615,44 @@ lsquic_engine_destroy (lsquic_engine_t *engine)
assert(0 == lsquic_mh_count(&engine->conns_tickable)); assert(0 == lsquic_mh_count(&engine->conns_tickable));
lsquic_mm_cleanup(&engine->pub.enp_mm); lsquic_mm_cleanup(&engine->pub.enp_mm);
free(engine->conns_tickable.mh_elems); free(engine->conns_tickable.mh_elems);
#if LSQUIC_CONN_STATS
if (engine->stats_fh)
{
const struct conn_stats *const stats = &engine->conn_stats_sum;
fprintf(engine->stats_fh, "Aggregate connection stats collected by engine:\n");
fprintf(engine->stats_fh, "Connections: %u\n", engine->stats.conns);
fprintf(engine->stats_fh, "Ticks: %lu\n", stats->n_ticks);
fprintf(engine->stats_fh, "In:\n");
fprintf(engine->stats_fh, " Total bytes: %lu\n", stats->in.bytes);
fprintf(engine->stats_fh, " packets: %lu\n", stats->in.packets);
fprintf(engine->stats_fh, " undecryptable packets: %lu\n", stats->in.undec_packets);
fprintf(engine->stats_fh, " duplicate packets: %lu\n", stats->in.dup_packets);
fprintf(engine->stats_fh, " error packets: %lu\n", stats->in.err_packets);
fprintf(engine->stats_fh, " STREAM frame count: %lu\n", stats->in.stream_frames);
fprintf(engine->stats_fh, " STREAM payload size: %lu\n", stats->in.stream_data_sz);
fprintf(engine->stats_fh, " Header bytes: %lu; uncompressed: %lu; ratio %.3lf\n",
stats->in.headers_comp, stats->in.headers_uncomp,
stats->in.headers_uncomp ?
(double) stats->in.headers_comp / (double) stats->in.headers_uncomp
: 0);
fprintf(engine->stats_fh, " ACK frames: %lu\n", stats->in.n_acks);
fprintf(engine->stats_fh, " ACK frames processed: %lu\n", stats->in.n_acks_proc);
fprintf(engine->stats_fh, " ACK frames merged to new: %lu\n", stats->in.n_acks_merged[0]);
fprintf(engine->stats_fh, " ACK frames merged to old: %lu\n", stats->in.n_acks_merged[1]);
fprintf(engine->stats_fh, "Out:\n");
fprintf(engine->stats_fh, " Total bytes: %lu\n", stats->out.bytes);
fprintf(engine->stats_fh, " packets: %lu\n", stats->out.packets);
fprintf(engine->stats_fh, " retx packets: %lu\n", stats->out.retx_packets);
fprintf(engine->stats_fh, " STREAM frame count: %lu\n", stats->out.stream_frames);
fprintf(engine->stats_fh, " STREAM payload size: %lu\n", stats->out.stream_data_sz);
fprintf(engine->stats_fh, " Header bytes: %lu; uncompressed: %lu; ratio %.3lf\n",
stats->out.headers_comp, stats->out.headers_uncomp,
stats->out.headers_uncomp ?
(double) stats->out.headers_comp / (double) stats->out.headers_uncomp
: 0);
fprintf(engine->stats_fh, " ACKs: %lu\n", stats->out.acks);
}
#endif
free(engine); free(engine);
} }

View file

@ -22,6 +22,7 @@
#include "lsquic_http1x_if.h" #include "lsquic_http1x_if.h"
#include "lsquic_headers.h" #include "lsquic_headers.h"
#include "lsquic_ev_log.h" #include "lsquic_ev_log.h"
#include "lsquic_conn.h"
#define LSQUIC_LOGGER_MODULE LSQLM_FRAME_READER #define LSQUIC_LOGGER_MODULE LSQLM_FRAME_READER
#define LSQUIC_LOG_CONN_ID lsquic_conn_id(lsquic_stream_conn(fr->fr_stream)) #define LSQUIC_LOG_CONN_ID lsquic_conn_id(lsquic_stream_conn(fr->fr_stream))
@ -116,6 +117,9 @@ struct lsquic_frame_reader
* CONTINUATION frames. It gets added to as block fragments come in. * CONTINUATION frames. It gets added to as block fragments come in.
*/ */
unsigned char *fr_header_block; unsigned char *fr_header_block;
#if LSQUIC_CONN_STATS
struct conn_stats *fr_conn_stats;
#endif
unsigned fr_header_block_sz; unsigned fr_header_block_sz;
unsigned fr_max_headers_sz; /* 0 means no limit */ unsigned fr_max_headers_sz; /* 0 means no limit */
enum frame_reader_flags fr_flags; enum frame_reader_flags fr_flags;
@ -175,6 +179,9 @@ lsquic_frame_reader_new (enum frame_reader_flags flags,
struct lshpack_dec *hdec, struct lshpack_dec *hdec,
const struct frame_reader_callbacks *cb, const struct frame_reader_callbacks *cb,
void *frame_reader_cb_ctx, void *frame_reader_cb_ctx,
#if LSQUIC_CONN_STATS
struct conn_stats *conn_stats,
#endif
const struct lsquic_hset_if *hsi_if, void *hsi_ctx) const struct lsquic_hset_if *hsi_if, void *hsi_ctx)
{ {
struct lsquic_frame_reader *fr = malloc(sizeof(*fr)); struct lsquic_frame_reader *fr = malloc(sizeof(*fr));
@ -202,6 +209,9 @@ lsquic_frame_reader_new (enum frame_reader_flags flags,
else else
fr->fr_hsi_ctx = hsi_ctx; fr->fr_hsi_ctx = hsi_ctx;
reset_state(fr); reset_state(fr);
#if LSQUIC_CONN_STATS
fr->fr_conn_stats = conn_stats;
#endif
return fr; return fr;
} }
@ -538,7 +548,12 @@ decode_and_pass_payload (struct lsquic_frame_reader *fr)
fr->fr_hsi_if->hsi_process_header(hset, name_idx, buf, fr->fr_hsi_if->hsi_process_header(hset, name_idx, buf,
name_len, buf + name_len, val_len); name_len, buf + name_len, val_len);
if (err == 0) if (err == 0)
{
#if LSQUIC_CONN_STATS
fr->fr_conn_stats->in.headers_uncomp += name_len + val_len;
#endif
continue; continue;
}
} }
else else
err = FR_ERR_DECOMPRESS; err = FR_ERR_DECOMPRESS;
@ -589,6 +604,9 @@ decode_and_pass_payload (struct lsquic_frame_reader *fr)
fr->fr_callbacks->frc_on_headers(fr->fr_cb_ctx, uh); fr->fr_callbacks->frc_on_headers(fr->fr_cb_ctx, uh);
else else
fr->fr_callbacks->frc_on_push_promise(fr->fr_cb_ctx, uh); fr->fr_callbacks->frc_on_push_promise(fr->fr_cb_ctx, uh);
#if LSQUIC_CONN_STATS
fr->fr_conn_stats->in.headers_comp += fr->fr_header_block_sz;
#endif
return 0; return 0;

View file

@ -18,6 +18,9 @@ struct lsquic_stream;
struct lsquic_frame_reader; struct lsquic_frame_reader;
struct lsquic_hset_if; struct lsquic_hset_if;
struct uncompressed_headers; struct uncompressed_headers;
#if LSQUIC_CONN_STATS
struct conn_stats;
#endif
enum frame_reader_flags enum frame_reader_flags
@ -79,6 +82,9 @@ lsquic_frame_reader_new (enum frame_reader_flags, unsigned max_headers_sz,
struct lsquic_mm *, struct lsquic_stream *, struct lsquic_mm *, struct lsquic_stream *,
fr_stream_read_f, struct lshpack_dec *, fr_stream_read_f, struct lshpack_dec *,
const struct frame_reader_callbacks *, void *fr_cb_ctx, const struct frame_reader_callbacks *, void *fr_cb_ctx,
#if LSQUIC_CONN_STATS
struct conn_stats *conn_stats,
#endif
const struct lsquic_hset_if *, void *hsi_ctx); const struct lsquic_hset_if *, void *hsi_ctx);
int int

View file

@ -21,6 +21,8 @@
#include "lshpack.h" #include "lshpack.h"
#include "lsquic_mm.h" #include "lsquic_mm.h"
#include "lsquic.h" #include "lsquic.h"
#include "lsquic_int_types.h"
#include "lsquic_conn.h"
#include "lsquic_frame_writer.h" #include "lsquic_frame_writer.h"
#include "lsquic_frame_common.h" #include "lsquic_frame_common.h"
@ -65,6 +67,9 @@ struct lsquic_frame_writer
fw_write_f fw_write; fw_write_f fw_write;
struct lsquic_mm *fw_mm; struct lsquic_mm *fw_mm;
struct lshpack_enc *fw_henc; struct lshpack_enc *fw_henc;
#if LSQUIC_CONN_STATS
struct conn_stats *fw_conn_stats;
#endif
struct frame_buf_head fw_frabs; struct frame_buf_head fw_frabs;
unsigned fw_max_frame_sz; unsigned fw_max_frame_sz;
uint32_t fw_max_header_list_sz; /* 0 means unlimited */ uint32_t fw_max_header_list_sz; /* 0 means unlimited */
@ -86,6 +91,9 @@ struct lsquic_frame_writer
struct lsquic_frame_writer * struct lsquic_frame_writer *
lsquic_frame_writer_new (struct lsquic_mm *mm, struct lsquic_stream *stream, lsquic_frame_writer_new (struct lsquic_mm *mm, struct lsquic_stream *stream,
unsigned max_frame_sz, struct lshpack_enc *henc, fw_write_f write, unsigned max_frame_sz, struct lshpack_enc *henc, fw_write_f write,
#if LSQUIC_CONN_STATS
struct conn_stats *conn_stats,
#endif
int is_server) int is_server)
{ {
struct lsquic_frame_writer *fw; struct lsquic_frame_writer *fw;
@ -124,6 +132,9 @@ lsquic_frame_writer_new (struct lsquic_mm *mm, struct lsquic_stream *stream,
else else
fw->fw_flags = 0; fw->fw_flags = 0;
TAILQ_INIT(&fw->fw_frabs); TAILQ_INIT(&fw->fw_frabs);
#if LSQUIC_CONN_STATS
fw->fw_conn_stats = conn_stats;
#endif
return fw; return fw;
} }
@ -458,6 +469,12 @@ write_headers (struct lsquic_frame_writer *fw,
s = hfc_write(hfc, buf, end - buf); s = hfc_write(hfc, buf, end - buf);
if (s < 0) if (s < 0)
return s; return s;
#if LSQUIC_CONN_STATS
fw->fw_conn_stats->out.headers_uncomp +=
headers->headers[i].name.iov_len
+ headers->headers[i].value.iov_len;
fw->fw_conn_stats->out.headers_comp += end - buf;
#endif
} }
else else
{ {

View file

@ -18,13 +18,20 @@ struct lsquic_frame_writer;
struct lsquic_stream; struct lsquic_stream;
struct lsquic_http_headers; struct lsquic_http_headers;
struct lsquic_http2_setting; struct lsquic_http2_setting;
#if LSQUIC_CONN_STATS
struct conn_stats;
#endif
typedef ssize_t (*fw_write_f)(struct lsquic_stream *, const void *, size_t); typedef ssize_t (*fw_write_f)(struct lsquic_stream *, const void *, size_t);
struct lsquic_frame_writer * struct lsquic_frame_writer *
lsquic_frame_writer_new (struct lsquic_mm *, struct lsquic_stream *, lsquic_frame_writer_new (struct lsquic_mm *, struct lsquic_stream *,
unsigned max_frame_sz, struct lshpack_enc *, unsigned max_frame_sz, struct lshpack_enc *,
fw_write_f, int is_server); fw_write_f,
#if LSQUIC_CONN_STATS
struct conn_stats *,
#endif
int is_server);
void void
lsquic_frame_writer_destroy (struct lsquic_frame_writer *); lsquic_frame_writer_destroy (struct lsquic_frame_writer *);

View file

@ -188,19 +188,8 @@ struct full_conn
union { union {
struct client_hsk_ctx client; struct client_hsk_ctx client;
} fc_hsk_ctx; } fc_hsk_ctx;
#if FULL_CONN_STATS #if LSQUIC_CONN_STATS
struct { struct conn_stats fc_stats;
unsigned n_all_packets_in,
n_packets_out,
n_undec_packets,
n_dup_packets,
n_err_packets;
unsigned long stream_data_sz;
unsigned long n_ticks;
unsigned n_acks_in,
n_acks_proc,
n_acks_merged[2];
} fc_stats;
#endif #endif
#if KEEP_CLOSED_STREAM_HISTORY #if KEEP_CLOSED_STREAM_HISTORY
/* Rolling log of histories of closed streams. Older entries are /* Rolling log of histories of closed streams. Older entries are
@ -552,6 +541,9 @@ new_conn_common (lsquic_cid_t cid, struct lsquic_engine_public *enpub,
conn->fc_pub.mm = &enpub->enp_mm; conn->fc_pub.mm = &enpub->enp_mm;
conn->fc_pub.lconn = &conn->fc_conn; conn->fc_pub.lconn = &conn->fc_conn;
conn->fc_pub.send_ctl = &conn->fc_send_ctl; conn->fc_pub.send_ctl = &conn->fc_send_ctl;
#if LSQUIC_CONN_STATS
conn->fc_pub.conn_stats = &conn->fc_stats;
#endif
conn->fc_pub.packet_out_malo = conn->fc_pub.packet_out_malo =
lsquic_malo_create(sizeof(struct lsquic_packet_out)); lsquic_malo_create(sizeof(struct lsquic_packet_out));
conn->fc_stream_ifs[STREAM_IF_STD].stream_if = stream_if; conn->fc_stream_ifs[STREAM_IF_STD].stream_if = stream_if;
@ -599,7 +591,11 @@ new_conn_common (lsquic_cid_t cid, struct lsquic_engine_public *enpub,
{ {
conn->fc_pub.hs = lsquic_headers_stream_new( conn->fc_pub.hs = lsquic_headers_stream_new(
!!(conn->fc_flags & FC_SERVER), conn->fc_enpub, !!(conn->fc_flags & FC_SERVER), conn->fc_enpub,
headers_callbacks_ptr, conn); headers_callbacks_ptr,
#if LSQUIC_CONN_STATS
&conn->fc_stats,
#endif
conn);
if (!conn->fc_pub.hs) if (!conn->fc_pub.hs)
goto cleanup_on_error; goto cleanup_on_error;
conn->fc_stream_ifs[STREAM_IF_HDR].stream_if = lsquic_headers_stream_if; conn->fc_stream_ifs[STREAM_IF_HDR].stream_if = lsquic_headers_stream_if;
@ -807,18 +803,18 @@ full_conn_ci_destroy (lsquic_conn_t *lconn)
if (conn->fc_conn.cn_enc_session) if (conn->fc_conn.cn_enc_session)
conn->fc_conn.cn_esf->esf_destroy(conn->fc_conn.cn_enc_session); conn->fc_conn.cn_esf->esf_destroy(conn->fc_conn.cn_enc_session);
lsquic_malo_destroy(conn->fc_pub.packet_out_malo); lsquic_malo_destroy(conn->fc_pub.packet_out_malo);
#if FULL_CONN_STATS #if LSQUIC_CONN_STATS
LSQ_NOTICE("# ticks: %lu", conn->fc_stats.n_ticks); LSQ_NOTICE("# ticks: %lu", conn->fc_stats.n_ticks);
LSQ_NOTICE("received %u packets, of which %u were not decryptable, %u were " LSQ_NOTICE("received %lu packets, of which %lu were not decryptable, %lu were "
"dups and %u were errors; sent %u packets, avg stream data per outgoing" "dups and %lu were errors; sent %lu packets, avg stream data per outgoing"
" packet is %lu bytes", " packet is %lu bytes",
conn->fc_stats.n_all_packets_in, conn->fc_stats.n_undec_packets, conn->fc_stats.in.packets, conn->fc_stats.in.undec_packets,
conn->fc_stats.n_dup_packets, conn->fc_stats.n_err_packets, conn->fc_stats.in.dup_packets, conn->fc_stats.in.err_packets,
conn->fc_stats.n_packets_out, conn->fc_stats.out.packets,
conn->fc_stats.stream_data_sz / conn->fc_stats.n_packets_out); conn->fc_stats.out.stream_data_sz / conn->fc_stats.out.packets);
LSQ_NOTICE("ACKs: in: %u; processed: %u; merged to: new %u, old %u", LSQ_NOTICE("ACKs: in: %lu; processed: %lu; merged to: new %lu, old %lu",
conn->fc_stats.n_acks_in, conn->fc_stats.n_acks_proc, conn->fc_stats.in.n_acks, conn->fc_stats.in.n_acks_proc,
conn->fc_stats.n_acks_merged[0], conn->fc_stats.n_acks_merged[1]); conn->fc_stats.in.n_acks_merged[0], conn->fc_stats.in.n_acks_merged[1]);
#endif #endif
while ((sitr = STAILQ_FIRST(&conn->fc_stream_ids_to_reset))) while ((sitr = STAILQ_FIRST(&conn->fc_stream_ids_to_reset)))
{ {
@ -933,11 +929,11 @@ new_stream (struct full_conn *conn, uint32_t stream_id,
{ {
case LSQUIC_STREAM_HANDSHAKE: case LSQUIC_STREAM_HANDSHAKE:
idx = STREAM_IF_HSK; idx = STREAM_IF_HSK;
flags |= SCF_DI_AUTOSWITCH; flags |= SCF_DI_AUTOSWITCH|SCF_CRITICAL;
break; break;
case LSQUIC_STREAM_HEADERS: case LSQUIC_STREAM_HEADERS:
idx = STREAM_IF_HDR; idx = STREAM_IF_HDR;
flags |= SCF_DI_AUTOSWITCH; flags |= SCF_DI_AUTOSWITCH|SCF_CRITICAL;
if (!(conn->fc_flags & FC_HTTP) && if (!(conn->fc_flags & FC_HTTP) &&
conn->fc_enpub->enp_settings.es_rw_once) conn->fc_enpub->enp_settings.es_rw_once)
flags |= SCF_DISP_RW_ONCE; flags |= SCF_DISP_RW_ONCE;
@ -1138,6 +1134,10 @@ process_stream_frame (struct full_conn *conn, lsquic_packet_in_t *packet_in,
} }
EV_LOG_STREAM_FRAME_IN(LSQUIC_LOG_CONN_ID, stream_frame); EV_LOG_STREAM_FRAME_IN(LSQUIC_LOG_CONN_ID, stream_frame);
LSQ_DEBUG("Got stream frame for stream #%u", stream_frame->stream_id); LSQ_DEBUG("Got stream frame for stream #%u", stream_frame->stream_id);
#if LSQUIC_CONN_STATS
++conn->fc_stats.in.stream_frames;
conn->fc_stats.in.stream_data_sz += stream_frame->data_frame.df_size;
#endif
enc_level = lsquic_packet_in_enc_level(packet_in); enc_level = lsquic_packet_in_enc_level(packet_in);
if (stream_frame->stream_id != LSQUIC_STREAM_HANDSHAKE if (stream_frame->stream_id != LSQUIC_STREAM_HANDSHAKE
@ -1349,8 +1349,8 @@ static int
process_ack (struct full_conn *conn, struct ack_info *acki, process_ack (struct full_conn *conn, struct ack_info *acki,
lsquic_time_t received) lsquic_time_t received)
{ {
#if FULL_CONN_STATS #if LSQUIC_CONN_STATS
++conn->fc_stats.n_acks_proc; ++conn->fc_stats.in.n_acks_proc;
#endif #endif
LSQ_DEBUG("Processing ACK"); LSQ_DEBUG("Processing ACK");
if (0 == lsquic_send_ctl_got_ack(&conn->fc_send_ctl, acki, received)) if (0 == lsquic_send_ctl_got_ack(&conn->fc_send_ctl, acki, received))
@ -1470,8 +1470,8 @@ process_ack_frame (struct full_conn *conn, lsquic_packet_in_t *packet_in,
struct ack_info *const new_acki = conn->fc_pub.mm->acki; struct ack_info *const new_acki = conn->fc_pub.mm->acki;
int parsed_len; int parsed_len;
#if FULL_CONN_STATS #if LSQUIC_CONN_STATS
++conn->fc_stats.n_acks_in; ++conn->fc_stats.in.n_acks;
#endif #endif
parsed_len = conn->fc_conn.cn_pf->pf_parse_ack_frame(p, len, new_acki); parsed_len = conn->fc_conn.cn_pf->pf_parse_ack_frame(p, len, new_acki);
@ -1504,8 +1504,8 @@ process_ack_frame (struct full_conn *conn, lsquic_packet_in_t *packet_in,
case (0 << 1) | (0 << 0): case (0 << 1) | (0 << 0):
if (merge_saved_to_new(&conn->fc_saved_ack_info, new_acki)) if (merge_saved_to_new(&conn->fc_saved_ack_info, new_acki))
{ {
#if FULL_CONN_STATS #if LSQUIC_CONN_STATS
++conn->fc_stats.n_acks_merged[0] ++conn->fc_stats.in.n_acks_merged[0]
#endif #endif
; ;
} }
@ -1518,8 +1518,8 @@ process_ack_frame (struct full_conn *conn, lsquic_packet_in_t *packet_in,
case (0 << 1) | (1 << 0): case (0 << 1) | (1 << 0):
if (merge_new_to_saved(&conn->fc_saved_ack_info, new_acki)) if (merge_new_to_saved(&conn->fc_saved_ack_info, new_acki))
{ {
#if FULL_CONN_STATS #if LSQUIC_CONN_STATS
++conn->fc_stats.n_acks_merged[1] ++conn->fc_stats.in.n_acks_merged[1]
#endif #endif
; ;
} }
@ -1914,8 +1914,8 @@ process_regular_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in)
reconstruct_packet_number(conn, packet_in); reconstruct_packet_number(conn, packet_in);
EV_LOG_PACKET_IN(LSQUIC_LOG_CONN_ID, packet_in); EV_LOG_PACKET_IN(LSQUIC_LOG_CONN_ID, packet_in);
#if FULL_CONN_STATS #if LSQUIC_CONN_STATS
++conn->fc_stats.n_all_packets_in; ++conn->fc_stats.in.packets;
#endif #endif
/* The packet is decrypted before receive history is updated. This is /* The packet is decrypted before receive history is updated. This is
@ -1934,8 +1934,8 @@ process_regular_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in)
else else
{ {
LSQ_INFO("could not decrypt packet"); LSQ_INFO("could not decrypt packet");
#if FULL_CONN_STATS #if LSQUIC_CONN_STATS
++conn->fc_stats.n_undec_packets; ++conn->fc_stats.in.undec_packets;
#endif #endif
return 0; return 0;
} }
@ -1957,8 +1957,8 @@ process_regular_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in)
} }
return 0; return 0;
case REC_ST_DUP: case REC_ST_DUP:
#if FULL_CONN_STATS #if LSQUIC_CONN_STATS
++conn->fc_stats.n_dup_packets; ++conn->fc_stats.in.dup_packets;
#endif #endif
LSQ_INFO("packet %"PRIu64" is a duplicate", packet_in->pi_packno); LSQ_INFO("packet %"PRIu64" is a duplicate", packet_in->pi_packno);
return 0; return 0;
@ -1966,8 +1966,8 @@ process_regular_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in)
assert(0); assert(0);
/* Fall through */ /* Fall through */
case REC_ST_ERR: case REC_ST_ERR:
#if FULL_CONN_STATS #if LSQUIC_CONN_STATS
++conn->fc_stats.n_err_packets; ++conn->fc_stats.in.err_packets;
#endif #endif
LSQ_INFO("error processing packet %"PRIu64, packet_in->pi_packno); LSQ_INFO("error processing packet %"PRIu64, packet_in->pi_packno);
return -1; return -1;
@ -2343,7 +2343,7 @@ process_streams_ready_to_send (struct full_conn *conn)
lsquic_spi_init(&spi, TAILQ_FIRST(&conn->fc_pub.sending_streams), lsquic_spi_init(&spi, TAILQ_FIRST(&conn->fc_pub.sending_streams),
TAILQ_LAST(&conn->fc_pub.sending_streams, lsquic_streams_tailq), TAILQ_LAST(&conn->fc_pub.sending_streams, lsquic_streams_tailq),
(uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_send_stream), (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_send_stream),
STREAM_SENDING_FLAGS, conn->fc_conn.cn_cid, "send"); STREAM_SENDING_FLAGS, conn->fc_conn.cn_cid, "send", NULL, NULL);
for (stream = lsquic_spi_first(&spi); stream; for (stream = lsquic_spi_first(&spi); stream;
stream = lsquic_spi_next(&spi)) stream = lsquic_spi_next(&spi))
@ -2485,6 +2485,8 @@ static void
process_streams_read_events (struct full_conn *conn) process_streams_read_events (struct full_conn *conn)
{ {
lsquic_stream_t *stream; lsquic_stream_t *stream;
enum stream_flags service_flags;
int needs_service;
struct stream_prio_iter spi; struct stream_prio_iter spi;
if (TAILQ_EMPTY(&conn->fc_pub.read_streams)) if (TAILQ_EMPTY(&conn->fc_pub.read_streams))
@ -2493,11 +2495,21 @@ process_streams_read_events (struct full_conn *conn)
lsquic_spi_init(&spi, TAILQ_FIRST(&conn->fc_pub.read_streams), lsquic_spi_init(&spi, TAILQ_FIRST(&conn->fc_pub.read_streams),
TAILQ_LAST(&conn->fc_pub.read_streams, lsquic_streams_tailq), TAILQ_LAST(&conn->fc_pub.read_streams, lsquic_streams_tailq),
(uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_read_stream), (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_read_stream),
STREAM_WANT_READ, conn->fc_conn.cn_cid, "read"); STREAM_WANT_READ, conn->fc_conn.cn_cid, "read", NULL, NULL);
needs_service = 0;
for (stream = lsquic_spi_first(&spi); stream; for (stream = lsquic_spi_first(&spi); stream;
stream = lsquic_spi_next(&spi)) stream = lsquic_spi_next(&spi))
{
service_flags = stream->stream_flags & STREAM_SERVICE_FLAGS;
lsquic_stream_dispatch_read_events(stream); lsquic_stream_dispatch_read_events(stream);
needs_service |= service_flags
^ (stream->stream_flags & STREAM_SERVICE_FLAGS);
}
if (needs_service)
service_streams(conn);
} }
@ -2525,7 +2537,7 @@ process_streams_write_events (struct full_conn *conn, int high_prio)
TAILQ_LAST(&conn->fc_pub.write_streams, lsquic_streams_tailq), TAILQ_LAST(&conn->fc_pub.write_streams, lsquic_streams_tailq),
(uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream), (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream),
STREAM_WANT_WRITE|STREAM_WANT_FLUSH, conn->fc_conn.cn_cid, STREAM_WANT_WRITE|STREAM_WANT_FLUSH, conn->fc_conn.cn_cid,
high_prio ? "write-high" : "write-low"); high_prio ? "write-high" : "write-low", NULL, NULL);
if (high_prio) if (high_prio)
lsquic_spi_drop_non_high(&spi); lsquic_spi_drop_non_high(&spi);
@ -2633,6 +2645,9 @@ generate_ack_frame (struct full_conn *conn)
ABORT_ERROR("generating ACK frame failed: %d", errno); ABORT_ERROR("generating ACK frame failed: %d", errno);
return; return;
} }
#if LSQUIC_CONN_STATS
++conn->fc_stats.out.acks;
#endif
EV_LOG_GENERATED_ACK_FRAME(LSQUIC_LOG_CONN_ID, conn->fc_conn.cn_pf, EV_LOG_GENERATED_ACK_FRAME(LSQUIC_LOG_CONN_ID, conn->fc_conn.cn_pf,
packet_out->po_data + packet_out->po_data_sz, w); packet_out->po_data + packet_out->po_data_sz, w);
verify_ack_frame(conn, packet_out->po_data + packet_out->po_data_sz, w); verify_ack_frame(conn, packet_out->po_data + packet_out->po_data_sz, w);
@ -2796,7 +2811,7 @@ full_conn_ci_tick (lsquic_conn_t *lconn, lsquic_time_t now)
} \ } \
} while (0) } while (0)
#if FULL_CONN_STATS #if LSQUIC_CONN_STATS
++conn->fc_stats.n_ticks; ++conn->fc_stats.n_ticks;
#endif #endif
@ -3050,6 +3065,9 @@ full_conn_ci_packet_in (lsquic_conn_t *lconn, lsquic_packet_in_t *packet_in)
{ {
struct full_conn *conn = (struct full_conn *) lconn; struct full_conn *conn = (struct full_conn *) lconn;
#if LSQUIC_CONN_STATS
conn->fc_stats.in.bytes += packet_in->pi_data_sz;
#endif
lsquic_alarmset_set(&conn->fc_alset, AL_IDLE, lsquic_alarmset_set(&conn->fc_alset, AL_IDLE,
packet_in->pi_received + conn->fc_settings->es_idle_conn_to); packet_in->pi_received + conn->fc_settings->es_idle_conn_to);
if (0 == (conn->fc_flags & FC_ERROR)) if (0 == (conn->fc_flags & FC_ERROR))
@ -3086,8 +3104,9 @@ full_conn_ci_packet_sent (lsquic_conn_t *lconn, lsquic_packet_out_t *packet_out)
s = lsquic_send_ctl_sent_packet(&conn->fc_send_ctl, packet_out, 1); s = lsquic_send_ctl_sent_packet(&conn->fc_send_ctl, packet_out, 1);
if (s != 0) if (s != 0)
ABORT_ERROR("sent packet failed: %s", strerror(errno)); ABORT_ERROR("sent packet failed: %s", strerror(errno));
#if FULL_CONN_STATS #if LSQUIC_CONN_STATS
++conn->fc_stats.n_packets_out; ++conn->fc_stats.out.packets;
conn->fc_stats.out.bytes += lsquic_packet_out_sent_sz(lconn, packet_out);
#endif #endif
} }
@ -3531,6 +3550,18 @@ full_conn_ci_next_tick_time (lsquic_conn_t *lconn)
} }
#if LSQUIC_CONN_STATS
static const struct conn_stats *
full_conn_ci_get_stats (struct lsquic_conn *lconn)
{
struct full_conn *conn = (struct full_conn *) lconn;
return &conn->fc_stats;
}
#endif
static const struct headers_stream_callbacks headers_callbacks = static const struct headers_stream_callbacks headers_callbacks =
{ {
.hsc_on_headers = headers_stream_on_incoming_headers, .hsc_on_headers = headers_stream_on_incoming_headers,
@ -3545,6 +3576,9 @@ static const struct headers_stream_callbacks *headers_callbacks_ptr = &headers_c
static const struct conn_iface full_conn_iface = { static const struct conn_iface full_conn_iface = {
.ci_destroy = full_conn_ci_destroy, .ci_destroy = full_conn_ci_destroy,
#if LSQUIC_CONN_STATS
.ci_get_stats = full_conn_ci_get_stats,
#endif
.ci_handshake_failed = full_conn_ci_handshake_failed, .ci_handshake_failed = full_conn_ci_handshake_failed,
.ci_handshake_ok = full_conn_ci_handshake_ok, .ci_handshake_ok = full_conn_ci_handshake_ok,
.ci_is_tickable = full_conn_ci_is_tickable, .ci_is_tickable = full_conn_ci_is_tickable,

View file

@ -49,6 +49,9 @@ struct headers_stream
HS_HENC_INITED = (1 << 1), HS_HENC_INITED = (1 << 1),
} hs_flags; } hs_flags;
struct lsquic_engine_public *hs_enpub; struct lsquic_engine_public *hs_enpub;
#if LSQUIC_CONN_STATS
struct conn_stats *hs_conn_stats;
#endif
}; };
@ -89,6 +92,9 @@ headers_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
MAX_HEADERS_SIZE, &hs->hs_enpub->enp_mm, MAX_HEADERS_SIZE, &hs->hs_enpub->enp_mm,
stream, lsquic_stream_read, &hs->hs_hdec, stream, lsquic_stream_read, &hs->hs_hdec,
frame_callbacks_ptr, hs, frame_callbacks_ptr, hs,
#if LSQUIC_CONN_STATS
hs->hs_conn_stats,
#endif
hs->hs_enpub->enp_hsi_if, hs->hs_enpub->enp_hsi_ctx); hs->hs_enpub->enp_hsi_if, hs->hs_enpub->enp_hsi_ctx);
if (!hs->hs_fr) if (!hs->hs_fr)
{ {
@ -97,7 +103,11 @@ headers_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
return NULL; return NULL;
} }
hs->hs_fw = lsquic_frame_writer_new(&hs->hs_enpub->enp_mm, stream, 0, hs->hs_fw = lsquic_frame_writer_new(&hs->hs_enpub->enp_mm, stream, 0,
&hs->hs_henc, lsquic_stream_write, (hs->hs_flags & HS_IS_SERVER)); &hs->hs_henc, lsquic_stream_write,
#if LSQUIC_CONN_STATS
hs->hs_conn_stats,
#endif
(hs->hs_flags & HS_IS_SERVER));
if (!hs->hs_fw) if (!hs->hs_fw)
{ {
LSQ_WARN("could not create frame writer: %s", strerror(errno)); LSQ_WARN("could not create frame writer: %s", strerror(errno));
@ -196,6 +206,9 @@ lsquic_headers_stream_send_priority (struct headers_stream *hs,
struct headers_stream * struct headers_stream *
lsquic_headers_stream_new (int is_server, struct lsquic_engine_public *enpub, lsquic_headers_stream_new (int is_server, struct lsquic_engine_public *enpub,
const struct headers_stream_callbacks *callbacks, const struct headers_stream_callbacks *callbacks,
#if LSQUIC_CONN_STATS
struct conn_stats *conn_stats,
#endif
void *cb_ctx) void *cb_ctx)
{ {
struct headers_stream *hs = calloc(1, sizeof(*hs)); struct headers_stream *hs = calloc(1, sizeof(*hs));
@ -208,6 +221,9 @@ lsquic_headers_stream_new (int is_server, struct lsquic_engine_public *enpub,
else else
hs->hs_flags = 0; hs->hs_flags = 0;
hs->hs_enpub = enpub; hs->hs_enpub = enpub;
#if LSQUIC_CONN_STATS
hs->hs_conn_stats= conn_stats;
#endif
return hs; return hs;
} }

View file

@ -18,6 +18,9 @@ struct lsquic_frame_writer;
struct uncompressed_headers; struct uncompressed_headers;
struct lsquic_engine_public; struct lsquic_engine_public;
struct lsquic_http2_setting; struct lsquic_http2_setting;
#if LSQUIC_CONN_STATS
struct conn_stats;
#endif
/* Incoming frames result in new objects or events. Callbacks in this /* Incoming frames result in new objects or events. Callbacks in this
@ -40,6 +43,9 @@ struct headers_stream_callbacks
struct headers_stream * struct headers_stream *
lsquic_headers_stream_new (int is_server, struct lsquic_engine_public *, lsquic_headers_stream_new (int is_server, struct lsquic_engine_public *,
const struct headers_stream_callbacks *, const struct headers_stream_callbacks *,
#if LSQUIC_CONN_STATS
struct conn_stats *,
#endif
void *hs_cb_ctx); void *hs_cb_ctx);
void void

View file

@ -1117,6 +1117,9 @@ lsquic_send_ctl_next_packet_to_send (lsquic_send_ctl_t *ctl)
{ {
if (packet_out->po_regen_sz < packet_out->po_data_sz) if (packet_out->po_regen_sz < packet_out->po_data_sz)
{ {
#if LSQUIC_CONN_STATS
++ctl->sc_conn_pub->conn_stats->out.retx_packets;
#endif
update_for_resending(ctl, packet_out); update_for_resending(ctl, packet_out);
packet_out->po_flags &= ~PO_REPACKNO; packet_out->po_flags &= ~PO_REPACKNO;
} }

View file

@ -49,7 +49,9 @@ add_stream_to_spi (struct stream_prio_iter *iter, lsquic_stream_t *stream)
void void
lsquic_spi_init (struct stream_prio_iter *iter, struct lsquic_stream *first, lsquic_spi_init (struct stream_prio_iter *iter, struct lsquic_stream *first,
struct lsquic_stream *last, uintptr_t next_ptr_offset, struct lsquic_stream *last, uintptr_t next_ptr_offset,
enum stream_flags onlist_mask, lsquic_cid_t cid, const char *name) enum stream_flags onlist_mask, lsquic_cid_t cid, const char *name,
int (*filter)(void *filter_ctx, struct lsquic_stream *),
void *filter_ctx)
{ {
struct lsquic_stream *stream; struct lsquic_stream *stream;
unsigned count; unsigned count;
@ -68,14 +70,27 @@ lsquic_spi_init (struct stream_prio_iter *iter, struct lsquic_stream *first,
stream = first; stream = first;
count = 0; count = 0;
while (1) if (filter)
{ while (1)
add_stream_to_spi(iter, stream); {
++count; if (filter(filter_ctx, stream))
if (stream == last) {
break; add_stream_to_spi(iter, stream);
stream = NEXT_STREAM(stream, next_ptr_offset); ++count;
} }
if (stream == last)
break;
stream = NEXT_STREAM(stream, next_ptr_offset);
}
else
while (1)
{
add_stream_to_spi(iter, stream);
++count;
if (stream == last)
break;
stream = NEXT_STREAM(stream, next_ptr_offset);
}
if (count > 2) if (count > 2)
SPI_DEBUG("initialized; # elems: %u; sets: [ %016"PRIX64", %016"PRIX64 SPI_DEBUG("initialized; # elems: %u; sets: [ %016"PRIX64", %016"PRIX64

View file

@ -32,7 +32,9 @@ struct stream_prio_iter
void void
lsquic_spi_init (struct stream_prio_iter *, struct lsquic_stream *first, lsquic_spi_init (struct stream_prio_iter *, struct lsquic_stream *first,
struct lsquic_stream *last, uintptr_t next_ptr_offset, struct lsquic_stream *last, uintptr_t next_ptr_offset,
unsigned onlist_mask, lsquic_cid_t cid, const char *name); unsigned onlist_mask, lsquic_cid_t cid, const char *name,
int (*filter)(void *filter_ctx, struct lsquic_stream *),
void *filter_ctx);
struct lsquic_stream * struct lsquic_stream *
lsquic_spi_first (struct stream_prio_iter *); lsquic_spi_first (struct stream_prio_iter *);

View file

@ -273,6 +273,8 @@ lsquic_stream_new_ext (uint32_t id, struct lsquic_conn_public *conn_pub,
lsquic_stream_call_on_new(stream); lsquic_stream_call_on_new(stream);
if (ctor_flags & SCF_DISP_RW_ONCE) if (ctor_flags & SCF_DISP_RW_ONCE)
stream->stream_flags |= STREAM_RW_ONCE; stream->stream_flags |= STREAM_RW_ONCE;
if (ctor_flags & SCF_CRITICAL)
stream->stream_flags |= STREAM_CRITICAL;
return stream; return stream;
} }
@ -1574,6 +1576,9 @@ stream_write_to_packet (struct frame_gen_ctx *fg_ctx, const size_t size)
packet_out->po_header_type = stream->tosend_off == 0 packet_out->po_header_type = stream->tosend_off == 0
? HETY_INITIAL : HETY_HANDSHAKE; ? HETY_INITIAL : HETY_HANDSHAKE;
#if LSQUIC_CONN_STATS
const uint64_t begin_off = stream->tosend_off;
#endif
off = packet_out->po_data_sz; off = packet_out->po_data_sz;
len = pf->pf_gen_stream_frame( len = pf->pf_gen_stream_frame(
packet_out->po_data + packet_out->po_data_sz, packet_out->po_data + packet_out->po_data_sz,
@ -1596,6 +1601,11 @@ stream_write_to_packet (struct frame_gen_ctx *fg_ctx, const size_t size)
} }
} }
#if LSQUIC_CONN_STATS
stream->conn_pub->conn_stats->out.stream_frames += 1;
stream->conn_pub->conn_stats->out.stream_data_sz
+= stream->tosend_off - begin_off;
#endif
EV_LOG_GENERATED_STREAM_FRAME(LSQUIC_LOG_CONN_ID, pf, EV_LOG_GENERATED_STREAM_FRAME(LSQUIC_LOG_CONN_ID, pf,
packet_out->po_data + packet_out->po_data_sz, len); packet_out->po_data + packet_out->po_data_sz, len);
lsquic_send_ctl_incr_pack_sz(send_ctl, packet_out, len); lsquic_send_ctl_incr_pack_sz(send_ctl, packet_out, len);

View file

@ -62,6 +62,7 @@ struct lsquic_stream
STREAM_ONNEW_DONE = (1 <<26), /* on_new_stream has been called */ STREAM_ONNEW_DONE = (1 <<26), /* on_new_stream has been called */
STREAM_AUTOSWITCH = (1 <<27), STREAM_AUTOSWITCH = (1 <<27),
STREAM_RW_ONCE = (1 <<28), /* When set, read/write events are dispatched once per call */ STREAM_RW_ONCE = (1 <<28), /* When set, read/write events are dispatched once per call */
STREAM_CRITICAL = (1 <<29),
} stream_flags; } stream_flags;
/* There are more than one reason that a stream may be put onto /* There are more than one reason that a stream may be put onto
@ -139,6 +140,7 @@ enum stream_ctor_flags
* performance. * performance.
*/ */
SCF_DISP_RW_ONCE = (1 << 3), SCF_DISP_RW_ONCE = (1 << 3),
SCF_CRITICAL = (1 << 4), /* This is a critical stream */
}; };
lsquic_stream_t * lsquic_stream_t *
@ -274,10 +276,8 @@ struct stream_read_prog_status
enum stream_flags srps_flags; enum stream_flags srps_flags;
}; };
#define lsquic_stream_is_critical(stream) ( \ #define lsquic_stream_is_critical(stream) \
(stream)->id == LSQUIC_STREAM_HANDSHAKE || \ ((stream)->stream_flags & STREAM_CRITICAL)
((stream)->id == LSQUIC_STREAM_HEADERS && \
(stream)->stream_flags & STREAM_USE_HEADERS))
size_t size_t
lsquic_stream_mem_used (const struct lsquic_stream *); lsquic_stream_mem_used (const struct lsquic_stream *);

View file

@ -31,6 +31,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <event2/event.h> #include <event2/event.h>
#include <math.h>
#ifndef WIN32 #ifndef WIN32
@ -44,12 +45,16 @@
#include "prog.h" #include "prog.h"
#include "../src/liblsquic/lsquic_logger.h" #include "../src/liblsquic/lsquic_logger.h"
#include "../src/liblsquic/lsquic_int_types.h"
#include "../src/liblsquic/lsquic_util.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b))
/* This is used to exercise generating and sending of priority frames */ /* This is used to exercise generating and sending of priority frames */
static int randomly_reprioritize_streams; static int randomly_reprioritize_streams;
static int s_display_cert_chain;
/* If this file descriptor is open, the client will accept server push and /* If this file descriptor is open, the client will accept server push and
* dump the contents here. See -u flag. * dump the contents here. See -u flag.
*/ */
@ -61,6 +66,71 @@ static int promise_fd = -1;
*/ */
static int g_header_bypass; static int g_header_bypass;
static int s_discard_response;
struct sample_stats
{
unsigned n;
unsigned long min, max;
unsigned long sum; /* To calculate mean */
unsigned long sum_X2; /* To calculate stddev */
};
static struct sample_stats s_stat_to_conn, /* Time to connect */
s_stat_ttfb,
s_stat_req; /* From TTFB to EOS */
static unsigned s_stat_conns_ok, s_stat_conns_failed;
static unsigned long s_stat_downloaded_bytes;
static void
update_sample_stats (struct sample_stats *stats, unsigned long val)
{
LSQ_DEBUG("%s: %p: %lu", __func__, stats, val);
if (stats->n)
{
if (val < stats->min)
stats->min = val;
else if (val > stats->max)
stats->max = val;
}
else
{
stats->min = val;
stats->max = val;
}
stats->sum += val;
stats->sum_X2 += val * val;
++stats->n;
}
static void
calc_sample_stats (const struct sample_stats *stats,
long double *mean_p, long double *stddev_p)
{
unsigned long mean, tmp;
if (stats->n)
{
mean = stats->sum / stats->n;
*mean_p = (long double) mean;
if (stats->n > 1)
{
tmp = stats->sum_X2 - stats->n * mean * mean;
tmp /= stats->n - 1;
*stddev_p = sqrtl((long double) tmp);
}
else
*stddev_p = 0;
}
else
{
*mean_p = 0;
*stddev_p = 0;
}
}
struct lsquic_conn_ctx; struct lsquic_conn_ctx;
struct path_elem { struct path_elem {
@ -91,10 +161,8 @@ struct http_client_ctx {
unsigned hcc_n_open_conns; unsigned hcc_n_open_conns;
enum { enum {
HCC_DISCARD_RESPONSE = (1 << 0),
HCC_SEEN_FIN = (1 << 1), HCC_SEEN_FIN = (1 << 1),
HCC_ABORT_ON_INCOMPLETE = (1 << 2), HCC_ABORT_ON_INCOMPLETE = (1 << 2),
HCC_PROCESSED_HEADERS = (1 << 3),
} hcc_flags; } hcc_flags;
struct prog *prog; struct prog *prog;
}; };
@ -103,6 +171,7 @@ struct lsquic_conn_ctx {
TAILQ_ENTRY(lsquic_conn_ctx) next_ch; TAILQ_ENTRY(lsquic_conn_ctx) next_ch;
lsquic_conn_t *conn; lsquic_conn_t *conn;
struct http_client_ctx *client_ctx; struct http_client_ctx *client_ctx;
lsquic_time_t ch_created;
unsigned ch_n_reqs; /* This number gets decremented as streams are closed and unsigned ch_n_reqs; /* This number gets decremented as streams are closed and
* incremented as push promises are accepted. * incremented as push promises are accepted.
*/ */
@ -128,6 +197,8 @@ static void
hset_dump (const struct hset *, FILE *); hset_dump (const struct hset *, FILE *);
static void static void
hset_destroy (void *hset); hset_destroy (void *hset);
static void
display_cert_chain (lsquic_conn_t *);
static void static void
@ -168,6 +239,7 @@ http_client_on_new_conn (void *stream_if_ctx, lsquic_conn_t *conn)
TAILQ_INSERT_TAIL(&client_ctx->conn_ctxs, conn_h, next_ch); TAILQ_INSERT_TAIL(&client_ctx->conn_ctxs, conn_h, next_ch);
++conn_h->client_ctx->hcc_n_open_conns; ++conn_h->client_ctx->hcc_n_open_conns;
create_streams(client_ctx, conn_h); create_streams(client_ctx, conn_h);
conn_h->ch_created = lsquic_time_now();
return conn_h; return conn_h;
} }
@ -246,7 +318,21 @@ http_client_on_conn_closed (lsquic_conn_t *conn)
static void static void
http_client_on_hsk_done (lsquic_conn_t *conn, int ok) http_client_on_hsk_done (lsquic_conn_t *conn, int ok)
{ {
lsquic_conn_ctx_t *conn_h;
LSQ_INFO("handshake %s", ok ? "completed successfully" : "failed"); LSQ_INFO("handshake %s", ok ? "completed successfully" : "failed");
if (ok && s_display_cert_chain)
display_cert_chain(conn);
if (ok)
{
conn_h = lsquic_conn_get_ctx(conn);
++s_stat_conns_ok;
update_sample_stats(&s_stat_to_conn,
lsquic_time_now() - conn_h->ch_created);
}
else
++s_stat_conns_failed;
} }
@ -256,8 +342,10 @@ struct lsquic_stream_ctx {
const char *path; const char *path;
enum { enum {
HEADERS_SENT = (1 << 0), HEADERS_SENT = (1 << 0),
CHAIN_DISPLAYED = (1 << 1), PROCESSED_HEADERS = 1 << 1,
} sh_flags; } sh_flags;
lsquic_time_t sh_created;
lsquic_time_t sh_ttfb;
unsigned count; unsigned count;
struct lsquic_reader reader; struct lsquic_reader reader;
}; };
@ -278,6 +366,7 @@ http_client_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
lsquic_stream_ctx_t *st_h = calloc(1, sizeof(*st_h)); lsquic_stream_ctx_t *st_h = calloc(1, sizeof(*st_h));
st_h->stream = stream; st_h->stream = stream;
st_h->client_ctx = stream_if_ctx; st_h->client_ctx = stream_if_ctx;
st_h->sh_created = lsquic_time_now();
if (st_h->client_ctx->hcc_cur_pe) if (st_h->client_ctx->hcc_cur_pe)
{ {
st_h->client_ctx->hcc_cur_pe = TAILQ_NEXT( st_h->client_ctx->hcc_cur_pe = TAILQ_NEXT(
@ -406,12 +495,6 @@ http_client_on_write (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
{ {
ssize_t nw; ssize_t nw;
if (!(st_h->sh_flags & CHAIN_DISPLAYED))
{
display_cert_chain(lsquic_stream_conn(stream));
st_h->sh_flags |= CHAIN_DISPLAYED;
}
if (st_h->sh_flags & HEADERS_SENT) if (st_h->sh_flags & HEADERS_SENT)
{ {
if (st_h->client_ctx->payload && test_reader_size(st_h->reader.lsqr_ctx) > 0) if (st_h->client_ctx->payload && test_reader_size(st_h->reader.lsqr_ctx) > 0)
@ -459,8 +542,7 @@ http_client_on_read (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
srand(GetTickCount()); srand(GetTickCount());
#endif #endif
if (g_header_bypass if (g_header_bypass && !(st_h->sh_flags & PROCESSED_HEADERS))
&& !(client_ctx->hcc_flags & HCC_PROCESSED_HEADERS))
{ {
hset = lsquic_stream_get_hset(stream); hset = lsquic_stream_get_hset(stream);
if (!hset) if (!hset)
@ -468,10 +550,14 @@ http_client_on_read (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
LSQ_ERROR("could not get header set from stream"); LSQ_ERROR("could not get header set from stream");
exit(2); exit(2);
} }
if (!(client_ctx->hcc_flags & HCC_DISCARD_RESPONSE)) st_h->sh_ttfb = lsquic_time_now();
update_sample_stats(&s_stat_ttfb, st_h->sh_ttfb - st_h->sh_created);
if (s_discard_response)
LSQ_DEBUG("discard response: do not dump headers");
else
hset_dump(hset, stdout); hset_dump(hset, stdout);
hset_destroy(hset); hset_destroy(hset);
client_ctx->hcc_flags |= HCC_PROCESSED_HEADERS; st_h->sh_flags |= PROCESSED_HEADERS;
} }
do do
@ -479,7 +565,16 @@ http_client_on_read (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
nread = lsquic_stream_read(stream, buf, sizeof(buf)); nread = lsquic_stream_read(stream, buf, sizeof(buf));
if (nread > 0) if (nread > 0)
{ {
if (!(client_ctx->hcc_flags & HCC_DISCARD_RESPONSE)) s_stat_downloaded_bytes += nread;
if (!g_header_bypass && !(st_h->sh_flags & PROCESSED_HEADERS))
{
/* First read is assumed to be the first byte */
st_h->sh_ttfb = lsquic_time_now();
update_sample_stats(&s_stat_ttfb,
st_h->sh_ttfb - st_h->sh_created);
st_h->sh_flags |= PROCESSED_HEADERS;
}
if (!s_discard_response)
write(STDOUT_FILENO, buf, nread); write(STDOUT_FILENO, buf, nread);
if (randomly_reprioritize_streams && (st_h->count++ & 0x3F) == 0) if (randomly_reprioritize_streams && (st_h->count++ & 0x3F) == 0)
{ {
@ -496,6 +591,7 @@ http_client_on_read (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
} }
else if (0 == nread) else if (0 == nread)
{ {
update_sample_stats(&s_stat_req, lsquic_time_now() - st_h->sh_ttfb);
client_ctx->hcc_flags |= HCC_SEEN_FIN; client_ctx->hcc_flags |= HCC_SEEN_FIN;
lsquic_stream_shutdown(stream, 0); lsquic_stream_shutdown(stream, 0);
break; break;
@ -597,6 +693,9 @@ usage (const char *prog)
" -C DIR Certificate store. If specified, server certificate will\n" " -C DIR Certificate store. If specified, server certificate will\n"
" be verified.\n" " be verified.\n"
#endif #endif
" -a Display server certificate chain after successful handshake.\n"
" -t Print stats to stdout.\n"
" -T FILE Print stats to FILE. If FILE is -, print stats to stdout.\n"
, prog); , prog);
} }
@ -708,8 +807,9 @@ hset_create (void *hsi_ctx, int is_push_promise)
{ {
struct hset *hset; struct hset *hset;
hset = malloc(sizeof(*hset)); if (s_discard_response)
if (hset) return (void *) 1;
else if ((hset = malloc(sizeof(*hset))))
{ {
STAILQ_INIT(hset); STAILQ_INIT(hset);
return hset; return hset;
@ -727,6 +827,14 @@ hset_add_header (void *hset_p, unsigned name_idx,
struct hset *hset = hset_p; struct hset *hset = hset_p;
struct hset_elem *el; struct hset_elem *el;
if (name)
s_stat_downloaded_bytes += name_len + value_len + 4; /* ": \r\n" */
else
s_stat_downloaded_bytes += 2; /* \r\n "*/
if (s_discard_response)
return LSQUIC_HDR_OK;
if (!name) /* This signals end of headers. We do no post-processing. */ if (!name) /* This signals end of headers. We do no post-processing. */
return LSQUIC_HDR_OK; return LSQUIC_HDR_OK;
@ -756,14 +864,17 @@ hset_destroy (void *hset_p)
struct hset *hset = hset_p; struct hset *hset = hset_p;
struct hset_elem *el, *next; struct hset_elem *el, *next;
for (el = STAILQ_FIRST(hset); el; el = next) if (!s_discard_response)
{ {
next = STAILQ_NEXT(el, next); for (el = STAILQ_FIRST(hset); el; el = next)
free(el->name); {
free(el->value); next = STAILQ_NEXT(el, next);
free(el); free(el->name);
free(el->value);
free(el);
}
free(hset);
} }
free(hset);
} }
@ -796,10 +907,25 @@ static const struct lsquic_hset_if header_bypass_api =
}; };
static void
display_stat (FILE *out, const struct sample_stats *stats, const char *name)
{
long double mean, stddev;
calc_sample_stats(stats, &mean, &stddev);
fprintf(out, "%s: n: %u; min: %.2Lf ms; max: %.2Lf ms; mean: %.2Lf ms; "
"sd: %.2Lf ms\n", name, stats->n, (long double) stats->min / 1000,
(long double) stats->max / 1000, mean / 1000, stddev / 1000);
}
int int
main (int argc, char **argv) main (int argc, char **argv)
{ {
int opt, s; int opt, s;
lsquic_time_t start_time;
FILE *stats_fh = NULL;
long double elapsed;
struct http_client_ctx client_ctx; struct http_client_ctx client_ctx;
struct stat st; struct stat st;
struct path_elem *pe; struct path_elem *pe;
@ -825,11 +951,14 @@ main (int argc, char **argv)
while (-1 != (opt = getopt(argc, argv, PROG_OPTS "46Br:R:IKu:EP:M:n:w:H:p:h" while (-1 != (opt = getopt(argc, argv, PROG_OPTS "46Br:R:IKu:EP:M:n:w:H:p:h"
#ifndef WIN32 #ifndef WIN32
"C:" "C:atT:"
#endif #endif
))) )))
{ {
switch (opt) { switch (opt) {
case 'a':
++s_display_cert_chain;
break;
case '4': case '4':
case '6': case '6':
prog.prog_ipver = opt - '0'; prog.prog_ipver = opt - '0';
@ -843,7 +972,7 @@ main (int argc, char **argv)
client_ctx.hcc_flags |= HCC_ABORT_ON_INCOMPLETE; client_ctx.hcc_flags |= HCC_ABORT_ON_INCOMPLETE;
break; break;
case 'K': case 'K':
client_ctx.hcc_flags |= HCC_DISCARD_RESPONSE; ++s_discard_response;
break; break;
case 'u': /* Accept p<U>sh promise */ case 'u': /* Accept p<U>sh promise */
promise_fd = open(optarg, O_WRONLY|O_CREAT|O_TRUNC, 0644); promise_fd = open(optarg, O_WRONLY|O_CREAT|O_TRUNC, 0644);
@ -902,18 +1031,39 @@ main (int argc, char **argv)
prog.prog_api.ea_verify_ctx = optarg; prog.prog_api.ea_verify_ctx = optarg;
break; break;
#endif #endif
case 't':
stats_fh = stdout;
break;
case 'T':
if (0 == strcmp(optarg, "-"))
stats_fh = stdout;
else
{
stats_fh = fopen(optarg, "w");
if (!stats_fh)
{
perror("fopen");
exit(1);
}
}
break;
default: default:
if (0 != prog_set_opt(&prog, opt, optarg)) if (0 != prog_set_opt(&prog, opt, optarg))
exit(1); exit(1);
} }
} }
#if LSQUIC_CONN_STATS
prog.prog_api.ea_stats_fh = stats_fh;
#endif
if (TAILQ_EMPTY(&client_ctx.hcc_path_elems)) if (TAILQ_EMPTY(&client_ctx.hcc_path_elems))
{ {
fprintf(stderr, "Specify at least one path using -p option\n"); fprintf(stderr, "Specify at least one path using -p option\n");
exit(1); exit(1);
} }
start_time = lsquic_time_now();
if (0 != prog_prep(&prog)) if (0 != prog_prep(&prog))
{ {
LSQ_ERROR("could not prep"); LSQ_ERROR("could not prep");
@ -925,6 +1075,21 @@ main (int argc, char **argv)
LSQ_DEBUG("entering event loop"); LSQ_DEBUG("entering event loop");
s = prog_run(&prog); s = prog_run(&prog);
if (stats_fh)
{
elapsed = (long double) (lsquic_time_now() - start_time) / 1000000;
fprintf(stats_fh, "overall statistics as calculated by %s:\n", argv[0]);
display_stat(stats_fh, &s_stat_to_conn, "time for connect");
display_stat(stats_fh, &s_stat_req, "time for request");
display_stat(stats_fh, &s_stat_ttfb, "time to 1st byte");
fprintf(stats_fh, "downloaded %lu application bytes in %.3Lf seconds\n",
s_stat_downloaded_bytes, elapsed);
fprintf(stats_fh, "%.2Lf reqs/sec; %.0Lf bytes/sec\n",
(long double) s_stat_req.n / elapsed,
(long double) s_stat_downloaded_bytes / elapsed);
}
prog_cleanup(&prog); prog_cleanup(&prog);
if (promise_fd >= 0) if (promise_fd >= 0)
(void) close(promise_fd); (void) close(promise_fd);

View file

@ -27,6 +27,10 @@
#include "lsquic_frame_common.h" #include "lsquic_frame_common.h"
#include "lsquic_frame_writer.h" #include "lsquic_frame_writer.h"
#include "lsquic_frame_reader.h" #include "lsquic_frame_reader.h"
#if LSQUIC_CONN_STATS
#include "lsquic_int_types.h"
#include "lsquic_conn.h"
#endif
struct lsquic_stream struct lsquic_stream
@ -98,11 +102,20 @@ test_chop (unsigned max_write_sz)
struct lshpack_enc henc; struct lshpack_enc henc;
int s; int s;
#if LSQUIC_CONN_STATS
struct conn_stats conn_stats;
memset(&conn_stats, 0, sizeof(conn_stats));
#endif
lsquic_mm_init(&mm); lsquic_mm_init(&mm);
lshpack_enc_init(&henc); lshpack_enc_init(&henc);
stream = stream_new(max_write_sz); stream = stream_new(max_write_sz);
fw = lsquic_frame_writer_new(&mm, stream, 0, &henc, stream_write, 0); fw = lsquic_frame_writer_new(&mm, stream, 0, &henc, stream_write,
#if LSQUIC_CONN_STATS
&conn_stats,
#endif
0);
struct lsquic_http_header header_arr[] = struct lsquic_http_header header_arr[] =
{ {

View file

@ -23,6 +23,10 @@
#include "lsquic_stream.h" #include "lsquic_stream.h"
#include "lsquic_conn_public.h" #include "lsquic_conn_public.h"
#include "lsquic_logger.h" #include "lsquic_logger.h"
#if LSQUIC_CONN_STATS
#include "lsquic_int_types.h"
#include "lsquic_conn.h"
#endif
#include "lsquic_frame_reader.h" #include "lsquic_frame_reader.h"
#include "lsquic_headers.h" #include "lsquic_headers.h"
@ -1105,6 +1109,11 @@ test_one_frt (const struct frame_reader_test *frt)
struct lsquic_stream stream; struct lsquic_stream stream;
int s; int s;
#if LSQUIC_CONN_STATS
struct conn_stats conn_stats;
memset(&conn_stats, 0, sizeof(conn_stats));
#endif
memset(&stream, 0, sizeof(stream)); memset(&stream, 0, sizeof(stream));
memset(&lconn, 0, sizeof(lconn)); memset(&lconn, 0, sizeof(lconn));
memset(&conn_pub, 0, sizeof(conn_pub)); memset(&conn_pub, 0, sizeof(conn_pub));
@ -1125,6 +1134,9 @@ test_one_frt (const struct frame_reader_test *frt)
fr = lsquic_frame_reader_new(frt->frt_fr_flags, frt->frt_max_headers_sz, fr = lsquic_frame_reader_new(frt->frt_fr_flags, frt->frt_max_headers_sz,
&mm, &stream, read_from_stream, &hdec, &frame_callbacks, &g_cb_ctx, &mm, &stream, read_from_stream, &hdec, &frame_callbacks, &g_cb_ctx,
#if LSQUIC_CONN_STATS
&conn_stats,
#endif
lsquic_http1x_if, NULL); lsquic_http1x_if, NULL);
do do
{ {

View file

@ -29,6 +29,10 @@
#include "lsquic_frame_reader.h" #include "lsquic_frame_reader.h"
#include "lsquic_headers.h" #include "lsquic_headers.h"
#include "lsquic_http1x_if.h" #include "lsquic_http1x_if.h"
#if LSQUIC_CONN_STATS
#include "lsquic_int_types.h"
#include "lsquic_conn.h"
#endif
struct lsquic_stream struct lsquic_stream
@ -192,6 +196,10 @@ test_rw (unsigned max_frame_sz)
struct lshpack_enc henc; struct lshpack_enc henc;
struct lshpack_dec hdec; struct lshpack_dec hdec;
int s; int s;
#if LSQUIC_CONN_STATS
struct conn_stats conn_stats;
memset(&conn_stats, 0, sizeof(conn_stats));
#endif
lsquic_mm_init(&mm); lsquic_mm_init(&mm);
lshpack_enc_init(&henc); lshpack_enc_init(&henc);
@ -200,7 +208,11 @@ test_rw (unsigned max_frame_sz)
stream->sm_max_sz = 1; stream->sm_max_sz = 1;
fw = lsquic_frame_writer_new(&mm, stream, max_frame_sz, &henc, fw = lsquic_frame_writer_new(&mm, stream, max_frame_sz, &henc,
stream_write, 0); stream_write,
#if LSQUIC_CONN_STATS
&conn_stats,
#endif
0);
struct lsquic_http_headers headers = { struct lsquic_http_headers headers = {
.count = N_HEADERS, .count = N_HEADERS,
@ -216,7 +228,11 @@ test_rw (unsigned max_frame_sz)
stream->sm_off = 0; stream->sm_off = 0;
fr = lsquic_frame_reader_new(0, 0, &mm, stream, read_from_stream, &hdec, fr = lsquic_frame_reader_new(0, 0, &mm, stream, read_from_stream, &hdec,
&frame_callbacks, &uh, lsquic_http1x_if, NULL); &frame_callbacks, &uh,
#if LSQUIC_CONN_STATS
&conn_stats,
#endif
lsquic_http1x_if, NULL);
do do
{ {
s = lsquic_frame_reader_read(fr); s = lsquic_frame_reader_read(fr);

View file

@ -14,6 +14,14 @@
#include "lsquic_mm.h" #include "lsquic_mm.h"
#include "lsquic_frame_common.h" #include "lsquic_frame_common.h"
#include "lsquic_frame_writer.h" #include "lsquic_frame_writer.h"
#if LSQUIC_CONN_STATS
#include "lsquic_int_types.h"
#include "lsquic_conn.h"
#endif
#if LSQUIC_CONN_STATS
static struct conn_stats s_conn_stats;
#endif
static struct { static struct {
@ -65,11 +73,19 @@ test_max_frame_size (void)
for (max_size = 1; max_size < 6 /* one settings frame */; ++max_size) for (max_size = 1; max_size < 6 /* one settings frame */; ++max_size)
{ {
fw = lsquic_frame_writer_new(&mm, NULL, max_size, &henc, fw = lsquic_frame_writer_new(&mm, NULL, max_size, &henc,
output_write, 0); output_write,
#if LSQUIC_CONN_STATS
&s_conn_stats,
#endif
0);
assert(!fw); assert(!fw);
} }
fw = lsquic_frame_writer_new(&mm, NULL, max_size, &henc, output_write, 0); fw = lsquic_frame_writer_new(&mm, NULL, max_size, &henc, output_write,
#if LSQUIC_CONN_STATS
&s_conn_stats,
#endif
0);
assert(fw); assert(fw);
lsquic_frame_writer_destroy(fw); lsquic_frame_writer_destroy(fw);
@ -88,7 +104,11 @@ test_one_header (void)
lshpack_enc_init(&henc); lshpack_enc_init(&henc);
lsquic_mm_init(&mm); lsquic_mm_init(&mm);
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write, 0); fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write,
#if LSQUIC_CONN_STATS
&s_conn_stats,
#endif
0);
reset_output(0); reset_output(0);
struct lsquic_http_header header_arr[] = struct lsquic_http_header header_arr[] =
@ -148,7 +168,11 @@ test_oversize_header (void)
lshpack_enc_init(&henc); lshpack_enc_init(&henc);
lsquic_mm_init(&mm); lsquic_mm_init(&mm);
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write, 0); fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write,
#if LSQUIC_CONN_STATS
&s_conn_stats,
#endif
0);
reset_output(0); reset_output(0);
value = malloc(big_len); value = malloc(big_len);
@ -186,7 +210,11 @@ test_continuations (void)
lshpack_enc_init(&henc); lshpack_enc_init(&henc);
lsquic_mm_init(&mm); lsquic_mm_init(&mm);
fw = lsquic_frame_writer_new(&mm, NULL, 6, &henc, output_write, 0); fw = lsquic_frame_writer_new(&mm, NULL, 6, &henc, output_write,
#if LSQUIC_CONN_STATS
&s_conn_stats,
#endif
0);
reset_output(0); reset_output(0);
/* /*
@ -271,7 +299,11 @@ test_settings_short (void)
struct lsquic_mm mm; struct lsquic_mm mm;
lsquic_mm_init(&mm); lsquic_mm_init(&mm);
fw = lsquic_frame_writer_new(&mm, NULL, 7, NULL, output_write, 0); fw = lsquic_frame_writer_new(&mm, NULL, 7, NULL, output_write,
#if LSQUIC_CONN_STATS
&s_conn_stats,
#endif
0);
{ {
reset_output(0); reset_output(0);
@ -315,7 +347,11 @@ test_settings_normal (void)
struct lsquic_mm mm; struct lsquic_mm mm;
lsquic_mm_init(&mm); lsquic_mm_init(&mm);
fw = lsquic_frame_writer_new(&mm, NULL, 0, NULL, output_write, 0); fw = lsquic_frame_writer_new(&mm, NULL, 0, NULL, output_write,
#if LSQUIC_CONN_STATS
&s_conn_stats,
#endif
0);
{ {
reset_output(0); reset_output(0);
@ -372,7 +408,11 @@ test_priority (void)
struct lsquic_mm mm; struct lsquic_mm mm;
lsquic_mm_init(&mm); lsquic_mm_init(&mm);
fw = lsquic_frame_writer_new(&mm, NULL, 6, NULL, output_write, 0); fw = lsquic_frame_writer_new(&mm, NULL, 6, NULL, output_write,
#if LSQUIC_CONN_STATS
&s_conn_stats,
#endif
0);
s = lsquic_frame_writer_write_priority(fw, 3, 0, 1UL << 31, 256); s = lsquic_frame_writer_write_priority(fw, 3, 0, 1UL << 31, 256);
assert(s < 0); /* Invalid dependency stream ID */ assert(s < 0); /* Invalid dependency stream ID */
@ -431,7 +471,11 @@ test_errors (void)
lshpack_enc_init(&henc); lshpack_enc_init(&henc);
lsquic_mm_init(&mm); lsquic_mm_init(&mm);
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write, 1); fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write,
#if LSQUIC_CONN_STATS
&s_conn_stats,
#endif
1);
reset_output(0); reset_output(0);
{ {
@ -481,7 +525,11 @@ test_push_promise (void)
lshpack_enc_init(&henc); lshpack_enc_init(&henc);
lsquic_mm_init(&mm); lsquic_mm_init(&mm);
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write, 1); fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write,
#if LSQUIC_CONN_STATS
&s_conn_stats,
#endif
1);
reset_output(0); reset_output(0);
/* /*

View file

@ -72,7 +72,7 @@ test_same_priority (unsigned priority)
lsquic_spi_init(&spi, TAILQ_FIRST(&streams), lsquic_spi_init(&spi, TAILQ_FIRST(&streams),
TAILQ_LAST(&streams, lsquic_streams_tailq), TAILQ_LAST(&streams, lsquic_streams_tailq),
(uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream), (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream),
flags, 0, __func__); flags, 0, __func__, NULL, NULL);
stream = lsquic_spi_first(&spi); stream = lsquic_spi_first(&spi);
assert(stream == stream_arr[0]); assert(stream == stream_arr[0]);
@ -88,7 +88,7 @@ test_same_priority (unsigned priority)
/* Test reinitialization: */ /* Test reinitialization: */
lsquic_spi_init(&spi, stream_arr[0], stream_arr[1], lsquic_spi_init(&spi, stream_arr[0], stream_arr[1],
(uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream), (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream),
flags, 0, __func__); flags, 0, __func__, NULL, NULL);
stream = lsquic_spi_first(&spi); stream = lsquic_spi_first(&spi);
assert(stream == stream_arr[0]); assert(stream == stream_arr[0]);
stream = lsquic_spi_next(&spi); stream = lsquic_spi_next(&spi);
@ -122,7 +122,7 @@ test_different_priorities (int *priority)
lsquic_spi_init(&spi, TAILQ_FIRST(&streams), lsquic_spi_init(&spi, TAILQ_FIRST(&streams),
TAILQ_LAST(&streams, lsquic_streams_tailq), TAILQ_LAST(&streams, lsquic_streams_tailq),
(uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_send_stream), (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_send_stream),
flags, 0, __func__); flags, 0, __func__, NULL, NULL);
for (prev_prio = -1, count = 0, stream = lsquic_spi_first(&spi); stream; for (prev_prio = -1, count = 0, stream = lsquic_spi_first(&spi); stream;
stream = lsquic_spi_next(&spi), ++count) stream = lsquic_spi_next(&spi), ++count)
@ -209,7 +209,7 @@ test_drop (const struct drop_test *test)
lsquic_spi_init(&spi, TAILQ_FIRST(&streams), lsquic_spi_init(&spi, TAILQ_FIRST(&streams),
TAILQ_LAST(&streams, lsquic_streams_tailq), TAILQ_LAST(&streams, lsquic_streams_tailq),
(uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream), (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream),
STREAM_WRITE_Q_FLAGS, 0, __func__); STREAM_WRITE_Q_FLAGS, 0, __func__, NULL, NULL);
if (drop_high) if (drop_high)
lsquic_spi_drop_high(&spi); lsquic_spi_drop_high(&spi);
@ -229,6 +229,69 @@ test_drop (const struct drop_test *test)
} }
#define MAGIC 0x12312312U
struct my_filter_ctx
{
unsigned magic;
};
static int
filter_out_odd_priorities (void *ctx, lsquic_stream_t *stream)
{
struct my_filter_ctx *fctx = ctx;
assert(fctx->magic == MAGIC);
return 0 == (stream->sm_priority & 1);
}
static void
test_different_priorities_filter_odd (int *priority)
{
struct lsquic_streams_tailq streams;
unsigned flags = 0xC000; /* Arbitrary value */
lsquic_stream_t *stream;
int prio, prev_prio, count, n_streams = 0;
TAILQ_INIT(&streams);
for ( ; *priority >= 0; ++priority)
{
assert(*priority < 256);
stream = new_stream(*priority);
TAILQ_INSERT_TAIL(&streams, stream, next_send_stream);
stream->stream_flags |= flags;
++n_streams;
}
struct my_filter_ctx my_filter_ctx = { MAGIC };
lsquic_spi_init(&spi, TAILQ_FIRST(&streams),
TAILQ_LAST(&streams, lsquic_streams_tailq),
(uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_send_stream),
flags, 0, NULL, filter_out_odd_priorities, &my_filter_ctx);
for (prev_prio = -1, count = 0, stream = lsquic_spi_first(&spi); stream;
stream = lsquic_spi_next(&spi), ++count)
{
prio = stream->sm_priority;
assert(0 == (prio & 1));
assert(prio >= prev_prio);
if (prio > prev_prio)
prev_prio = prio;
}
assert(count < n_streams);
while ((stream = TAILQ_FIRST(&streams)))
{
TAILQ_REMOVE(&streams, stream, next_send_stream);
free(stream);
}
}
int int
main (int argc, char **argv) main (int argc, char **argv)
{ {
@ -259,6 +322,11 @@ main (int argc, char **argv)
test_different_priorities(prio); test_different_priorities(prio);
} }
{
int prio[] = { 200, 202, 240, 201, 200, 199, -1 };
test_different_priorities_filter_odd(prio);
}
unsigned n; unsigned n;
for (n = 0; n < sizeof(drop_tests) / sizeof(drop_tests[0]); ++n) for (n = 0; n < sizeof(drop_tests) / sizeof(drop_tests[0]); ++n)
test_drop(&drop_tests[n]); test_drop(&drop_tests[n]);