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:
Dmitri Tikhonov 2019-02-18 08:40:51 -05:00
parent 3329170846
commit 9c4445241e
12 changed files with 113 additions and 20 deletions

View file

@ -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.

View file

@ -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:

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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

View file

@ -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))

View file

@ -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;
}

View file

@ -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

View file

@ -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))

View file

@ -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 {