mirror of
https://gitea.invidious.io/iv-org/litespeed-quic.git
synced 2024-08-15 00:53:43 +00:00
Release 1.19.3
- [BUGFIX] Q044: don't encode packet number in 6 bytes. Six-byte packet number encoding does not exist in Q044. This fixes a regression introduced in '[BUGFIX] Buffered packets can contain ACK frames' -- we need to keep QUIC version in mind when selecting the longest possible packet number encoding used for the buffered packet that carries the ACK. - [BUGFIX] Do not increase CWND when timeout occurs. - http_client: support setting handshake timeout on command line. Use -o handshake_to=timeout. - http_client: use -k to connect UDP socket to pick up ICMP errors. - http_client: allow pathless mode, when only handshake is performed without issuing any requests. This can be done by simply not specifying a -p flag on the command line.
This commit is contained in:
parent
3329170846
commit
9c4445241e
12 changed files with 113 additions and 20 deletions
16
CHANGELOG
16
CHANGELOG
|
@ -1,3 +1,19 @@
|
|||
2019-02-18
|
||||
- 1.19.3
|
||||
- [BUGFIX] Q044: don't encode packet number in 6 bytes. Six-byte
|
||||
packet number encoding does not exist in Q044. This fixes a
|
||||
regression introduced in '[BUGFIX] Buffered packets can contain
|
||||
ACK frames' -- we need to keep QUIC version in mind when selecting
|
||||
the longest possible packet number encoding used for the buffered
|
||||
packet that carries the ACK.
|
||||
- [BUGFIX] Do not increase CWND when timeout occurs.
|
||||
- http_client: support setting handshake timeout on command line.
|
||||
Use -o handshake_to=timeout.
|
||||
- http_client: use -k to connect UDP socket to pick up ICMP errors.
|
||||
- http_client: allow pathless mode, when only handshake is performed
|
||||
without issuing any requests. This can be done by simply not
|
||||
specifying a -p flag on the command line.
|
||||
|
||||
2019-02-11
|
||||
- 1.19.2
|
||||
- [BUGFIX] Begin negotiation with version provided in 0-RTT info.
|
||||
|
|
|
@ -25,7 +25,7 @@ extern "C" {
|
|||
|
||||
#define LSQUIC_MAJOR_VERSION 1
|
||||
#define LSQUIC_MINOR_VERSION 19
|
||||
#define LSQUIC_PATCH_VERSION 2
|
||||
#define LSQUIC_PATCH_VERSION 3
|
||||
|
||||
/**
|
||||
* Engine flags:
|
||||
|
|
|
@ -183,10 +183,14 @@ lsquic_cubic_loss (struct lsquic_cubic *cubic)
|
|||
void
|
||||
lsquic_cubic_timeout (struct lsquic_cubic *cubic)
|
||||
{
|
||||
unsigned long cwnd;
|
||||
|
||||
cwnd = cubic->cu_cwnd;
|
||||
LSQ_DEBUG("%s(cubic)", __func__);
|
||||
cubic_reset(cubic);
|
||||
cubic->cu_ssthresh = cubic->cu_cwnd;
|
||||
cubic->cu_tcp_cwnd = cubic->cu_cwnd;
|
||||
cubic->cu_ssthresh = cwnd / 2;
|
||||
cubic->cu_tcp_cwnd = 2 * TCP_MSS;
|
||||
cubic->cu_cwnd = 2 * TCP_MSS;
|
||||
LSQ_INFO("timeout, cwnd: %lu", cubic->cu_cwnd);
|
||||
LOG_CWND(cubic);
|
||||
}
|
||||
|
|
|
@ -2106,6 +2106,7 @@ process_incoming_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in)
|
|||
}
|
||||
LSQ_DEBUG("end of version negotiation: agreed upon %s",
|
||||
lsquic_ver2str[conn->fc_ver_neg.vn_ver]);
|
||||
lsquic_send_ctl_verneg_done(&conn->fc_send_ctl);
|
||||
}
|
||||
return process_regular_packet(conn, packet_in);
|
||||
}
|
||||
|
|
|
@ -1923,7 +1923,7 @@ lsquic_enc_session_get_zero_rtt (lsquic_enc_session_t *enc_session,
|
|||
sz += sizeof(struct lsquic_zero_rtt_storage);
|
||||
if (len < sz)
|
||||
{
|
||||
LSQ_DEBUG("client provided buf is too small %lu < %lu", len, sz);
|
||||
LSQ_DEBUG("client provided buf is too small %zu < %zu", len, sz);
|
||||
errno = ENOBUFS;
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -257,6 +257,7 @@ lsquic_send_ctl_init (lsquic_send_ctl_t *ctl, struct lsquic_alarmset *alset,
|
|||
for (i = 0; i < sizeof(ctl->sc_buffered_packets) /
|
||||
sizeof(ctl->sc_buffered_packets[0]); ++i)
|
||||
TAILQ_INIT(&ctl->sc_buffered_packets[i].bpq_packets);
|
||||
ctl->sc_max_packno_bits = PACKNO_LEN_4; /* Safe value before verneg */
|
||||
}
|
||||
|
||||
|
||||
|
@ -1698,7 +1699,7 @@ send_ctl_get_buffered_packet (lsquic_send_ctl_t *ctl,
|
|||
{
|
||||
LSQ_DEBUG("steal ACK frame from low-priority buffered queue");
|
||||
ack_action = AA_STEAL;
|
||||
bits = PACKNO_LEN_6;
|
||||
bits = ctl->sc_max_packno_bits;
|
||||
}
|
||||
/* If ACK can be generated, write it to the first buffered packet. */
|
||||
else if (lconn->cn_if->ci_can_write_ack(lconn))
|
||||
|
@ -1709,7 +1710,7 @@ send_ctl_get_buffered_packet (lsquic_send_ctl_t *ctl,
|
|||
/* Packet length is set to the largest possible size to guarantee
|
||||
* that buffered packet with the ACK will not need to be split.
|
||||
*/
|
||||
bits = PACKNO_LEN_6;
|
||||
bits = ctl->sc_max_packno_bits;
|
||||
}
|
||||
else
|
||||
goto no_ack_action;
|
||||
|
@ -1781,12 +1782,17 @@ enum lsquic_packno_bits
|
|||
lsquic_send_ctl_calc_packno_bits (lsquic_send_ctl_t *ctl)
|
||||
{
|
||||
lsquic_packno_t smallest_unacked;
|
||||
enum lsquic_packno_bits bits;
|
||||
unsigned n_in_flight;
|
||||
|
||||
smallest_unacked = lsquic_send_ctl_smallest_unacked(ctl);
|
||||
n_in_flight = lsquic_cubic_get_cwnd(&ctl->sc_cubic) / ctl->sc_pack_size;
|
||||
return calc_packno_bits(ctl->sc_cur_packno + 1, smallest_unacked,
|
||||
bits = calc_packno_bits(ctl->sc_cur_packno + 1, smallest_unacked,
|
||||
n_in_flight);
|
||||
if (bits <= ctl->sc_max_packno_bits)
|
||||
return bits;
|
||||
else
|
||||
return ctl->sc_max_packno_bits;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1929,3 +1935,18 @@ lsquic_send_ctl_mem_used (const struct lsquic_send_ctl *ctl)
|
|||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_send_ctl_verneg_done (struct lsquic_send_ctl *ctl)
|
||||
{
|
||||
if ((1 << ctl->sc_conn_pub->lconn->cn_version) &
|
||||
LSQUIC_GQUIC_HEADER_VERSIONS)
|
||||
ctl->sc_max_packno_bits = PACKNO_LEN_6;
|
||||
else
|
||||
/* Assuming Q044 */
|
||||
ctl->sc_max_packno_bits = PACKNO_LEN_4;
|
||||
LSQ_DEBUG("version negotiation done (%s): max packno bits: %u",
|
||||
lsquic_ver2str[ ctl->sc_conn_pub->lconn->cn_version ],
|
||||
ctl->sc_max_packno_bits);
|
||||
}
|
||||
|
|
|
@ -89,6 +89,7 @@ typedef struct lsquic_send_ctl {
|
|||
} sc_cached_bpt;
|
||||
unsigned sc_next_limit;
|
||||
unsigned sc_n_scheduled;
|
||||
enum lsquic_packno_bits sc_max_packno_bits;
|
||||
#if LSQUIC_SEND_STATS
|
||||
struct {
|
||||
unsigned n_total_sent,
|
||||
|
@ -283,4 +284,7 @@ int
|
|||
lsquic_send_ctl_buffered_and_same_prio_as_headers (struct lsquic_send_ctl *,
|
||||
const struct lsquic_stream *);
|
||||
|
||||
void
|
||||
lsquic_send_ctl_verneg_done (struct lsquic_send_ctl *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -231,7 +231,7 @@ create_connections (struct http_client_ctx *client_ctx)
|
|||
{
|
||||
zero_rtt = client_ctx->hcc_zero_rtt;
|
||||
zero_rtt_len = client_ctx->hcc_zero_rtt_len;
|
||||
LSQ_INFO("create connection zero_rtt %ld bytes", zero_rtt_len);
|
||||
LSQ_INFO("create connection zero_rtt %zu bytes", zero_rtt_len);
|
||||
}
|
||||
|
||||
while (client_ctx->hcc_n_open_conns < client_ctx->hcc_concurrency &&
|
||||
|
@ -268,7 +268,8 @@ http_client_on_new_conn (void *stream_if_ctx, lsquic_conn_t *conn)
|
|||
client_ctx->hcc_total_n_reqs -= conn_h->ch_n_reqs;
|
||||
TAILQ_INSERT_TAIL(&client_ctx->conn_ctxs, conn_h, next_ch);
|
||||
++conn_h->client_ctx->hcc_n_open_conns;
|
||||
create_streams(client_ctx, conn_h);
|
||||
if (!TAILQ_EMPTY(&client_ctx->hcc_path_elems))
|
||||
create_streams(client_ctx, conn_h);
|
||||
conn_h->ch_created = lsquic_time_now();
|
||||
return conn_h;
|
||||
}
|
||||
|
@ -365,7 +366,7 @@ http_client_on_hsk_done (lsquic_conn_t *conn, enum lsquic_hsk_status status)
|
|||
if (ret > 0)
|
||||
{
|
||||
client_ctx->hcc_zero_rtt_len = ret;
|
||||
LSQ_INFO("get zero_rtt %ld bytes", client_ctx->hcc_zero_rtt_len);
|
||||
LSQ_INFO("get zero_rtt %zu bytes", client_ctx->hcc_zero_rtt_len);
|
||||
client_ctx->hcc_flags |= HCC_RTT_INFO;
|
||||
/* clear file and prepare to write */
|
||||
if (client_ctx->hcc_zero_rtt_file)
|
||||
|
@ -392,7 +393,7 @@ http_client_on_hsk_done (lsquic_conn_t *conn, enum lsquic_hsk_status status)
|
|||
size_t ret2 = fwrite(client_ctx->hcc_zero_rtt, 1,
|
||||
client_ctx->hcc_zero_rtt_len,
|
||||
client_ctx->hcc_zero_rtt_file);
|
||||
LSQ_DEBUG("wrote %ld bytes to zero_rtt file", ret2);
|
||||
LSQ_DEBUG("wrote %zu bytes to zero_rtt file", ret2);
|
||||
if (ret2 == client_ctx->hcc_zero_rtt_len)
|
||||
{
|
||||
fclose(client_ctx->hcc_zero_rtt_file);
|
||||
|
@ -419,6 +420,11 @@ http_client_on_hsk_done (lsquic_conn_t *conn, enum lsquic_hsk_status status)
|
|||
++s_stat_conns_ok;
|
||||
update_sample_stats(&s_stat_to_conn,
|
||||
lsquic_time_now() - conn_h->ch_created);
|
||||
if (TAILQ_EMPTY(&client_ctx->hcc_path_elems))
|
||||
{
|
||||
LSQ_INFO("no paths mode: close connection");
|
||||
lsquic_conn_close(conn_h->conn);
|
||||
}
|
||||
}
|
||||
else
|
||||
++s_stat_conns_failed;
|
||||
|
@ -762,7 +768,9 @@ usage (const char *prog)
|
|||
"Usage: %s [opts]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -p PATH Path to request. May be specified more than once.\n"
|
||||
" -p PATH Path to request. May be specified more than once. If no\n"
|
||||
" path is specified, the connection is closed as soon as\n"
|
||||
" handshake succeeds.\n"
|
||||
" -n CONNS Number of concurrent connections. Defaults to 1.\n"
|
||||
" -r NREQS Total number of requests to send. Defaults to 1.\n"
|
||||
" -R MAXREQS Maximum number of requests per single connection. Some\n"
|
||||
|
@ -1180,16 +1188,11 @@ main (int argc, char **argv)
|
|||
{
|
||||
client_ctx.hcc_flags |= HCC_RTT_INFO;
|
||||
client_ctx.hcc_zero_rtt_len = ret;
|
||||
LSQ_DEBUG("read %ld bytes from zero_rtt file", ret);
|
||||
LSQ_DEBUG("read %zu bytes from zero_rtt file", ret);
|
||||
}
|
||||
else
|
||||
LSQ_DEBUG("zero_rtt file is empty");
|
||||
}
|
||||
if (TAILQ_EMPTY(&client_ctx.hcc_path_elems))
|
||||
{
|
||||
fprintf(stderr, "Specify at least one path using -p option\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
start_time = lsquic_time_now();
|
||||
if (0 != prog_prep(&prog))
|
||||
|
|
10
test/prog.c
10
test/prog.c
|
@ -152,6 +152,8 @@ prog_print_common_options (const struct prog *prog, FILE *out)
|
|||
|
||||
|
||||
fprintf(out,
|
||||
" -k Connect UDP socket. Only meant to be used with clients\n"
|
||||
" to pick up ICMP errors.\n"
|
||||
" -i USECS Clock granularity in microseconds. Defaults to %u.\n",
|
||||
LSQUIC_DF_CLOCK_GRANULARITY
|
||||
);
|
||||
|
@ -239,6 +241,14 @@ prog_set_opt (struct prog *prog, int opt, const char *arg)
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
case 'k':
|
||||
{
|
||||
struct service_port *sport = TAILQ_LAST(prog->prog_sports, sport_head);
|
||||
if (!sport)
|
||||
sport = &prog->prog_dummy_sport;
|
||||
sport->sp_flags |= SPORT_CONNECT;
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ prog_init (struct prog *, unsigned lsquic_engine_flags, struct sport_head *,
|
|||
# define IP_DONTFRAG_FLAG ""
|
||||
#endif
|
||||
|
||||
#define PROG_OPTS "i:m:c:y:L:l:o:H:s:S:Y:z:" IP_DONTFRAG_FLAG
|
||||
#define PROG_OPTS "i:km:c:y:L:l:o:H:s:S:Y:z:" IP_DONTFRAG_FLAG
|
||||
|
||||
/* Returns:
|
||||
* 0 Applied
|
||||
|
|
|
@ -545,6 +545,13 @@ read_one_packet (struct read_iter *iter)
|
|||
}
|
||||
|
||||
|
||||
#if __GNUC__
|
||||
# define UNLIKELY(cond) __builtin_expect(cond, 0)
|
||||
#else
|
||||
# define UNLIKELY(cond) cond
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
read_handler (evutil_socket_t fd, short flags, void *ctx)
|
||||
{
|
||||
|
@ -570,6 +577,14 @@ read_handler (evutil_socket_t fd, short flags, void *ctx)
|
|||
rop = read_one_packet(&iter);
|
||||
while (ROP_OK == rop);
|
||||
|
||||
if (UNLIKELY(ROP_ERROR == rop && (sport->sp_flags & SPORT_CONNECT)
|
||||
&& errno == ECONNREFUSED))
|
||||
{
|
||||
LSQ_ERROR("connection refused: exit program");
|
||||
prog_cleanup(sport->sp_prog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
n_batches += iter.ri_idx > 0;
|
||||
|
||||
for (n = 0; n < iter.ri_idx; ++n)
|
||||
|
@ -623,7 +638,7 @@ sport_init_client (struct service_port *sport, struct lsquic_engine *engine,
|
|||
int flags;
|
||||
#endif
|
||||
SOCKET_TYPE sockfd;
|
||||
socklen_t socklen;
|
||||
socklen_t socklen, peer_socklen;
|
||||
union {
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_in6 sin6;
|
||||
|
@ -663,6 +678,19 @@ sport_init_client (struct service_port *sport, struct lsquic_engine *engine,
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (sport->sp_flags & SPORT_CONNECT)
|
||||
{
|
||||
peer_socklen = AF_INET == sa_peer->sa_family
|
||||
? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
|
||||
if (0 != connect(sockfd, sa_peer, peer_socklen))
|
||||
{
|
||||
saved_errno = errno;
|
||||
CLOSE_SOCKET(sockfd);
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make socket non-blocking */
|
||||
#ifndef WIN32
|
||||
flags = fcntl(sockfd, F_GETFL);
|
||||
|
@ -1079,6 +1107,11 @@ set_engine_option (struct lsquic_engine_settings *settings,
|
|||
settings->es_pace_packets = atoi(val);
|
||||
return 0;
|
||||
}
|
||||
if (0 == strncmp(name, "handshake_to", 12))
|
||||
{
|
||||
settings->es_handshake_to = atoi(val);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 13:
|
||||
if (0 == strncmp(name, "support_tcid0", 13))
|
||||
|
|
|
@ -28,6 +28,7 @@ enum sport_flags
|
|||
SPORT_SET_SNDBUF = (1 << 1), /* SO_SNDBUF */
|
||||
SPORT_SET_RCVBUF = (1 << 2), /* SO_RCVBUF */
|
||||
SPORT_SERVER = (1 << 3),
|
||||
SPORT_CONNECT = (1 << 4),
|
||||
};
|
||||
|
||||
struct service_port {
|
||||
|
|
Loading…
Reference in a new issue