Skip to content

Commit

Permalink
Release 2.27.6
Browse files Browse the repository at this point in the history
- [BUGFIX] Replace dispatch read/write events assertion with a check.
- [BUGFIX] gQUIC connection close: there is no HEADERS stream without
  HTTP flag, see issue #220.
- http_client, http_server: add hq protocol support and other flags
  for use with QUIC Interop Runner.
- Fix: use IP_PMTUDISC_PROBE (not IP_PMTUDISC_DO) on Linux to set
  Don't-Fragment flag on outgoing packets.
- Fix send_packets_one_by_one on Windows platform when sending
  multiple iovs, see issue #218.
- Exit echo_client on Windows immediately, see issue #219.
  • Loading branch information
Dmitri Tikhonov committed Jan 27, 2021
1 parent 65c5d50 commit 5650ee6
Show file tree
Hide file tree
Showing 11 changed files with 274 additions and 14 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
2021-01-27
- 2.27.6
- [BUGFIX] Replace dispatch read/write events assertion with a check.
- [BUGFIX] gQUIC connection close: there is no HEADERS stream without
HTTP flag, see issue #220.
- http_client, http_server: add hq protocol support and other flags
for use with QUIC Interop Runner.
- Fix: use IP_PMTUDISC_PROBE (not IP_PMTUDISC_DO) on Linux to set
Don't-Fragment flag on outgoing packets.
- Fix send_packets_one_by_one on Windows platform when sending
multiple iovs, see issue #218.
- Exit echo_client on Windows immediately, see issue #219.

2021-01-18
- 2.27.5
- [BUGFIX] Assertion in send controller when path validation fails.
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ to the LiteSpeed QUIC and HTTP/3 Library:
- Aaron France -- Shared library support and Lisp bindings
- Suma Subbarao -- Use callback to supply client's SSL_CTX
- Paul Sheer -- Callback on arrival of CONNECTION_CLOSE frame
- Weiwei Wang -- Some fixes on Windows

Thank you!

Expand Down
6 changes: 6 additions & 0 deletions bin/echo_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,12 @@ main (int argc, char **argv)
struct prog prog;
struct echo_client_ctx client_ctx;

#ifdef WIN32
fprintf(stderr, "%s does not work on Windows, see\n"
"https://github.com/litespeedtech/lsquic/issues/219\n", argv[0]);
exit(EXIT_FAILURE);
#endif

memset(&client_ctx, 0, sizeof(client_ctx));
client_ctx.prog = &prog;

Expand Down
96 changes: 95 additions & 1 deletion bin/http_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ struct http_client_ctx {
unsigned hcc_n_open_conns;
unsigned hcc_reset_after_nbytes;
unsigned hcc_retire_cid_after_nbytes;
const char *hcc_download_dir;

char *hcc_sess_resume_file_name;

Expand Down Expand Up @@ -487,6 +488,7 @@ struct lsquic_stream_ctx {
* lsquic_stream_read* functions.
*/
unsigned count;
FILE *download_fh;
struct lsquic_reader reader;
};

Expand Down Expand Up @@ -552,6 +554,23 @@ http_client_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
st_h->sh_flags |= ABANDON;
}

if (st_h->client_ctx->hcc_download_dir)
{
char path[PATH_MAX];
snprintf(path, sizeof(path), "%s/%s",
st_h->client_ctx->hcc_download_dir, st_h->path);
st_h->download_fh = fopen(path, "wb");
if (st_h->download_fh)
LSQ_NOTICE("downloading %s to %s", st_h->path, path);
else
{
LSQ_ERROR("cannot open %s for writing: %s", path, strerror(errno));
lsquic_stream_close(stream);
}
}
else
st_h->download_fh = NULL;

return st_h;
}

Expand Down Expand Up @@ -785,7 +804,8 @@ http_client_on_read (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
st_h->sh_flags |= PROCESSED_HEADERS;
}
if (!s_discard_response)
fwrite(buf, 1, nread, stdout);
fwrite(buf, 1, nread, st_h->download_fh
? st_h->download_fh : stdout);
if (randomly_reprioritize_streams && (st_h->count++ & 0x3F) == 0)
{
if ((1 << lsquic_conn_quic_version(lsquic_stream_conn(stream)))
Expand Down Expand Up @@ -887,6 +907,8 @@ http_client_on_close (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
}
if (st_h->reader.lsqr_ctx)
destroy_lsquic_reader_ctx(st_h->reader.lsqr_ctx);
if (st_h->download_fh)
fclose(st_h->download_fh);
free(st_h);
}

Expand All @@ -902,6 +924,65 @@ static struct lsquic_stream_if http_client_if = {
};


/* XXX This function assumes we can send the request in one shot. This is
* not a realistic assumption to make in general, but will work for our
* limited use case (QUIC Interop Runner).
*/
static void
hq_client_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *st_h)
{
if (st_h->client_ctx->payload)
{
LSQ_ERROR("payload is not supported in HQ client");
lsquic_stream_close(stream);
return;
}

lsquic_stream_write(stream, "GET ", 4);
lsquic_stream_write(stream, st_h->path, strlen(st_h->path));
lsquic_stream_write(stream, "\r\n", 2);
lsquic_stream_shutdown(stream, 1);
lsquic_stream_wantread(stream, 1);
}


static size_t
hq_client_print_to_file (void *user_data, const unsigned char *buf,
size_t buf_len, int fin_unused)
{
fwrite(buf, 1, buf_len, user_data);
return buf_len;
}


static void
hq_client_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *st_h)
{
FILE *out = st_h->download_fh ? st_h->download_fh : stdout;
ssize_t nread;

nread = lsquic_stream_readf(stream, hq_client_print_to_file, out);
if (nread <= 0)
{
if (nread < 0)
LSQ_WARN("error reading response for %s: %s", st_h->path,
strerror(errno));
lsquic_stream_close(stream);
}
}


/* The "hq" set of callbacks differs only in the read and write routines */
static struct lsquic_stream_if hq_client_if = {
.on_new_conn = http_client_on_new_conn,
.on_conn_closed = http_client_on_conn_closed,
.on_new_stream = http_client_on_new_stream,
.on_read = hq_client_on_read,
.on_write = hq_client_on_write,
.on_close = http_client_on_close,
};


static void
usage (const char *prog)
{
Expand Down Expand Up @@ -947,6 +1028,8 @@ usage (const char *prog)
" -9 SPEC Priority specification. May be specified several times.\n"
" SPEC takes the form stream_id:nread:UI, where U is\n"
" urgency and I is incremental. Matched \\d+:\\d+:[0-7][01]\n"
" -7 DIR Save fetched resources into this directory.\n"
" -Q ALPN Use hq ALPN. Specify, for example, \"h3-29\".\n"
, prog);
}

Expand Down Expand Up @@ -1535,6 +1618,8 @@ main (int argc, char **argv)
"46Br:R:IKu:EP:M:n:w:H:p:0:q:e:hatT:b:d:"
"3:" /* 3 is 133+ for "e" ("e" for "early") */
"9:" /* 9 sort of looks like P... */
"7:" /* Download directory */
"Q:" /* ALPN, e.g. h3-29 */
#ifndef WIN32
"C:"
#endif
Expand Down Expand Up @@ -1694,6 +1779,15 @@ main (int argc, char **argv)
s_priority_specs = priority_specs;
break;
}
case '7':
client_ctx.hcc_download_dir = optarg;
break;
case 'Q':
/* XXX A bit hacky, as `prog' has already been initialized... */
prog.prog_engine_flags &= ~LSENG_HTTP;
prog.prog_api.ea_alpn = optarg;
prog.prog_api.ea_stream_if = &hq_client_if;
break;
default:
if (0 != prog_set_opt(&prog, opt, optarg))
exit(1);
Expand Down
119 changes: 118 additions & 1 deletion bin/http_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -1066,6 +1066,116 @@ const struct lsquic_stream_if http_server_if = {
};


/* XXX Assume we can always read the request in one shot. This is not a
* good assumption to make in a real product.
*/
static void
hq_server_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *st_h)
{
char buf[0x400];
ssize_t nread;
char *path, *end, *filename;

nread = lsquic_stream_read(stream, buf, sizeof(buf));
if (nread >= (ssize_t) sizeof(buf))
{
LSQ_WARN("request too large, at least %zd bytes", sizeof(buf));
lsquic_stream_close(stream);
return;
}
else if (nread < 0)
{
LSQ_WARN("error reading request from stream: %s", strerror(errno));
lsquic_stream_close(stream);
return;
}
buf[nread] = '\0';
path = strchr(buf, ' ');
if (!path)
{
LSQ_WARN("invalid request (no space character): `%s'", buf);
lsquic_stream_close(stream);
return;
}
if (!(path - buf == 3 && 0 == strncasecmp(buf, "GET", 3)))
{
LSQ_NOTICE("unsupported method `%.*s'", (int) (path - buf), buf);
lsquic_stream_close(stream);
return;
}
++path;
for (end = path + nread - 5; end > path
&& (*end == '\r' || *end == '\n'); --end)
*end = '\0';
LSQ_NOTICE("parsed out request path: %s", path);

filename = malloc(strlen(st_h->server_ctx->document_root) + 1 + strlen(path) + 1);
strcpy(filename, st_h->server_ctx->document_root);
strcat(filename, "/");
strcat(filename, path);
LSQ_NOTICE("file to fetch: %s", filename);
/* XXX This copy pasta is getting a bit annoying now: two mallocs of the
* same thing?
*/
st_h->req_filename = filename;
st_h->req_path = strdup(filename);
st_h->reader.lsqr_read = test_reader_read;
st_h->reader.lsqr_size = test_reader_size;
st_h->reader.lsqr_ctx = create_lsquic_reader_ctx(st_h->req_path);
if (!st_h->reader.lsqr_ctx)
{
lsquic_stream_close(stream);
return;
}
lsquic_stream_shutdown(stream, 0);
lsquic_stream_wantwrite(stream, 1);
}


static void
hq_server_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *st_h)
{
ssize_t nw;

nw = lsquic_stream_writef(stream, &st_h->reader);
if (nw < 0)
{
struct lsquic_conn *conn = lsquic_stream_conn(stream);
lsquic_conn_ctx_t *conn_h = lsquic_conn_get_ctx(conn);
if (conn_h->flags & RECEIVED_GOAWAY)
{
LSQ_NOTICE("cannot write: goaway received");
lsquic_stream_close(stream);
}
else
{
LSQ_ERROR("write error: %s", strerror(errno));
lsquic_stream_close(stream);
}
}
else if (bytes_left(st_h) > 0)
{
st_h->written += (size_t) nw;
lsquic_stream_wantwrite(stream, 1);
}
else
{
lsquic_stream_shutdown(stream, 1);
lsquic_stream_wantread(stream, 1);
}
}


const struct lsquic_stream_if hq_server_if = {
.on_new_conn = http_server_on_new_conn,
.on_conn_closed = http_server_on_conn_closed,
.on_new_stream = http_server_on_new_stream,
.on_read = hq_server_on_read,
.on_write = hq_server_on_write,
.on_close = http_server_on_close,
};


#if HAVE_REGEX
struct req_map
{
Expand Down Expand Up @@ -1655,6 +1765,7 @@ usage (const char *prog)
" Incompatible with -w.\n"
#endif
" -y DELAY Delay response for this many seconds -- use for debugging\n"
" -Q ALPN Use hq mode; ALPN could be \"hq-29\", for example.\n"
, prog);
}

Expand Down Expand Up @@ -1811,7 +1922,7 @@ main (int argc, char **argv)
prog_init(&prog, LSENG_SERVER|LSENG_HTTP, &server_ctx.sports,
&http_server_if, &server_ctx);

while (-1 != (opt = getopt(argc, argv, PROG_OPTS "y:Y:n:p:r:w:P:h")))
while (-1 != (opt = getopt(argc, argv, PROG_OPTS "y:Y:n:p:r:w:P:hQ:")))
{
switch (opt) {
case 'n':
Expand Down Expand Up @@ -1854,6 +1965,12 @@ main (int argc, char **argv)
usage(argv[0]);
prog_print_common_options(&prog, stdout);
exit(0);
case 'Q':
/* XXX A bit hacky, as `prog' has already been initialized... */
prog.prog_engine_flags &= ~LSENG_HTTP;
prog.prog_api.ea_stream_if = &hq_server_if;
add_alpn(optarg);
break;
default:
if (0 != prog_set_opt(&prog, opt, optarg))
exit(1);
Expand Down
4 changes: 2 additions & 2 deletions bin/test_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -947,7 +947,7 @@ sport_init_server (struct service_port *sport, struct lsquic_engine *engine,
if (AF_INET == sa_local->sa_family)
{
#if __linux__
on = IP_PMTUDISC_DO;
on = IP_PMTUDISC_PROBE;
s = setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &on,
sizeof(on));
#else
Expand Down Expand Up @@ -1136,7 +1136,7 @@ sport_init_client (struct service_port *sport, struct lsquic_engine *engine,
{
int on;
#if __linux__
on = IP_PMTUDISC_DO;
on = IP_PMTUDISC_PROBE;
s = setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &on,
sizeof(on));
#elif WIN32
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
# The short X.Y version
version = u'2.27'
# The full version, including alpha/beta/rc tags
release = u'2.27.5'
release = u'2.27.6'


# -- General configuration ---------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion include/lsquic.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ extern "C" {

#define LSQUIC_MAJOR_VERSION 2
#define LSQUIC_MINOR_VERSION 27
#define LSQUIC_PATCH_VERSION 5
#define LSQUIC_PATCH_VERSION 6

/**
* Engine flags:
Expand Down
4 changes: 3 additions & 1 deletion src/liblsquic/lsquic_full_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -2615,10 +2615,12 @@ maybe_close_conn (struct full_conn *conn)
struct lsquic_stream *stream;
struct lsquic_hash_elem *el;
#endif
const unsigned n_special_streams = N_SPECIAL_STREAMS
- !(conn->fc_flags & FC_HTTP);

if ((conn->fc_flags & (FC_CLOSING|FC_GOAWAY_SENT|FC_SERVER))
== (FC_GOAWAY_SENT|FC_SERVER)
&& lsquic_hash_count(conn->fc_pub.all_streams) == N_SPECIAL_STREAMS)
&& lsquic_hash_count(conn->fc_pub.all_streams) == n_special_streams)
{
#ifndef NDEBUG
for (el = lsquic_hash_first(conn->fc_pub.all_streams); el;
Expand Down
Loading

0 comments on commit 5650ee6

Please sign in to comment.