mirror of
https://gitea.invidious.io/iv-org/litespeed-quic.git
synced 2024-08-15 00:53:43 +00:00
Release 2.29.1
- Make it possible to build the library and unit tests without libevent. - Build all command-line utilities in bin/ - Add perf_client and perf_server command-line utilities to test performance according to the "perf" protocol.
This commit is contained in:
parent
4ffff819e8
commit
8ecb980d26
6 changed files with 673 additions and 2 deletions
|
@ -1,3 +1,11 @@
|
|||
2021-02-18
|
||||
- 2.29.1
|
||||
- Make it possible to build the library and unit tests without
|
||||
libevent.
|
||||
- Build all command-line utilities in bin/
|
||||
- Add perf_client and perf_server command-line utilities to test
|
||||
performance according to the "perf" protocol.
|
||||
|
||||
2021-02-10
|
||||
- 2.29.0
|
||||
- [FEATURE] QUIC and HTTP/3 Internet Draft 34 support and v1 support.
|
||||
|
|
|
@ -32,6 +32,8 @@ add_executable(echo_server echo_server.c prog.c test_common.c test_cert.c ${GETO
|
|||
add_executable(echo_client echo_client.c prog.c test_common.c test_cert.c ${GETOPT_C})
|
||||
add_executable(duck_server duck_server.c prog.c test_common.c test_cert.c ${GETOPT_C})
|
||||
add_executable(duck_client duck_client.c prog.c test_common.c test_cert.c ${GETOPT_C})
|
||||
add_executable(perf_client perf_client.c prog.c test_common.c test_cert.c ${GETOPT_C})
|
||||
add_executable(perf_server perf_server.c prog.c test_common.c test_cert.c ${GETOPT_C})
|
||||
|
||||
|
||||
IF (NOT MSVC)
|
||||
|
@ -67,6 +69,8 @@ TARGET_LINK_LIBRARIES(echo_server ${LIBS})
|
|||
TARGET_LINK_LIBRARIES(echo_client ${LIBS})
|
||||
TARGET_LINK_LIBRARIES(duck_server ${LIBS})
|
||||
TARGET_LINK_LIBRARIES(duck_client ${LIBS})
|
||||
TARGET_LINK_LIBRARIES(perf_client ${LIBS})
|
||||
TARGET_LINK_LIBRARIES(perf_server ${LIBS})
|
||||
|
||||
|
||||
INCLUDE(CheckFunctionExists)
|
||||
|
|
406
bin/perf_client.c
Normal file
406
bin/perf_client.c
Normal file
|
@ -0,0 +1,406 @@
|
|||
/* Copyright (c) 2017 - 2021 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
/*
|
||||
* perf_client.c -- Implements the "perf" client, see
|
||||
* https://tools.ietf.org/html/draft-banks-quic-performance-00
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#else
|
||||
#include "vc_compat.h"
|
||||
#include "getopt.h"
|
||||
#endif
|
||||
|
||||
#include <event2/event.h>
|
||||
|
||||
#include "lsquic.h"
|
||||
#include "test_common.h"
|
||||
#include "prog.h"
|
||||
|
||||
#include "../src/liblsquic/lsquic_logger.h"
|
||||
#include "../src/liblsquic/lsquic_int_types.h"
|
||||
#include "../src/liblsquic/lsquic_byteswap.h"
|
||||
|
||||
struct scenario
|
||||
{
|
||||
STAILQ_ENTRY(scenario) next;
|
||||
uint64_t bytes_to_request;
|
||||
uint64_t bytes_to_send; /* After the 8-byte header */
|
||||
};
|
||||
|
||||
/* Assume all connections use the same list of scenarios, so store it in
|
||||
* a global variable.
|
||||
*/
|
||||
static STAILQ_HEAD(, scenario) s_scenarios
|
||||
= STAILQ_HEAD_INITIALIZER(s_scenarios);
|
||||
static unsigned s_n_scenarios;
|
||||
static unsigned s_n_conns;
|
||||
|
||||
struct prog s_prog;
|
||||
|
||||
struct lsquic_conn_ctx
|
||||
{
|
||||
/* Once a connection runs out of scenarios, no new streams are created
|
||||
* and the connection is closed when all streams are closed.
|
||||
*/
|
||||
const struct scenario *next_scenario;
|
||||
unsigned n_scenarios_left;
|
||||
unsigned n_streams;
|
||||
};
|
||||
|
||||
|
||||
static bool
|
||||
perf_create_streams (struct lsquic_conn *conn, struct lsquic_conn_ctx *conn_ctx)
|
||||
{
|
||||
if (conn_ctx->n_scenarios_left)
|
||||
{
|
||||
--conn_ctx->n_scenarios_left;
|
||||
lsquic_conn_make_stream(conn);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static lsquic_conn_ctx_t *
|
||||
perf_client_on_new_conn (void *stream_if_ctx, struct lsquic_conn *conn)
|
||||
{
|
||||
struct lsquic_conn_ctx *conn_ctx;
|
||||
|
||||
if (s_n_scenarios)
|
||||
{
|
||||
conn_ctx = calloc(1, sizeof(*conn_ctx));
|
||||
conn_ctx->next_scenario = STAILQ_FIRST(&s_scenarios);
|
||||
conn_ctx->n_scenarios_left = s_n_scenarios;
|
||||
perf_create_streams(conn, conn_ctx);
|
||||
++s_n_conns;
|
||||
return conn_ctx;
|
||||
}
|
||||
else
|
||||
{
|
||||
lsquic_conn_close(conn);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
perf_client_on_conn_closed (struct lsquic_conn *conn)
|
||||
{
|
||||
struct lsquic_conn_ctx *conn_ctx;
|
||||
|
||||
LSQ_NOTICE("Connection closed");
|
||||
conn_ctx = lsquic_conn_get_ctx(conn);
|
||||
free(conn_ctx);
|
||||
--s_n_conns;
|
||||
if (0 == s_n_conns)
|
||||
prog_stop(&s_prog);
|
||||
}
|
||||
|
||||
|
||||
struct lsquic_stream_ctx
|
||||
{
|
||||
const struct scenario *scenario;
|
||||
struct {
|
||||
uint64_t header; /* Big-endian */
|
||||
unsigned n_h; /* Number of header bytes written */
|
||||
uint64_t n_written; /* Number of non-header bytes written */
|
||||
} write_state;
|
||||
struct {
|
||||
uint64_t n_read;
|
||||
} read_state;
|
||||
};
|
||||
|
||||
|
||||
static struct lsquic_stream_ctx *
|
||||
perf_client_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
|
||||
{
|
||||
struct lsquic_conn_ctx *conn_ctx;
|
||||
struct lsquic_conn *conn;
|
||||
|
||||
conn = lsquic_stream_conn(stream);
|
||||
conn_ctx = lsquic_conn_get_ctx(conn);
|
||||
|
||||
if (!stream)
|
||||
{
|
||||
LSQ_NOTICE("%s: got null stream: no more streams possible", __func__);
|
||||
lsquic_conn_close(conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(conn_ctx->next_scenario);
|
||||
|
||||
struct lsquic_stream_ctx *stream_ctx = calloc(1, sizeof(*stream_ctx));
|
||||
stream_ctx->scenario = conn_ctx->next_scenario;
|
||||
conn_ctx->next_scenario = STAILQ_NEXT(conn_ctx->next_scenario, next);
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
stream_ctx->write_state.header
|
||||
= bswap_64(stream_ctx->scenario->bytes_to_request);
|
||||
#else
|
||||
stream_ctx->write_state.header = stream_ctx->scenario->bytes_to_request;
|
||||
#endif
|
||||
lsquic_stream_wantwrite(stream, 1);
|
||||
return stream_ctx;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
buffer_size (void *lsqr_ctx)
|
||||
{
|
||||
struct lsquic_stream_ctx *const stream_ctx = lsqr_ctx;
|
||||
return stream_ctx->scenario->bytes_to_send
|
||||
- stream_ctx->write_state.n_written;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
buffer_read (void *lsqr_ctx, void *buf, size_t count)
|
||||
{
|
||||
struct lsquic_stream_ctx *const stream_ctx = lsqr_ctx;
|
||||
size_t left;
|
||||
|
||||
left = buffer_size(stream_ctx);
|
||||
if (count > left)
|
||||
count = left;
|
||||
memset(buf, 0, count);
|
||||
stream_ctx->write_state.n_written += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
header_size (void *lsqr_ctx)
|
||||
{
|
||||
struct lsquic_stream_ctx *const stream_ctx = lsqr_ctx;
|
||||
return sizeof(uint64_t) - stream_ctx->write_state.n_h;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
header_read (void *lsqr_ctx, void *buf, size_t count)
|
||||
{
|
||||
struct lsquic_stream_ctx *const stream_ctx = lsqr_ctx;
|
||||
const unsigned char *src;
|
||||
size_t left;
|
||||
|
||||
left = header_size(stream_ctx);
|
||||
if (count < left)
|
||||
count = left;
|
||||
src = (unsigned char *) &stream_ctx->write_state.header
|
||||
+ sizeof(uint64_t) - left;
|
||||
memcpy(buf, src, count);
|
||||
stream_ctx->write_state.n_h += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
perf_client_on_write (struct lsquic_stream *stream,
|
||||
struct lsquic_stream_ctx *stream_ctx)
|
||||
{
|
||||
struct lsquic_reader reader;
|
||||
ssize_t nw;
|
||||
|
||||
if (stream_ctx->write_state.n_h >= sizeof(uint64_t))
|
||||
reader = (struct lsquic_reader) {
|
||||
buffer_read,
|
||||
buffer_size,
|
||||
stream_ctx,
|
||||
};
|
||||
else
|
||||
reader = (struct lsquic_reader) {
|
||||
header_read,
|
||||
header_size,
|
||||
stream_ctx,
|
||||
};
|
||||
|
||||
nw = lsquic_stream_writef(stream, &reader);
|
||||
if (nw >= 0)
|
||||
LSQ_DEBUG("%s: wrote %zd bytes", __func__, nw);
|
||||
else
|
||||
LSQ_WARN("%s: cannot write to stream: %s", __func__, strerror(errno));
|
||||
|
||||
if (reader.lsqr_size(stream_ctx) == 0
|
||||
&& (reader.lsqr_size == buffer_size || buffer_size(stream_ctx) == 0))
|
||||
{
|
||||
lsquic_stream_shutdown(stream, 1);
|
||||
lsquic_stream_wantread(stream, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
perf_read_and_discard (void *user_data, const unsigned char *buf,
|
||||
size_t count, int fin)
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
perf_client_on_read (struct lsquic_stream *stream,
|
||||
struct lsquic_stream_ctx *stream_ctx)
|
||||
{
|
||||
ssize_t nr;
|
||||
|
||||
nr = lsquic_stream_readf(stream, perf_read_and_discard, NULL);
|
||||
if (nr >= 0)
|
||||
{
|
||||
stream_ctx->read_state.n_read += nr;
|
||||
if (nr == 0)
|
||||
{
|
||||
LSQ_DEBUG("reached fin after reading %"PRIu64" bytes from server",
|
||||
stream_ctx->read_state.n_read);
|
||||
lsquic_stream_shutdown(stream, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LSQ_WARN("error reading from stream: %s, abort connection",
|
||||
strerror(errno));
|
||||
lsquic_stream_close(stream);
|
||||
lsquic_conn_abort(lsquic_stream_conn(stream));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
perf_client_on_close (struct lsquic_stream *stream,
|
||||
struct lsquic_stream_ctx *stream_ctx)
|
||||
{
|
||||
struct lsquic_conn_ctx *conn_ctx;
|
||||
struct lsquic_conn *conn;
|
||||
|
||||
conn = lsquic_stream_conn(stream);
|
||||
conn_ctx = lsquic_conn_get_ctx(conn);
|
||||
if (!perf_create_streams(conn, conn_ctx))
|
||||
{
|
||||
LSQ_DEBUG("out of scenarios, will close connection");
|
||||
lsquic_conn_close(conn);
|
||||
}
|
||||
free(stream_ctx);
|
||||
}
|
||||
|
||||
|
||||
const struct lsquic_stream_if perf_stream_if = {
|
||||
.on_new_conn = perf_client_on_new_conn,
|
||||
.on_conn_closed = perf_client_on_conn_closed,
|
||||
.on_new_stream = perf_client_on_new_stream,
|
||||
.on_read = perf_client_on_read,
|
||||
.on_write = perf_client_on_write,
|
||||
.on_close = perf_client_on_close,
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
usage (const char *prog)
|
||||
{
|
||||
const char *const slash = strrchr(prog, '/');
|
||||
if (slash)
|
||||
prog = slash + 1;
|
||||
printf(
|
||||
"Usage: %s [opts]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -p NREQ:NSEND Request NREQ bytes from server and, in addition, send\n"
|
||||
" NSEND bytes to server. May be specified many times\n"
|
||||
" and must be specified at least once.\n"
|
||||
" -T FILE Print stats to FILE. If FILE is -, print stats to stdout.\n"
|
||||
, prog);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
char *p;
|
||||
int opt, s;
|
||||
struct sport_head sports;
|
||||
struct scenario *scenario;
|
||||
|
||||
TAILQ_INIT(&sports);
|
||||
prog_init(&s_prog, 0, &sports, &perf_stream_if, NULL);
|
||||
s_prog.prog_api.ea_alpn = "perf";
|
||||
|
||||
while (-1 != (opt = getopt(argc, argv, PROG_OPTS "hp:T:")))
|
||||
{
|
||||
switch (opt) {
|
||||
case 'p':
|
||||
scenario = calloc(1, sizeof(*scenario));
|
||||
if (!scenario)
|
||||
{
|
||||
perror("calloc");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
++s_n_scenarios;
|
||||
STAILQ_INSERT_TAIL(&s_scenarios, scenario, next);
|
||||
scenario->bytes_to_request = strtoull(optarg, &p, 10);
|
||||
if (*p != ':')
|
||||
{
|
||||
fprintf(stderr, "invalid scenario `%s'\n", optarg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
scenario->bytes_to_send = strtoull(p + 1, NULL, 10);
|
||||
break;
|
||||
case 'T':
|
||||
if (0 == strcmp(optarg, "-"))
|
||||
s_prog.prog_api.ea_stats_fh = stdout;
|
||||
else
|
||||
{
|
||||
s_prog.prog_api.ea_stats_fh = fopen(optarg, "w");
|
||||
if (!s_prog.prog_api.ea_stats_fh)
|
||||
{
|
||||
perror("fopen");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
prog_print_common_options(&s_prog, stdout);
|
||||
exit(0);
|
||||
default:
|
||||
if (0 != prog_set_opt(&s_prog, opt, optarg))
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (STAILQ_EMPTY(&s_scenarios))
|
||||
{
|
||||
fprintf(stderr, "please specify one of more requests using -p\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (0 != prog_prep(&s_prog))
|
||||
{
|
||||
LSQ_ERROR("could not prep");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (0 != prog_connect(&s_prog, NULL, 0))
|
||||
{
|
||||
LSQ_ERROR("could not connect");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
LSQ_DEBUG("entering event loop");
|
||||
|
||||
s = prog_run(&s_prog);
|
||||
prog_cleanup(&s_prog);
|
||||
|
||||
exit(0 == s ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
253
bin/perf_server.c
Normal file
253
bin/perf_server.c
Normal file
|
@ -0,0 +1,253 @@
|
|||
/* Copyright (c) 2017 - 2021 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
/*
|
||||
* perf_server.c -- Implements the "perf" server, see
|
||||
* https://tools.ietf.org/html/draft-banks-quic-performance-00
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#else
|
||||
#include "vc_compat.h"
|
||||
#include "getopt.h"
|
||||
#endif
|
||||
|
||||
#include <event2/event.h>
|
||||
|
||||
#include "lsquic.h"
|
||||
#include "test_common.h"
|
||||
#include "../src/liblsquic/lsquic_hash.h"
|
||||
#include "test_cert.h"
|
||||
#include "prog.h"
|
||||
|
||||
#include "../src/liblsquic/lsquic_byteswap.h"
|
||||
#include "../src/liblsquic/lsquic_logger.h"
|
||||
|
||||
|
||||
static lsquic_conn_ctx_t *
|
||||
perf_server_on_new_conn (void *stream_if_ctx, lsquic_conn_t *conn)
|
||||
{
|
||||
LSQ_INFO("New connection!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
perf_server_on_conn_closed (lsquic_conn_t *conn)
|
||||
{
|
||||
LSQ_INFO("Connection closed");
|
||||
}
|
||||
|
||||
|
||||
struct lsquic_stream_ctx
|
||||
{
|
||||
union {
|
||||
uint64_t left; /* Number of bytes left to write */
|
||||
unsigned char buf[sizeof(uint64_t)]; /* Read client header in */
|
||||
} u;
|
||||
unsigned n_h_read; /* Number of header bytes read in */
|
||||
};
|
||||
|
||||
|
||||
static struct lsquic_stream_ctx *
|
||||
perf_server_on_new_stream (void *unused, struct lsquic_stream *stream)
|
||||
{
|
||||
struct lsquic_stream_ctx *stream_ctx;
|
||||
|
||||
stream_ctx = calloc(1, sizeof(*stream_ctx));
|
||||
if (stream_ctx)
|
||||
{
|
||||
lsquic_stream_wantread(stream, 1);
|
||||
return stream_ctx;
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("calloc");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
perf_read_and_discard (void *user_data, const unsigned char *buf,
|
||||
size_t count, int fin)
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
perf_server_on_read (struct lsquic_stream *stream,
|
||||
struct lsquic_stream_ctx *stream_ctx)
|
||||
{
|
||||
ssize_t nr;
|
||||
size_t toread;
|
||||
|
||||
if (stream_ctx->n_h_read < sizeof(stream_ctx->u.buf))
|
||||
{
|
||||
/* Read the header */
|
||||
toread = sizeof(stream_ctx->u.buf) - stream_ctx->n_h_read;
|
||||
nr = lsquic_stream_read(stream, stream_ctx->u.buf
|
||||
+ sizeof(stream_ctx->u.buf) - toread, toread);
|
||||
if (nr > 0)
|
||||
{
|
||||
stream_ctx->n_h_read += nr;
|
||||
if (stream_ctx->n_h_read == sizeof(stream_ctx->u.left))
|
||||
{
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
stream_ctx->u.left = bswap_64(stream_ctx->u.left);
|
||||
#endif
|
||||
LSQ_INFO("client requests %"PRIu64" bytes on stream %"PRIu64,
|
||||
stream_ctx->u.left, lsquic_stream_id(stream));
|
||||
}
|
||||
}
|
||||
else if (nr < 0)
|
||||
{
|
||||
LSQ_WARN("error reading from stream: %s", strerror(errno));
|
||||
lsquic_stream_close(stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
LSQ_WARN("incomplete header on stream %"PRIu64", abort connection",
|
||||
lsquic_stream_id(stream));
|
||||
lsquic_stream_wantread(stream, 0);
|
||||
lsquic_conn_abort(lsquic_stream_conn(stream));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Read up until FIN, discarding whatever the client is sending */
|
||||
nr = lsquic_stream_readf(stream, perf_read_and_discard, NULL);
|
||||
if (nr == 0)
|
||||
{
|
||||
lsquic_stream_wantread(stream, 0);
|
||||
lsquic_stream_wantwrite(stream, 1);
|
||||
}
|
||||
else if (nr < 0)
|
||||
{
|
||||
LSQ_WARN("error reading from stream: %s", strerror(errno));
|
||||
lsquic_stream_close(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
buffer_size (void *lsqr_ctx)
|
||||
{
|
||||
struct lsquic_stream_ctx *const stream_ctx = lsqr_ctx;
|
||||
return stream_ctx->u.left;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
buffer_read (void *lsqr_ctx, void *buf, size_t count)
|
||||
{
|
||||
struct lsquic_stream_ctx *const stream_ctx = lsqr_ctx;
|
||||
size_t left;
|
||||
|
||||
left = buffer_size(stream_ctx);
|
||||
if (count > left)
|
||||
count = left;
|
||||
memset(buf, 0, count);
|
||||
stream_ctx->u.left -= count;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
perf_server_on_write (struct lsquic_stream *stream,
|
||||
struct lsquic_stream_ctx *stream_ctx)
|
||||
{
|
||||
struct lsquic_reader reader;
|
||||
ssize_t nw;
|
||||
|
||||
reader = (struct lsquic_reader) { buffer_read, buffer_size, stream_ctx, };
|
||||
nw = lsquic_stream_writef(stream, &reader);
|
||||
if (nw >= 0)
|
||||
LSQ_DEBUG("%s: wrote %zd bytes", __func__, nw);
|
||||
else
|
||||
LSQ_WARN("%s: cannot write to stream: %s", __func__, strerror(errno));
|
||||
|
||||
if (stream_ctx->u.left == 0)
|
||||
lsquic_stream_shutdown(stream, 1);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
perf_server_on_close (lsquic_stream_t *stream, lsquic_stream_ctx_t *stream_ctx)
|
||||
{
|
||||
LSQ_DEBUG("stream closed");
|
||||
free(stream_ctx);
|
||||
}
|
||||
|
||||
|
||||
const struct lsquic_stream_if perf_server_stream_if = {
|
||||
.on_new_conn = perf_server_on_new_conn,
|
||||
.on_conn_closed = perf_server_on_conn_closed,
|
||||
.on_new_stream = perf_server_on_new_stream,
|
||||
.on_read = perf_server_on_read,
|
||||
.on_write = perf_server_on_write,
|
||||
.on_close = perf_server_on_close,
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
usage (const char *prog)
|
||||
{
|
||||
const char *const slash = strrchr(prog, '/');
|
||||
if (slash)
|
||||
prog = slash + 1;
|
||||
printf(
|
||||
"Usage: %s [opts]\n"
|
||||
"\n"
|
||||
, prog);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int opt, s;
|
||||
struct prog prog;
|
||||
struct sport_head sports;
|
||||
|
||||
TAILQ_INIT(&sports);
|
||||
prog_init(&prog, LSENG_SERVER, &sports, &perf_server_stream_if, NULL);
|
||||
|
||||
while (-1 != (opt = getopt(argc, argv, PROG_OPTS "h")))
|
||||
{
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
prog_print_common_options(&prog, stdout);
|
||||
exit(0);
|
||||
default:
|
||||
if (0 != prog_set_opt(&prog, opt, optarg))
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
add_alpn("perf");
|
||||
if (0 != prog_prep(&prog))
|
||||
{
|
||||
LSQ_ERROR("could not prep");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
LSQ_DEBUG("entering event loop");
|
||||
|
||||
s = prog_run(&prog);
|
||||
prog_cleanup(&prog);
|
||||
|
||||
exit(0 == s ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
|
@ -26,7 +26,7 @@ author = u'LiteSpeed Technologies'
|
|||
# The short X.Y version
|
||||
version = u'2.29'
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = u'2.29.0'
|
||||
release = u'2.29.1'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
|
|
@ -25,7 +25,7 @@ extern "C" {
|
|||
|
||||
#define LSQUIC_MAJOR_VERSION 2
|
||||
#define LSQUIC_MINOR_VERSION 29
|
||||
#define LSQUIC_PATCH_VERSION 0
|
||||
#define LSQUIC_PATCH_VERSION 1
|
||||
|
||||
/**
|
||||
* Engine flags:
|
||||
|
|
Loading…
Reference in a new issue