From fbfb0a0616a193dcde7652d5438ad0c60e29cd30 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Tue, 29 Sep 2020 19:22:57 +0000 Subject: [PATCH 001/361] dtrace: convert quictrace_recv to packet_received --- lib/quicly.c | 8 +++----- quicly-probes.d | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index b9731eb8c..1e36cb3e2 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5392,8 +5392,7 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * QUICLY_PROBE(ACCEPT, *conn, (*conn)->stash.now, QUICLY_PROBE_HEXDUMP(packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len), address_token); - QUICLY_PROBE(CRYPTO_DECRYPT, *conn, (*conn)->stash.now, pn, payload.base, payload.len); - QUICLY_PROBE(QUICTRACE_RECV, *conn, (*conn)->stash.now, pn); + QUICLY_PROBE(PACKET_RECEIVED, *conn, (*conn)->stash.now, pn, payload.base, payload.len); /* handle the input; we ignore is_ack_only, we consult if there's any output from TLS in response to CH anyways */ (*conn)->super.stats.num_packets.received += 1; @@ -5586,12 +5585,11 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka if ((ret = decrypt_packet(header_protection, aead.cb, aead.ctx, &(*space)->next_expected_packet_number, packet, &pn, &payload)) != 0) { ++conn->super.stats.num_packets.decryption_failed; - QUICLY_PROBE(CRYPTO_DECRYPT, conn, conn->stash.now, pn, NULL, 0); + QUICLY_PROBE(CRYPTO_DECRYPT_FAILURE, conn, conn->stash.now, pn); goto Exit; } - QUICLY_PROBE(CRYPTO_DECRYPT, conn, conn->stash.now, pn, payload.base, payload.len); - QUICLY_PROBE(QUICTRACE_RECV, conn, conn->stash.now, pn); + QUICLY_PROBE(PACKET_RECEIVED, conn, conn->stash.now, pn, payload.base, payload.len); /* update states */ if (conn->super.state == QUICLY_STATE_FIRSTFLIGHT) diff --git a/quicly-probes.d b/quicly-probes.d index d9e84e7a4..3fbf3ddd5 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -35,7 +35,7 @@ provider quicly { probe idle_timeout(struct st_quicly_conn_t *conn, int64_t at); probe stateless_reset_receive(struct st_quicly_conn_t *conn, int64_t at); - probe crypto_decrypt(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, const void *decrypted, size_t decrypted_len); + probe crypto_decrypt_failure(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); probe crypto_handshake(struct st_quicly_conn_t *conn, int64_t at, int ret); probe crypto_update_secret(struct st_quicly_conn_t *conn, int64_t at, int is_enc, uint8_t epoch, const char *label, const char *secret); probe crypto_send_key_update(struct st_quicly_conn_t *conn, int64_t at, uint64_t phase, const char *secret); @@ -106,7 +106,7 @@ provider quicly { uint64_t max_ack_delay, int ignore_order); probe quictrace_sent(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, size_t len, uint8_t packet_type); - probe quictrace_recv(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); + probe packet_received(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, const void *decrypted, size_t decrypted_len); probe quictrace_send_stream(struct st_quicly_conn_t *conn, int64_t at, struct st_quicly_stream_t *stream, uint64_t off, size_t len, int fin); probe quictrace_recv_stream(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t off, size_t len, int fin); From c670a5e1adae8b3e0deb8c856d0eca6a5d26d847 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Tue, 29 Sep 2020 21:26:15 +0000 Subject: [PATCH 002/361] dtrace: convert quictrace_sent to packet_sent --- lib/quicly.c | 6 ++---- quicly-probes.d | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 1e36cb3e2..ddaa81082 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -2933,10 +2933,8 @@ static int commit_send_packet(quicly_conn_t *conn, quicly_send_context_t *s, enu quicly_sentmap_commit(&conn->egress.loss.sentmap, (uint16_t)packet_bytes_in_flight); conn->egress.cc.impl->cc_on_sent(&conn->egress.cc, &conn->egress.loss, (uint32_t)packet_bytes_in_flight, conn->stash.now); - QUICLY_PROBE(PACKET_COMMIT, conn, conn->stash.now, conn->egress.packet_number, s->dst - s->target.first_byte_at, - !s->target.ack_eliciting); - QUICLY_PROBE(QUICTRACE_SENT, conn, conn->stash.now, conn->egress.packet_number, s->dst - s->target.first_byte_at, - get_epoch(*s->target.first_byte_at)); + QUICLY_PROBE(PACKET_SENT, conn, conn->stash.now, conn->egress.packet_number, s->dst - s->target.first_byte_at, + get_epoch(*s->target.first_byte_at), !s->target.ack_eliciting); ++conn->egress.packet_number; ++conn->super.stats.num_packets.sent; diff --git a/quicly-probes.d b/quicly-probes.d index 3fbf3ddd5..82ba73e36 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -44,7 +44,6 @@ provider quicly { probe crypto_receive_key_update_prepare(struct st_quicly_conn_t *conn, int64_t at, uint64_t phase, const char *secret); probe packet_prepare(struct st_quicly_conn_t *conn, int64_t at, uint8_t first_octet, const char *dcid); - probe packet_commit(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, size_t len, int ack_only); probe packet_acked(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, int is_late_ack); probe packet_lost(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); @@ -105,7 +104,7 @@ provider quicly { probe ack_frequency_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t sequence, uint64_t packet_tolerance, uint64_t max_ack_delay, int ignore_order); - probe quictrace_sent(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, size_t len, uint8_t packet_type); + probe packet_sent(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, size_t len, uint8_t packet_type, int ack_only); probe packet_received(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, const void *decrypted, size_t decrypted_len); probe quictrace_send_stream(struct st_quicly_conn_t *conn, int64_t at, struct st_quicly_stream_t *stream, uint64_t off, size_t len, int fin); From 0e4df93926988cb2646cc310343bfe6a72f9e4d4 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Tue, 29 Sep 2020 21:26:51 +0000 Subject: [PATCH 003/361] dtrace: group the packet_* probes together --- quicly-probes.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quicly-probes.d b/quicly-probes.d index 82ba73e36..d463369dc 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -43,6 +43,8 @@ provider quicly { probe crypto_receive_key_update(struct st_quicly_conn_t *conn, int64_t at, uint64_t phase, const char *secret); probe crypto_receive_key_update_prepare(struct st_quicly_conn_t *conn, int64_t at, uint64_t phase, const char *secret); + probe packet_sent(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, size_t len, uint8_t packet_type, int ack_only); + probe packet_received(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, const void *decrypted, size_t decrypted_len); probe packet_prepare(struct st_quicly_conn_t *conn, int64_t at, uint8_t first_octet, const char *dcid); probe packet_acked(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, int is_late_ack); probe packet_lost(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); @@ -104,8 +106,6 @@ provider quicly { probe ack_frequency_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t sequence, uint64_t packet_tolerance, uint64_t max_ack_delay, int ignore_order); - probe packet_sent(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, size_t len, uint8_t packet_type, int ack_only); - probe packet_received(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, const void *decrypted, size_t decrypted_len); probe quictrace_send_stream(struct st_quicly_conn_t *conn, int64_t at, struct st_quicly_stream_t *stream, uint64_t off, size_t len, int fin); probe quictrace_recv_stream(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t off, size_t len, int fin); From 0f53ad808a2fba934e197748d437d38972decbcc Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Mon, 19 Oct 2020 17:53:43 +0000 Subject: [PATCH 004/361] dtrace: emit packet_type from the packet_received probe --- lib/quicly.c | 4 ++-- quicly-probes.d | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index ddaa81082..03e3aff06 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5390,7 +5390,7 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * QUICLY_PROBE(ACCEPT, *conn, (*conn)->stash.now, QUICLY_PROBE_HEXDUMP(packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len), address_token); - QUICLY_PROBE(PACKET_RECEIVED, *conn, (*conn)->stash.now, pn, payload.base, payload.len); + QUICLY_PROBE(PACKET_RECEIVED, *conn, (*conn)->stash.now, pn, payload.base, payload.len, get_epoch(packet->octets.base[0])); /* handle the input; we ignore is_ack_only, we consult if there's any output from TLS in response to CH anyways */ (*conn)->super.stats.num_packets.received += 1; @@ -5587,7 +5587,7 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka goto Exit; } - QUICLY_PROBE(PACKET_RECEIVED, conn, conn->stash.now, pn, payload.base, payload.len); + QUICLY_PROBE(PACKET_RECEIVED, conn, conn->stash.now, pn, payload.base, payload.len, get_epoch(packet->octets.base[0])); /* update states */ if (conn->super.state == QUICLY_STATE_FIRSTFLIGHT) diff --git a/quicly-probes.d b/quicly-probes.d index d463369dc..85936f4c6 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -44,7 +44,7 @@ provider quicly { probe crypto_receive_key_update_prepare(struct st_quicly_conn_t *conn, int64_t at, uint64_t phase, const char *secret); probe packet_sent(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, size_t len, uint8_t packet_type, int ack_only); - probe packet_received(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, const void *decrypted, size_t decrypted_len); + probe packet_received(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, const void *decrypted, size_t decrypted_len, uint8_t packet_type); probe packet_prepare(struct st_quicly_conn_t *conn, int64_t at, uint8_t first_octet, const char *dcid); probe packet_acked(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, int is_late_ack); probe packet_lost(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); From 892a7c3ab1b50323a578618b22755a6f035fc481 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Thu, 5 Nov 2020 12:36:51 -0800 Subject: [PATCH 005/361] qlog: scaffold the qlog-adapter program --- misc/qlog-adapter.py | 99 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 misc/qlog-adapter.py diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py new file mode 100644 index 000000000..e73c55b5f --- /dev/null +++ b/misc/qlog-adapter.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python +# +# Copyright (c) 2020 Fastly, Toru Maesaka +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import sys +import json + +PACKET_LABELS = ["initial", "0rtt", "handshake", "1rtt"] + +def handle_packet_received(events, idx): + source_event = events[idx] + qlog_event_data = { + "packet_type": PACKET_LABELS[source_event["packet-type"]], + "header": { + "packet_number": source_event["pn"] + }, + "frames": [] + } + return [source_event["time"], "transport", "packet_received", qlog_event_data] + +def handle_packet_sent(events, idx): + source_event = events[idx] + qlog_event_data = { + "packet_type": PACKET_LABELS[source_event["packet-type"]], + "header": { + "packet_number": source_event["pn"] + }, + "frames": [] + } + return [source_event["time"], "transport", "packet_sent", qlog_event_data] + +QLOG_EVENT_HANDLERS = { + "packet-received": handle_packet_received, + "packet-sent": handle_packet_sent +} + +def usage(): + print(r""" +Usage: + python qlog-adapter.py inTrace.jsonl +""".strip()) + +def load_quicly_events(infile): + events = [] + with open(infile, "r") as fh: + for line in fh: + events.append(json.loads(line)) + return events + +def main(): + if len(sys.argv) != 2: + usage() + sys.exit(1) + + (_, infile) = sys.argv + source_events = load_quicly_events(infile) + trace = { + "vantage_point": { + "type": "server" + }, + "event_fields": [ + "time", + "category", + "event", + "data" + ], + "events": [] + } + for i, event in enumerate(source_events): + handler = QLOG_EVENT_HANDLERS.get(event["type"]) + if handler: + trace["events"].append(handler(source_events, i)) + + print(json.dumps({ + "qlog_version": "draft-02-wip", + "title": "h2o/quicly qlog", + "traces": [trace] + })) + +if __name__ == "__main__": + main() From 4d328135b042bfeec463dc504e22ffc888e31e0d Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Thu, 5 Nov 2020 14:53:50 -0800 Subject: [PATCH 006/361] qlog: introduce a frame event handler registry --- misc/qlog-adapter.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index e73c55b5f..1bea38427 100644 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -34,6 +34,15 @@ def handle_packet_received(events, idx): }, "frames": [] } + + for i in range(idx+1, len(events)): + ev = events[i] + if ev["type"] == "packet-prepare" or QLOG_EVENT_HANDLERS.has_key(ev["type"]): + break + handler = FRAME_EVENT_HANDLERS.get(ev["type"]) + if handler: + qlog_event_data["frames"].append(handler(ev)) + return [source_event["time"], "transport", "packet_received", qlog_event_data] def handle_packet_sent(events, idx): @@ -47,11 +56,35 @@ def handle_packet_sent(events, idx): } return [source_event["time"], "transport", "packet_sent", qlog_event_data] +def handle_quictrace_recv_ack(event): + return { + "frame_type": "ack", + } + +def handle_ping_receive(event): + return { + "frame_type": "ping", + } + + +def handle_recv_crypto_frame(event): + return { + "frame_type": "crypto", + "length": event["len"], + "offset": event["off"] + } + QLOG_EVENT_HANDLERS = { "packet-received": handle_packet_received, "packet-sent": handle_packet_sent } +FRAME_EVENT_HANDLERS = { + "ping-receive": handle_ping_receive, + "quictrace-recv-ack": handle_quictrace_recv_ack, + "recv-crypto-frame": handle_recv_crypto_frame, +} + def usage(): print(r""" Usage: From 08005fb65914b01c6687538eb6b7531987abdc2a Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Fri, 6 Nov 2020 11:11:03 -0800 Subject: [PATCH 007/361] qlog: simplify handle_packet_received() --- misc/qlog-adapter.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 1bea38427..9a543c79a 100644 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -26,24 +26,22 @@ PACKET_LABELS = ["initial", "0rtt", "handshake", "1rtt"] def handle_packet_received(events, idx): - source_event = events[idx] - qlog_event_data = { - "packet_type": PACKET_LABELS[source_event["packet-type"]], - "header": { - "packet_number": source_event["pn"] - }, - "frames": [] - } - + frames = [] for i in range(idx+1, len(events)): ev = events[i] if ev["type"] == "packet-prepare" or QLOG_EVENT_HANDLERS.has_key(ev["type"]): break handler = FRAME_EVENT_HANDLERS.get(ev["type"]) if handler: - qlog_event_data["frames"].append(handler(ev)) + frames.append(handler(ev)) - return [source_event["time"], "transport", "packet_received", qlog_event_data] + return [events[idx]["time"], "transport", "packet_received", { + "packet_type": PACKET_LABELS[events[idx]["packet-type"]], + "header": { + "packet_number": events[idx]["pn"] + }, + "frames": frames + }] def handle_packet_sent(events, idx): source_event = events[idx] From f39ef30a95135d158a9f113b53b58e3d7f6f058e Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Fri, 6 Nov 2020 12:44:59 -0800 Subject: [PATCH 008/361] qlog: frame search code for the packet_sent event --- misc/qlog-adapter.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 9a543c79a..ede430f38 100644 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -44,15 +44,26 @@ def handle_packet_received(events, idx): }] def handle_packet_sent(events, idx): - source_event = events[idx] - qlog_event_data = { - "packet_type": PACKET_LABELS[source_event["packet-type"]], + frames = [] + i = idx-1 + while i > 0 and events[i]["type"] != "packet-prepare": + handler = FRAME_EVENT_HANDLERS.get(events[i]["type"]) + if handler: + frames.append(handler(events[i])) + i -= 1 + + return [events[idx]["time"], "transport", "packet_sent", { + "packet_type": PACKET_LABELS[events[idx]["packet-type"]], "header": { - "packet_number": source_event["pn"] + "packet_number": events[idx]["pn"] }, - "frames": [] + "frames": frames + }] + +def handle_ack_send(event): + return { + "frame_type": "ack", } - return [source_event["time"], "transport", "packet_sent", qlog_event_data] def handle_quictrace_recv_ack(event): return { @@ -78,6 +89,7 @@ def handle_recv_crypto_frame(event): } FRAME_EVENT_HANDLERS = { + "ack-send": handle_ack_send, "ping-receive": handle_ping_receive, "quictrace-recv-ack": handle_quictrace_recv_ack, "recv-crypto-frame": handle_recv_crypto_frame, From d8c25bc6ebe6f134c08d87fbd4c64d63f0093258 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Wed, 11 Nov 2020 21:50:37 -0800 Subject: [PATCH 009/361] qlog: crypto is a stream frame --- misc/qlog-adapter.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index ede430f38..0d2ac944f 100644 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -75,10 +75,11 @@ def handle_ping_receive(event): "frame_type": "ping", } - -def handle_recv_crypto_frame(event): +def handle_stream_receive(event): + label = "stream" if event["stream-id"] > 0 else "crypto" return { - "frame_type": "crypto", + "frame_type": label, + "stream_id": event["stream-id"], "length": event["len"], "offset": event["off"] } @@ -92,7 +93,7 @@ def handle_recv_crypto_frame(event): "ack-send": handle_ack_send, "ping-receive": handle_ping_receive, "quictrace-recv-ack": handle_quictrace_recv_ack, - "recv-crypto-frame": handle_recv_crypto_frame, + "stream-receive": handle_stream_receive, } def usage(): From 6809118b0a4fce2f7db6892933f4bd663271d756 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Wed, 11 Nov 2020 22:10:01 -0800 Subject: [PATCH 010/361] qlog: fix incorrect stream/crypto definition --- misc/qlog-adapter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 0d2ac944f..1135f2861 100644 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -76,7 +76,7 @@ def handle_ping_receive(event): } def handle_stream_receive(event): - label = "stream" if event["stream-id"] > 0 else "crypto" + label = "stream" if event["stream-id"] >= 0 else "crypto" return { "frame_type": label, "stream_id": event["stream-id"], From 0821d4356744e1a3ebe38ffaad2c2ff06824bb38 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 16 Nov 2020 14:57:05 +0900 Subject: [PATCH 011/361] no need to optimize for a seldom used frame --- lib/quicly.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 5eb64672e..f69939b88 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -2572,7 +2572,6 @@ static int on_ack_max_stream_data(quicly_sentmap_t *map, const quicly_sent_packe quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); quicly_stream_t *stream; - /* TODO cache pointer to stream (using a generation counter?) */ if ((stream = quicly_get_stream(conn, sent->data.stream.stream_id)) != NULL) { if (acked) { quicly_maxsender_acked(&stream->_send_aux.max_stream_data_sender, &sent->data.max_stream_data.args); From c0c88a786d3a77c5510d281ff6acd4ec1eb37d56 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 16 Nov 2020 14:59:27 +0900 Subject: [PATCH 012/361] on_ack_stream uses a frame-level flag too --- lib/quicly.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index f69939b88..c94443e14 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -2714,7 +2714,6 @@ static int on_ack_new_token(quicly_sentmap_t *map, const quicly_sent_packet_t *p { quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); - /* TODO use `packet->bytes_in_flight != 0`, like on_ack_stream */ if (sent->data.new_token.is_inflight) { --conn->egress.new_token.num_inflight; sent->data.new_token.is_inflight = 0; From da64032208c95f092820811973c54e18d237613d Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 16 Nov 2020 15:00:22 +0900 Subject: [PATCH 013/361] maybe we are used to the existing interface? --- lib/quicly.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index c94443e14..193d3127a 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3170,7 +3170,6 @@ static int allocate_ack_eliciting_frame(quicly_conn_t *conn, quicly_send_context if ((*sent = quicly_sentmap_allocate(&conn->egress.loss.sentmap, acked)) == NULL) return PTLS_ERROR_NO_MEMORY; - /* TODO return the remaining window that the sender can use */ return ret; } From 4f1f8ba7b45fbc40329857f4d7867d7a5c5cb58c Mon Sep 17 00:00:00 2001 From: Jana Iyengar Date: Sun, 15 Nov 2020 22:14:07 -0800 Subject: [PATCH 014/361] fix servername --- misc/quic-interop-runner/run_endpoint.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/quic-interop-runner/run_endpoint.sh b/misc/quic-interop-runner/run_endpoint.sh index 99f693280..2c8af397f 100755 --- a/misc/quic-interop-runner/run_endpoint.sh +++ b/misc/quic-interop-runner/run_endpoint.sh @@ -26,7 +26,7 @@ if [ "$ROLE" == "client" ]; then echo "Requests: " $REQUESTS # Pull server and file names out of requests, generate file list for cli. for REQ in $REQUESTS; do - SERVER=`echo $REQ | cut -f3 -d'/'` + SERVER=`echo $REQ | cut -f3 -d'/' | cut -f1 -d':'` FILE=`echo $REQ | cut -f4 -d'/'` FILES=${FILES}" "${FILE} CLI_LIST=${CLI_LIST}" -P /"${FILE} From d1067eaa3d8f1f8f2174ce3e9ccfa7174538f9f8 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Mon, 16 Nov 2020 10:59:10 -0800 Subject: [PATCH 015/361] qlog: support the new_connection_id frame type --- misc/qlog-adapter.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 1135f2861..2d46613c3 100644 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -65,6 +65,24 @@ def handle_ack_send(event): "frame_type": "ack", } +def handle_new_connection_id_receive(event): + return { + "frame_type": "new_connection_id", + "sequence_number": event["sequence"], + "retire_prior_to": event["retire-prior-to"], + "connection_id": event["cid"], + "stateless_reset_token": event["stateless-reset-token"] + } + +def handle_new_connection_id_send(event): + return { + "frame_type": "new_connection_id", + "sequence_number": event["sequence"], + "retire_prior_to": event["retire-prior-to"], + "connection_id": event["cid"], + "stateless_reset_token": event["stateless-reset-token"] + } + def handle_quictrace_recv_ack(event): return { "frame_type": "ack", @@ -91,6 +109,8 @@ def handle_stream_receive(event): FRAME_EVENT_HANDLERS = { "ack-send": handle_ack_send, + "new-connection-id-receive": handle_new_connection_id_receive, + "new-connection-id-send": handle_new_connection_id_send, "ping-receive": handle_ping_receive, "quictrace-recv-ack": handle_quictrace_recv_ack, "stream-receive": handle_stream_receive, From dddb3369abe1734826cfe0839fabcefcdd8536cb Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Mon, 16 Nov 2020 12:39:07 -0800 Subject: [PATCH 016/361] qlog: support the connection_close frame type --- misc/qlog-adapter.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 2d46613c3..2f431de12 100644 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -102,6 +102,22 @@ def handle_stream_receive(event): "offset": event["off"] } +def handle_transport_close_receive(event): + return { + "frame_type": "connection_close", + "offending_frame_type": event["frame-type"], + "error_code": event["error-code"], + "reason": event["reason-phrase"] + } + +def handle_transport_close_send(event): + return { + "frame_type": "connection_close", + "offending_frame_type": event["frame-type"], + "error_code": event["error-code"], + "reason": event["reason-phrase"] + } + QLOG_EVENT_HANDLERS = { "packet-received": handle_packet_received, "packet-sent": handle_packet_sent @@ -114,6 +130,8 @@ def handle_stream_receive(event): "ping-receive": handle_ping_receive, "quictrace-recv-ack": handle_quictrace_recv_ack, "stream-receive": handle_stream_receive, + "transport-close-receive": handle_transport_close_receive, + "transport-close-send": handle_transport_close_send } def usage(): From d3280a834c2e8eb531df2200eabf13f4dbb455bd Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Mon, 16 Nov 2020 12:43:25 -0800 Subject: [PATCH 017/361] qlog: require python3 for the adapter --- misc/qlog-adapter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) mode change 100644 => 100755 misc/qlog-adapter.py diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py old mode 100644 new mode 100755 index 2f431de12..415599bf3 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # Copyright (c) 2020 Fastly, Toru Maesaka # @@ -29,7 +29,7 @@ def handle_packet_received(events, idx): frames = [] for i in range(idx+1, len(events)): ev = events[i] - if ev["type"] == "packet-prepare" or QLOG_EVENT_HANDLERS.has_key(ev["type"]): + if ev["type"] == "packet-prepare" or ev["type"] in QLOG_EVENT_HANDLERS: break handler = FRAME_EVENT_HANDLERS.get(ev["type"]) if handler: From 981f1b00de90bdb8c31678a15c830b34d81ff412 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Mon, 16 Nov 2020 16:04:21 -0800 Subject: [PATCH 018/361] qlog: support the new_token frame type --- misc/qlog-adapter.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 415599bf3..845ceaf70 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -83,6 +83,20 @@ def handle_new_connection_id_send(event): "stateless_reset_token": event["stateless-reset-token"] } +def handle_new_token_receive(event): + return { + "frame_type": "new_token", + "token": event["token"], + "generation": event["generation"] + } + +def handle_new_token_send(event): + return { + "frame_type": "new_token", + "token": event["token"], + "generation": event["generation"] + } + def handle_quictrace_recv_ack(event): return { "frame_type": "ack", @@ -127,6 +141,8 @@ def handle_transport_close_send(event): "ack-send": handle_ack_send, "new-connection-id-receive": handle_new_connection_id_receive, "new-connection-id-send": handle_new_connection_id_send, + "new-token-receive": handle_new_token_receive, + "new-token-send": handle_new_token_send, "ping-receive": handle_ping_receive, "quictrace-recv-ack": handle_quictrace_recv_ack, "stream-receive": handle_stream_receive, From 68619ea2001af4cf9a70e38c33e10671a65795c4 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Mon, 16 Nov 2020 16:19:33 -0800 Subject: [PATCH 019/361] qlog: support the handshake_done frame type --- misc/qlog-adapter.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 845ceaf70..698d1f7f4 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -65,6 +65,16 @@ def handle_ack_send(event): "frame_type": "ack", } +def handle_handshake_done_receive(event): + return { + "frame_type": "handshake_done", + } + +def handle_handshake_done_send(event): + return { + "frame_type": "handshake_done", + } + def handle_new_connection_id_receive(event): return { "frame_type": "new_connection_id", @@ -139,6 +149,8 @@ def handle_transport_close_send(event): FRAME_EVENT_HANDLERS = { "ack-send": handle_ack_send, + "handshake-done-receive": handle_handshake_done_receive, + "handshake-done-send": handle_handshake_done_send, "new-connection-id-receive": handle_new_connection_id_receive, "new-connection-id-send": handle_new_connection_id_send, "new-token-receive": handle_new_token_receive, From 6712ecf56d519b6230cbc29ae0965293734c5a9d Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 17 Nov 2020 15:26:17 +0900 Subject: [PATCH 020/361] failure to set DF bit is okay, some platforms do not support it even though their SDK might (e.g., macOS 10.16 SDK used on macOS 10.15) --- src/cli.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/cli.c b/src/cli.c index 2c0155366..be2219758 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1406,18 +1406,14 @@ int main(int argc, char **argv) #if defined(IP_DONTFRAG) { int on = 1; - if (setsockopt(fd, IPPROTO_IP, IP_DONTFRAG, &on, sizeof(on)) != 0) { - perror("setsockopt(IP_DONTFRAG) failed"); - return 1; - } + if (setsockopt(fd, IPPROTO_IP, IP_DONTFRAG, &on, sizeof(on)) != 0) + perror("Warning: setsockopt(IP_DONTFRAG) failed"); } #elif defined(IP_PMTUDISC_DO) { int opt = IP_PMTUDISC_DO; - if (setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &opt, sizeof(opt)) != 0) { - perror("setsockopt(IP_MTU_DISCOVER) failed"); - return 1; - } + if (setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &opt, sizeof(opt)) != 0) + perror("Warning: setsockopt(IP_MTU_DISCOVER) failed"); } #endif From 194d9df9b8ef302d0f1ed8f13141bd2cc41cf185 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Tue, 17 Nov 2020 08:55:02 -0800 Subject: [PATCH 021/361] qlog: support the stop_sending frame type --- misc/qlog-adapter.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 698d1f7f4..f7a64828b 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -107,14 +107,20 @@ def handle_new_token_send(event): "generation": event["generation"] } +def handle_ping_receive(event): + return { + "frame_type": "ping", + } + def handle_quictrace_recv_ack(event): return { "frame_type": "ack", } -def handle_ping_receive(event): +def handle_stream_on_send_stop(event): return { - "frame_type": "ping", + "frame_type": "stop_sending", + "stream_id": event["stream-id"] } def handle_stream_receive(event): @@ -157,6 +163,7 @@ def handle_transport_close_send(event): "new-token-send": handle_new_token_send, "ping-receive": handle_ping_receive, "quictrace-recv-ack": handle_quictrace_recv_ack, + "stream-on-send-stop": handle_stream_on_send_stop, "stream-receive": handle_stream_receive, "transport-close-receive": handle_transport_close_receive, "transport-close-send": handle_transport_close_send From 95d2bcf5a9a3e10b49cd804908f3c40467bb8ea2 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Tue, 17 Nov 2020 11:40:06 -0800 Subject: [PATCH 022/361] qlog: support max data related frames --- misc/qlog-adapter.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index f7a64828b..b6d35506d 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -75,6 +75,32 @@ def handle_handshake_done_send(event): "frame_type": "handshake_done", } +def handle_max_data_receive(event): + return { + "frame_type": "max_data", + "maximum": event["limit"] + } + +def handle_max_data_send(event): + return { + "frame_type": "max_data", + "maximum": event["limit"] + } + +def handle_max_stream_data_receive(event): + return { + "frame_type": "max_stream_data", + "stream_id": event["stream-id"], + "maximum": event["limit"] + } + +def handle_max_stream_data_send(event): + return { + "frame_type": "max_stream_data", + "stream_id": event["stream-id"], + "maximum": event["limit"] + } + def handle_new_connection_id_receive(event): return { "frame_type": "new_connection_id", @@ -157,6 +183,10 @@ def handle_transport_close_send(event): "ack-send": handle_ack_send, "handshake-done-receive": handle_handshake_done_receive, "handshake-done-send": handle_handshake_done_send, + "max-data-receive": handle_max_data_receive, + "max-data-send": handle_max_data_send, + "max-stream-data-receive": handle_max_stream_data_receive, + "max-stream-data-send": handle_max_stream_data_send, "new-connection-id-receive": handle_new_connection_id_receive, "new-connection-id-send": handle_new_connection_id_send, "new-token-receive": handle_new_token_receive, From 3d3be2e41890ed1b78a762c5867f1a1d3bf7bb46 Mon Sep 17 00:00:00 2001 From: Jason Huh Date: Wed, 18 Nov 2020 13:32:23 +0900 Subject: [PATCH 023/361] Fix the confusing line spacing --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 995c22fa6..5142bacb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,8 @@ INCLUDE_DIRECTORIES( ${OPENSSL_INCLUDE_DIR} deps/klib deps/picotls/include - deps/picotest include + deps/picotest + include ${CMAKE_CURRENT_BINARY_DIR}) SET(PICOTLS_OPENSSL_FILES From d9a40a1b1fcebd168a5d735263ddee3e682f1dc8 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Wed, 18 Nov 2020 12:34:27 -0800 Subject: [PATCH 024/361] qlog: support the max stream frame type --- misc/qlog-adapter.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index b6d35506d..5051756cc 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -87,6 +87,17 @@ def handle_max_data_send(event): "maximum": event["limit"] } +def handle_max_streams_send(event): + if event["is-unidirectional"]: + stream_type = "unidirectional" + else: + stream_type = "bidirectional" + return { + "frame_type": "max_streams", + "stream_type": stream_type, + "maximum": event["limit"] + } + def handle_max_stream_data_receive(event): return { "frame_type": "max_stream_data", @@ -185,6 +196,7 @@ def handle_transport_close_send(event): "handshake-done-send": handle_handshake_done_send, "max-data-receive": handle_max_data_receive, "max-data-send": handle_max_data_send, + "max-streams-send": handle_max_streams_send, "max-stream-data-receive": handle_max_stream_data_receive, "max-stream-data-send": handle_max_stream_data_send, "new-connection-id-receive": handle_new_connection_id_receive, From 8389f3e9c1ad182e76d4114198f699485b9db27f Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Wed, 18 Nov 2020 14:32:09 -0800 Subject: [PATCH 025/361] qlog: support the streams_blocked frame type --- misc/qlog-adapter.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 5051756cc..fef30b764 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -154,6 +154,28 @@ def handle_quictrace_recv_ack(event): "frame_type": "ack", } +def handle_streams_blocked_receive(event): + if event["is-unidirectional"]: + stream_type = unidirectional + else: + stream_type = bidirectional + return { + "frame_type": "streams_blocked", + "stream_type": stream_type, + "limit": event["limit"] + } + +def handle_streams_blocked_send(event): + if event["is-unidirectional"]: + stream_type = unidirectional + else: + stream_type = bidirectional + return { + "frame_type": "streams_blocked", + "stream_type": stream_type, + "limit": event["limit"] + } + def handle_stream_on_send_stop(event): return { "frame_type": "stop_sending", @@ -205,6 +227,8 @@ def handle_transport_close_send(event): "new-token-send": handle_new_token_send, "ping-receive": handle_ping_receive, "quictrace-recv-ack": handle_quictrace_recv_ack, + "streams-blocked-receive": handle_streams_blocked_receive, + "streams-blocked-send": handle_streams_blocked_send, "stream-on-send-stop": handle_stream_on_send_stop, "stream-receive": handle_stream_receive, "transport-close-receive": handle_transport_close_receive, From b572dd1c0f68a162db9cdbcaf7fde795d772eaed Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Wed, 18 Nov 2020 16:35:14 -0800 Subject: [PATCH 026/361] qlog: support the data_blocked frame type --- misc/qlog-adapter.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index fef30b764..b3897836a 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -65,6 +65,16 @@ def handle_ack_send(event): "frame_type": "ack", } +def handle_data_blocked_receive(event): + return { + "frame_type": "data_blocked" + } + +def handle_data_blocked_send(event): + return { + "frame_type": "data_blocked" + } + def handle_handshake_done_receive(event): return { "frame_type": "handshake_done", @@ -214,6 +224,8 @@ def handle_transport_close_send(event): FRAME_EVENT_HANDLERS = { "ack-send": handle_ack_send, + "data-blocked-receive": handle_data_blocked_receive, + "data-blocked-send": handle_data_blocked_send, "handshake-done-receive": handle_handshake_done_receive, "handshake-done-send": handle_handshake_done_send, "max-data-receive": handle_max_data_receive, From a654b622309d45b11e0bb7e0beddd5ca21aec709 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Wed, 18 Nov 2020 16:44:50 -0800 Subject: [PATCH 027/361] qlog: support the stream_data_blocked frame type --- misc/qlog-adapter.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index b3897836a..8020b0167 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -186,6 +186,20 @@ def handle_streams_blocked_send(event): "limit": event["limit"] } +def handle_stream_data_blocked_receive(event): + return { + "frame_type": "stream_data_blocked", + "stream_id": event["stream-id"], + "limit": event["limit"] + } + +def handle_stream_data_blocked_send(event): + return { + "frame_type": "stream_data_blocked", + "stream_id": event["stream-id"], + "limit": event["limit"] + } + def handle_stream_on_send_stop(event): return { "frame_type": "stop_sending", @@ -241,6 +255,8 @@ def handle_transport_close_send(event): "quictrace-recv-ack": handle_quictrace_recv_ack, "streams-blocked-receive": handle_streams_blocked_receive, "streams-blocked-send": handle_streams_blocked_send, + "stream-data-blocked-receive": handle_stream_data_blocked_receive, + "stream-data-blocked-send": handle_stream_data_blocked_send, "stream-on-send-stop": handle_stream_on_send_stop, "stream-receive": handle_stream_receive, "transport-close-receive": handle_transport_close_receive, From d6da42b803eeb3738c42c961000530e20fb9194b Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Wed, 18 Nov 2020 16:53:35 -0800 Subject: [PATCH 028/361] qlog: support the retire_connection_id frame type --- misc/qlog-adapter.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 8020b0167..0d0d51e0d 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -164,6 +164,18 @@ def handle_quictrace_recv_ack(event): "frame_type": "ack", } +def handle_retire_connection_id_receive(event): + return { + "frame_type": "retire_connection_id", + "sequence_number": event["sequence"] + } + +def handle_retire_connection_id_send(event): + return { + "frame_type": "retire_connection_id", + "sequence_number": event["sequence"] + } + def handle_streams_blocked_receive(event): if event["is-unidirectional"]: stream_type = unidirectional @@ -253,6 +265,8 @@ def handle_transport_close_send(event): "new-token-send": handle_new_token_send, "ping-receive": handle_ping_receive, "quictrace-recv-ack": handle_quictrace_recv_ack, + "retire-connection-id-receive": handle_retire_connection_id_receive, + "retire-connection-id-send": handle_retire_connection_id_send, "streams-blocked-receive": handle_streams_blocked_receive, "streams-blocked-send": handle_streams_blocked_send, "stream-data-blocked-receive": handle_stream_data_blocked_receive, From 04e8bae5320e2031521ddfe572ae90775ac01306 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Wed, 18 Nov 2020 17:06:24 -0800 Subject: [PATCH 029/361] qlog: support the reset_stream frame type --- misc/qlog-adapter.py | 52 +++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 0d0d51e0d..04c209f6a 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -176,6 +176,33 @@ def handle_retire_connection_id_send(event): "sequence_number": event["sequence"] } +def handle_stream_data_blocked_receive(event): + return { + "frame_type": "stream_data_blocked", + "stream_id": event["stream-id"], + "limit": event["limit"] + } + +def handle_stream_data_blocked_send(event): + return { + "frame_type": "stream_data_blocked", + "stream_id": event["stream-id"], + "limit": event["limit"] + } + +def handle_stream_on_receive_reset(event): + return { + "frame_type": "reset_stream", + "stream_id": event["stream-id"], + "error_code": event["err"] + } + +def handle_stream_on_send_stop(event): + return { + "frame_type": "stop_sending", + "stream_id": event["stream-id"] + } + def handle_streams_blocked_receive(event): if event["is-unidirectional"]: stream_type = unidirectional @@ -198,26 +225,6 @@ def handle_streams_blocked_send(event): "limit": event["limit"] } -def handle_stream_data_blocked_receive(event): - return { - "frame_type": "stream_data_blocked", - "stream_id": event["stream-id"], - "limit": event["limit"] - } - -def handle_stream_data_blocked_send(event): - return { - "frame_type": "stream_data_blocked", - "stream_id": event["stream-id"], - "limit": event["limit"] - } - -def handle_stream_on_send_stop(event): - return { - "frame_type": "stop_sending", - "stream_id": event["stream-id"] - } - def handle_stream_receive(event): label = "stream" if event["stream-id"] >= 0 else "crypto" return { @@ -267,10 +274,11 @@ def handle_transport_close_send(event): "quictrace-recv-ack": handle_quictrace_recv_ack, "retire-connection-id-receive": handle_retire_connection_id_receive, "retire-connection-id-send": handle_retire_connection_id_send, - "streams-blocked-receive": handle_streams_blocked_receive, - "streams-blocked-send": handle_streams_blocked_send, "stream-data-blocked-receive": handle_stream_data_blocked_receive, "stream-data-blocked-send": handle_stream_data_blocked_send, + "stream-on-receive-reset": handle_stream_on_receive_reset, + "streams-blocked-receive": handle_streams_blocked_receive, + "streams-blocked-send": handle_streams_blocked_send, "stream-on-send-stop": handle_stream_on_send_stop, "stream-receive": handle_stream_receive, "transport-close-receive": handle_transport_close_receive, From a6ec9c982bf103add14e3ff58ab243524fbdfb53 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Wed, 18 Nov 2020 17:15:04 -0800 Subject: [PATCH 030/361] qlog: capture sent stream frames --- misc/qlog-adapter.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 04c209f6a..155f1f912 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -197,6 +197,24 @@ def handle_stream_on_receive_reset(event): "error_code": event["err"] } +def handle_stream_receive(event): + label = "stream" if event["stream-id"] >= 0 else "crypto" + return { + "frame_type": label, + "stream_id": event["stream-id"], + "length": event["len"], + "offset": event["off"] + } + +def handle_stream_send(event): + label = "stream" if event["stream-id"] >= 0 else "crypto" + return { + "frame_type": label, + "stream_id": event["stream-id"], + "length": event["len"], + "offset": event["off"] + } + def handle_stream_on_send_stop(event): return { "frame_type": "stop_sending", @@ -225,15 +243,6 @@ def handle_streams_blocked_send(event): "limit": event["limit"] } -def handle_stream_receive(event): - label = "stream" if event["stream-id"] >= 0 else "crypto" - return { - "frame_type": label, - "stream_id": event["stream-id"], - "length": event["len"], - "offset": event["off"] - } - def handle_transport_close_receive(event): return { "frame_type": "connection_close", @@ -277,6 +286,7 @@ def handle_transport_close_send(event): "stream-data-blocked-receive": handle_stream_data_blocked_receive, "stream-data-blocked-send": handle_stream_data_blocked_send, "stream-on-receive-reset": handle_stream_on_receive_reset, + "stream-send": handle_stream_send, "streams-blocked-receive": handle_streams_blocked_receive, "streams-blocked-send": handle_streams_blocked_send, "stream-on-send-stop": handle_stream_on_send_stop, From c1ccee6a5ec8c88f81c2093570dfcc39b0d87522 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Wed, 18 Nov 2020 21:27:08 -0800 Subject: [PATCH 031/361] t/e2e: reflect the probe definition change "packet-commit" and "quictrace-sent" probes were merged into the "packet-sent" probe. This commit reflects this change to the e2e test. --- parselog.py | 2 +- t/e2e.t | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/parselog.py b/parselog.py index d88fe9feb..a3c4a8a0c 100644 --- a/parselog.py +++ b/parselog.py @@ -18,7 +18,7 @@ def gen_trace(f, cid, sent_trace, ack_trace): if event["type"] == "" or event["conn"] != cid: continue # sent packet - if event["type"] == "packet-commit": + if event["type"] == "packet-sent": if conn_start == 0: conn_start = event["time"] outstr = str(event["time"] - conn_start) + " " + \ str(event["pn"]) + " " + \ diff --git a/t/e2e.t b/t/e2e.t index 74f3ba070..86ce88ac4 100755 --- a/t/e2e.t +++ b/t/e2e.t @@ -41,7 +41,7 @@ subtest "hello" => sub { my $events = slurp_file("$tempdir/events"); complex $events, sub { $_ =~ /"type":"transport-close-send",.*?"type":"([^\"]*)",.*?"type":"([^\"]*)",.*?"type":"([^\"]*)",.*?"type":"([^\"]*)"/s - and $1 eq 'packet-commit' and $2 eq 'quictrace-sent' and $3 eq 'send' and $4 eq 'free'; + and $1 eq 'packet-sent' and $2 eq 'send' and $3 eq 'free'; }; }; # check if the client receives extra connection IDs @@ -122,7 +122,7 @@ subtest "0-rtt" => sub { ok -e "$tempdir/session", "session saved"; system "$cli -s $tempdir/session -e $tempdir/events 127.0.0.1 $port > /dev/null 2>&1"; my $events = slurp_file("$tempdir/events"); - like $events, qr/"type":"stream-send".*"stream-id":0,(.|\n)*"type":"packet-commit".*"pn":1,/m, "stream 0 on pn 1"; + like $events, qr/"type":"stream-send".*"stream-id":0,(.|\n)*"type":"packet-sent".*"pn":1,/m, "stream 0 on pn 1"; like $events, qr/"type":"cc-ack-received".*"largest-acked":1,/m, "pn 1 acked"; }; @@ -175,7 +175,7 @@ subtest "stateless-reset" => sub { # check that the stateless reset is logged my $events = slurp_file("$tempdir/events"); like $events, qr/"type":"stateless-reset-receive",/m, 'got stateless reset'; - unlike +($events =~ /"type":"stateless-reset-receive",.*?\n/ and $'), qr/"type":"packet-commit",/m, 'nothing sent after receiving stateless reset'; + unlike +($events =~ /"type":"stateless-reset-receive",.*?\n/ and $'), qr/"type":"packet-sent",/m, 'nothing sent after receiving stateless reset'; }; subtest "no-compatible-version" => sub { @@ -204,7 +204,7 @@ subtest "no-compatible-version" => sub { # check the trace my $events = slurp_file("$tempdir/events"); like $events, qr/"type":"receive",/m, "one receive event"; - unlike +($events =~ /"type":"receive",.*?\n/ and $'), qr/"type":"packet-commit",/m, "nothing sent after receiving VN"; + unlike +($events =~ /"type":"receive",.*?\n/ and $'), qr/"type":"packet-sent",/m, "nothing sent after receiving VN"; }; subtest "idle-timeout" => sub { From bcb3cae86295515daaf6d3fac6586b30972cf789 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Wed, 18 Nov 2020 21:55:24 -0800 Subject: [PATCH 032/361] qlog: rename crypto_decrypt_failure to packet_dropped --- lib/quicly.c | 2 +- quicly-probes.d | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 03e3aff06..b6d1b494a 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5583,7 +5583,7 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka if ((ret = decrypt_packet(header_protection, aead.cb, aead.ctx, &(*space)->next_expected_packet_number, packet, &pn, &payload)) != 0) { ++conn->super.stats.num_packets.decryption_failed; - QUICLY_PROBE(CRYPTO_DECRYPT_FAILURE, conn, conn->stash.now, pn); + QUICLY_PROBE(PACKET_DROPPED, conn, conn->stash.now, pn); goto Exit; } diff --git a/quicly-probes.d b/quicly-probes.d index 85936f4c6..dfcda209b 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -35,7 +35,6 @@ provider quicly { probe idle_timeout(struct st_quicly_conn_t *conn, int64_t at); probe stateless_reset_receive(struct st_quicly_conn_t *conn, int64_t at); - probe crypto_decrypt_failure(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); probe crypto_handshake(struct st_quicly_conn_t *conn, int64_t at, int ret); probe crypto_update_secret(struct st_quicly_conn_t *conn, int64_t at, int is_enc, uint8_t epoch, const char *label, const char *secret); probe crypto_send_key_update(struct st_quicly_conn_t *conn, int64_t at, uint64_t phase, const char *secret); @@ -48,6 +47,7 @@ provider quicly { probe packet_prepare(struct st_quicly_conn_t *conn, int64_t at, uint8_t first_octet, const char *dcid); probe packet_acked(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, int is_late_ack); probe packet_lost(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); + probe packet_dropped(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); probe pto(struct st_quicly_conn_t *conn, int64_t at, size_t inflight, uint32_t cwnd, int8_t pto_count); probe cc_ack_received(struct st_quicly_conn_t *conn, int64_t at, uint64_t largest_acked, size_t bytes_acked, uint32_t cwnd, From 018fd68f795640fc0a8d186648f28eefacc5edf6 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Wed, 18 Nov 2020 22:00:46 -0800 Subject: [PATCH 033/361] qlog: emit why the packet was dropped --- lib/quicly.c | 2 +- quicly-probes.d | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index b6d1b494a..7c94de591 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5583,7 +5583,7 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka if ((ret = decrypt_packet(header_protection, aead.cb, aead.ctx, &(*space)->next_expected_packet_number, packet, &pn, &payload)) != 0) { ++conn->super.stats.num_packets.decryption_failed; - QUICLY_PROBE(PACKET_DROPPED, conn, conn->stash.now, pn); + QUICLY_PROBE(PACKET_DROPPED, conn, conn->stash.now, "payload_decrypt_error", pn); goto Exit; } diff --git a/quicly-probes.d b/quicly-probes.d index dfcda209b..a7a2d165c 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -47,7 +47,7 @@ provider quicly { probe packet_prepare(struct st_quicly_conn_t *conn, int64_t at, uint8_t first_octet, const char *dcid); probe packet_acked(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, int is_late_ack); probe packet_lost(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); - probe packet_dropped(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); + probe packet_dropped(struct st_quicly_conn_t *conn, int64_t at, const char *reason_phrase, uint64_t pn); probe pto(struct st_quicly_conn_t *conn, int64_t at, size_t inflight, uint32_t cwnd, int8_t pto_count); probe cc_ack_received(struct st_quicly_conn_t *conn, int64_t at, uint64_t largest_acked, size_t bytes_acked, uint32_t cwnd, From 03d560d4e39c94284814271bd18ef7a70d34c201 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Wed, 18 Nov 2020 22:25:08 -0800 Subject: [PATCH 034/361] qlog: fix an incorrect label assignment RHS should be a string literal, not a variable name. --- misc/qlog-adapter.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 155f1f912..8184059fd 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -223,9 +223,9 @@ def handle_stream_on_send_stop(event): def handle_streams_blocked_receive(event): if event["is-unidirectional"]: - stream_type = unidirectional + stream_type = "unidirectional" else: - stream_type = bidirectional + stream_type = "bidirectional" return { "frame_type": "streams_blocked", "stream_type": stream_type, @@ -234,9 +234,9 @@ def handle_streams_blocked_receive(event): def handle_streams_blocked_send(event): if event["is-unidirectional"]: - stream_type = unidirectional + stream_type = "unidirectional" else: - stream_type = bidirectional + stream_type = "bidirectional" return { "frame_type": "streams_blocked", "stream_type": stream_type, From 3d30865486a252d290767094433c702b6d341158 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Thu, 19 Nov 2020 17:49:41 -0800 Subject: [PATCH 035/361] qlog: rename packet_dropped to packet_decryption_failure --- lib/quicly.c | 2 +- quicly-probes.d | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 7c94de591..87b83d3c9 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5583,7 +5583,7 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka if ((ret = decrypt_packet(header_protection, aead.cb, aead.ctx, &(*space)->next_expected_packet_number, packet, &pn, &payload)) != 0) { ++conn->super.stats.num_packets.decryption_failed; - QUICLY_PROBE(PACKET_DROPPED, conn, conn->stash.now, "payload_decrypt_error", pn); + QUICLY_PROBE(PACKET_DECRYPTION_FAILURE, conn, conn->stash.now, pn); goto Exit; } diff --git a/quicly-probes.d b/quicly-probes.d index a7a2d165c..7b449e97d 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -47,7 +47,7 @@ provider quicly { probe packet_prepare(struct st_quicly_conn_t *conn, int64_t at, uint8_t first_octet, const char *dcid); probe packet_acked(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, int is_late_ack); probe packet_lost(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); - probe packet_dropped(struct st_quicly_conn_t *conn, int64_t at, const char *reason_phrase, uint64_t pn); + probe packet_decryption_failure(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); probe pto(struct st_quicly_conn_t *conn, int64_t at, size_t inflight, uint32_t cwnd, int8_t pto_count); probe cc_ack_received(struct st_quicly_conn_t *conn, int64_t at, uint64_t largest_acked, size_t bytes_acked, uint32_t cwnd, From 84d322d4893333619c5d0423029bfa8c0668cdab Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Thu, 19 Nov 2020 22:07:00 -0800 Subject: [PATCH 036/361] qlog: rename packet_decryption_failure to packet_decryption_failed --- lib/quicly.c | 2 +- quicly-probes.d | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 87b83d3c9..6cc1effaf 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5583,7 +5583,7 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka if ((ret = decrypt_packet(header_protection, aead.cb, aead.ctx, &(*space)->next_expected_packet_number, packet, &pn, &payload)) != 0) { ++conn->super.stats.num_packets.decryption_failed; - QUICLY_PROBE(PACKET_DECRYPTION_FAILURE, conn, conn->stash.now, pn); + QUICLY_PROBE(PACKET_DECRYPTION_FAILED, conn, conn->stash.now, pn); goto Exit; } diff --git a/quicly-probes.d b/quicly-probes.d index 7b449e97d..00409be6b 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -47,7 +47,7 @@ provider quicly { probe packet_prepare(struct st_quicly_conn_t *conn, int64_t at, uint8_t first_octet, const char *dcid); probe packet_acked(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, int is_late_ack); probe packet_lost(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); - probe packet_decryption_failure(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); + probe packet_decryption_failed(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); probe pto(struct st_quicly_conn_t *conn, int64_t at, size_t inflight, uint32_t cwnd, int8_t pto_count); probe cc_ack_received(struct st_quicly_conn_t *conn, int64_t at, uint64_t largest_acked, size_t bytes_acked, uint32_t cwnd, From 617dd09b7644609ffd163c5d273340c2d4353d52 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Wed, 18 Nov 2020 21:07:59 +0000 Subject: [PATCH 037/361] Signal decryption failure from quicly_accept Currently there is no explicit way for an application to know if decryption of Initial packet failed in quicly_accept. This commit defines a new error code QUICLY_ERROR_DECRYPTION_FAILED and return it from quicly_accept upon decryption failure. --- include/quicly/constants.h | 1 + lib/quicly.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/quicly/constants.h b/include/quicly/constants.h index b6cf86aeb..03a35c41b 100644 --- a/include/quicly/constants.h +++ b/include/quicly/constants.h @@ -106,6 +106,7 @@ extern "C" { #define QUICLY_ERROR_IS_CLOSING 0xff06 /* indicates that the connection has already entered closing state */ #define QUICLY_ERROR_STATE_EXHAUSTION 0xff07 #define QUICLY_ERROR_INVALID_INITIAL_VERSION 0xff08 +#define QUICLY_ERROR_DECRYPTION_FAILED 0xff09 typedef int64_t quicly_stream_id_t; diff --git a/lib/quicly.c b/lib/quicly.c index 017762b5a..2453b29fa 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5481,8 +5481,10 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * goto Exit; next_expected_pn = 0; /* is this correct? do we need to take care of underflow? */ if ((ret = decrypt_packet(ingress_cipher.header_protection, aead_decrypt_fixed_key, ingress_cipher.aead, &next_expected_pn, - packet, &pn, &payload)) != 0) + packet, &pn, &payload)) != 0) { + ret = QUICLY_ERROR_DECRYPTION_FAILED; goto Exit; + } /* create connection */ if ((*conn = create_connection(ctx, packet->version, NULL, src_addr, dest_addr, &packet->cid.src, new_cid, handshake_properties, From 4de33b44f19c72e90bbc63f1194f3e696d888b99 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Tue, 1 Dec 2020 20:43:45 +0000 Subject: [PATCH 038/361] Add a test case for decryption failure in accept --- t/test.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/t/test.c b/t/test.c index 6b8712807..1d4fdaa55 100644 --- a/t/test.c +++ b/t/test.c @@ -509,6 +509,66 @@ static void test_cid(void) subtest("retire cid", test_retire_cid); } +/** + * test if quicly_accept correctly rejects a non-decryptable Initial packet with QUICLY_ERROR_DECRYPTION_FAILED + */ +static void test_nondecryptable_initial(void) +{ +#define PACKET_LEN 1280 +#define HEADER_LEN 18 +#define LEN_HIGH (((PACKET_LEN - HEADER_LEN) & 0xff00) >> 8) +#define LEN_LOW ((PACKET_LEN - HEADER_LEN) & 0xff) + uint8_t header[HEADER_LEN] = { + /* first byte for Initial: 0b1100???? */ + 0xc5, + /* version (29) */ + 0xff, + 0x00, + 0x00, + 0x1d, + /* DCID len */ + 0x08, + /* DCID */ + 0x83, + 0x94, + 0xc8, + 0xf0, + 0x3e, + 0x51, + 0x57, + 0x08, + /* SCID len */ + 0x00, + /* SCID does not appear */ + /* token length */ + 0x00, + /* token does not appear */ + /* length */ + (0x40 | LEN_HIGH), + LEN_LOW, + }; + quicly_conn_t *server; + uint8_t packetbuf[PACKET_LEN]; + struct iovec packet = {.iov_base = packetbuf, .iov_len = sizeof(packetbuf)}; + size_t num_decoded; + quicly_decoded_packet_t decoded; + int ret; + + /* create an Initial packet, with its payload all set to zero */ + memcpy(packetbuf, header, sizeof(header)); + memset(packetbuf + sizeof(header), 0, sizeof(packetbuf) - sizeof(header)); + num_decoded = decode_packets(&decoded, &packet, 1); + ok(num_decoded == 1); + + /* decryption should fail */ + ret = quicly_accept(&server, &quic_ctx, NULL, &fake_address.sa, &decoded, NULL, new_master_id(), NULL); + ok(ret == QUICLY_ERROR_DECRYPTION_FAILED); +#undef PACKET_LEN +#undef HEADER_LEN +#undef LEN_HIGH +#undef LEN_LOW +} + int main(int argc, char **argv) { static ptls_iovec_t cert; @@ -580,6 +640,7 @@ int main(int argc, char **argv) subtest("simple", test_simple); subtest("stream-concurrency", test_stream_concurrency); subtest("lossy", test_lossy); + subtest("test-nondecryptable-initial", test_nondecryptable_initial); return done_testing(); } From ab0d7aabf50ddc3648c5870bfdcc3b7c560bc318 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Tue, 1 Dec 2020 20:45:11 +0000 Subject: [PATCH 039/361] test: fix typo in a function name --- t/simple.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/simple.c b/t/simple.c index b3b5d2d96..6f69fd0a8 100644 --- a/t/simple.c +++ b/t/simple.c @@ -460,8 +460,8 @@ static void test_reset_during_loss(void) static uint16_t test_close_error_code; -static void test_closeed_by_remote(quicly_closed_by_remote_t *self, quicly_conn_t *conn, int err, uint64_t frame_type, - const char *reason, size_t reason_len) +static void test_closed_by_remote(quicly_closed_by_remote_t *self, quicly_conn_t *conn, int err, uint64_t frame_type, + const char *reason, size_t reason_len) { ok(QUICLY_ERROR_IS_QUIC_APPLICATION(err)); test_close_error_code = QUICLY_ERROR_GET_ERROR_CODE(err); @@ -472,7 +472,7 @@ static void test_closeed_by_remote(quicly_closed_by_remote_t *self, quicly_conn_ static void test_close(void) { - quicly_closed_by_remote_t closed_by_remote = {test_closeed_by_remote}, *orig_closed_by_remote = quic_ctx.closed_by_remote; + quicly_closed_by_remote_t closed_by_remote = {test_closed_by_remote}, *orig_closed_by_remote = quic_ctx.closed_by_remote; quicly_address_t dest, src; struct iovec datagram; uint8_t datagram_buf[quic_ctx.transport_params.max_udp_payload_size]; From 86484036f9774159ff4763d6da5895ee3fa9db8c Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Tue, 1 Dec 2020 20:45:45 +0000 Subject: [PATCH 040/361] test: fix typo in a comment --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 2453b29fa..406466ae1 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -592,7 +592,7 @@ size_t quicly_decode_packet(quicly_context_t *ctx, quicly_decoded_packet_t *pack packet->token = ptls_iovec_init(NULL, 0); packet->decrypted.pn = UINT64_MAX; - /* move the cursor to the sencond byte */ + /* move the cursor to the second byte */ src += *off + 1; if (QUICLY_PACKET_IS_LONG_HEADER(packet->octets.base[0])) { From db2e16709de18ff8df53bd3d167ed1bc51fd7814 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Tue, 1 Dec 2020 13:56:02 -0800 Subject: [PATCH 041/361] qlog: fix incorrect incoming ack frame interpretation --- misc/qlog-adapter.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 8184059fd..7a24e557f 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -27,10 +27,21 @@ def handle_packet_received(events, idx): frames = [] + acked = [] for i in range(idx+1, len(events)): ev = events[i] if ev["type"] == "packet-prepare" or ev["type"] in QLOG_EVENT_HANDLERS: break + + # An ACK frame can't be re-composed in an iteration. Continue buffering + # the ACK blocks until all the blocks are processed. + if ev["type"] == "quictrace-recv-ack": + acked.append([ev["ack-block-begin"],ev["ack-block-end"]]) + continue + elif ev["type"] == "quictrace-recv-ack-delay": + frames.append(render_ack_frame(acked)) + continue + handler = FRAME_EVENT_HANDLERS.get(ev["type"]) if handler: frames.append(handler(ev)) @@ -159,11 +170,6 @@ def handle_ping_receive(event): "frame_type": "ping", } -def handle_quictrace_recv_ack(event): - return { - "frame_type": "ack", - } - def handle_retire_connection_id_receive(event): return { "frame_type": "retire_connection_id", @@ -259,6 +265,12 @@ def handle_transport_close_send(event): "reason": event["reason-phrase"] } +def render_ack_frame(ranges): + return { + "frame_type": "ack", + "acked_ranges": ranges + } + QLOG_EVENT_HANDLERS = { "packet-received": handle_packet_received, "packet-sent": handle_packet_sent @@ -280,7 +292,6 @@ def handle_transport_close_send(event): "new-token-receive": handle_new_token_receive, "new-token-send": handle_new_token_send, "ping-receive": handle_ping_receive, - "quictrace-recv-ack": handle_quictrace_recv_ack, "retire-connection-id-receive": handle_retire_connection_id_receive, "retire-connection-id-send": handle_retire_connection_id_send, "stream-data-blocked-receive": handle_stream_data_blocked_receive, From b348ea01d2e3cadd02ac6898ff80844219b13e09 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Tue, 1 Dec 2020 16:30:42 -0800 Subject: [PATCH 042/361] qlog: render the largest acked packet number on ack_send --- misc/qlog-adapter.py | 1 + 1 file changed, 1 insertion(+) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 7a24e557f..556c8fa6e 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -74,6 +74,7 @@ def handle_packet_sent(events, idx): def handle_ack_send(event): return { "frame_type": "ack", + "acked_ranges": [[event["largest-acked"]]] } def handle_data_blocked_receive(event): From 5715ed9b6ab40f97f43e6d002b9e653da0c18dd9 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Tue, 1 Dec 2020 16:42:26 -0800 Subject: [PATCH 043/361] dtrace: rename quictrace_recv_ack to ack_block_recv --- lib/quicly.c | 2 +- quicly-probes.d | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 017762b5a..350844002 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -4691,7 +4691,7 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload /* Ack blocks are organized in the ACK frame and consequently in the ack_block_lengths array from the largest acked down. * Processing acks in packet number order requires processing the ack blocks in reverse order. */ uint64_t pn_block_max = pn_acked + frame.ack_block_lengths[gap_index] - 1; - QUICLY_PROBE(QUICTRACE_RECV_ACK, conn, conn->stash.now, pn_acked, pn_block_max); + QUICLY_PROBE(ACK_BLOCK_RECV, conn, conn->stash.now, pn_acked, pn_block_max); while (quicly_sentmap_get(&iter)->packet_number < pn_acked) quicly_sentmap_skip(&iter); do { diff --git a/quicly-probes.d b/quicly-probes.d index 13aac69d6..1d9c1d026 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -54,6 +54,7 @@ provider quicly { size_t inflight); probe cc_congestion(struct st_quicly_conn_t *conn, int64_t at, uint64_t max_lost_pn, size_t inflight, uint32_t cwnd); + probe ack_block_recv(struct st_quicly_conn_t *conn, int64_t at, uint64_t ack_block_begin, uint64_t ack_block_end); probe ack_send(struct st_quicly_conn_t *conn, int64_t at, uint64_t largest_acked, uint64_t ack_delay); probe ping_send(struct st_quicly_conn_t *conn, int64_t at); @@ -112,7 +113,6 @@ provider quicly { probe quictrace_send_stream(struct st_quicly_conn_t *conn, int64_t at, struct st_quicly_stream_t *stream, uint64_t off, size_t len, int fin); probe quictrace_recv_stream(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t off, size_t len, int fin); - probe quictrace_recv_ack(struct st_quicly_conn_t *conn, int64_t at, uint64_t ack_block_begin, uint64_t ack_block_end); probe quictrace_recv_ack_delay(struct st_quicly_conn_t *conn, int64_t at, int64_t ack_delay); probe quictrace_lost(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); probe quictrace_cc_ack(struct st_quicly_conn_t *conn, int64_t at, struct quicly_rtt_t *rtt, uint32_t cwnd, size_t inflight); From 2dcef616b522903ecc2522664927bea89f9f9f13 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Tue, 1 Dec 2020 17:25:40 -0800 Subject: [PATCH 044/361] qlog: remove redundant ack rendering code --- misc/qlog-adapter.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 556c8fa6e..39aa78e58 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -72,10 +72,7 @@ def handle_packet_sent(events, idx): }] def handle_ack_send(event): - return { - "frame_type": "ack", - "acked_ranges": [[event["largest-acked"]]] - } + return render_ack_frame([[event["largest-acked"]]]) def handle_data_blocked_receive(event): return { From 79e40d8706d8b4e55a0131fc7cd04857824f258f Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Tue, 1 Dec 2020 17:28:19 -0800 Subject: [PATCH 045/361] dtrace: use received over recv --- lib/quicly.c | 2 +- quicly-probes.d | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 350844002..f4bb8f43e 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -4691,7 +4691,7 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload /* Ack blocks are organized in the ACK frame and consequently in the ack_block_lengths array from the largest acked down. * Processing acks in packet number order requires processing the ack blocks in reverse order. */ uint64_t pn_block_max = pn_acked + frame.ack_block_lengths[gap_index] - 1; - QUICLY_PROBE(ACK_BLOCK_RECV, conn, conn->stash.now, pn_acked, pn_block_max); + QUICLY_PROBE(ACK_BLOCK_RECEIVED, conn, conn->stash.now, pn_acked, pn_block_max); while (quicly_sentmap_get(&iter)->packet_number < pn_acked) quicly_sentmap_skip(&iter); do { diff --git a/quicly-probes.d b/quicly-probes.d index 1d9c1d026..fd5a48c29 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -54,7 +54,7 @@ provider quicly { size_t inflight); probe cc_congestion(struct st_quicly_conn_t *conn, int64_t at, uint64_t max_lost_pn, size_t inflight, uint32_t cwnd); - probe ack_block_recv(struct st_quicly_conn_t *conn, int64_t at, uint64_t ack_block_begin, uint64_t ack_block_end); + probe ack_block_received(struct st_quicly_conn_t *conn, int64_t at, uint64_t ack_block_begin, uint64_t ack_block_end); probe ack_send(struct st_quicly_conn_t *conn, int64_t at, uint64_t largest_acked, uint64_t ack_delay); probe ping_send(struct st_quicly_conn_t *conn, int64_t at); From 957b7fd7cc88e02431237361e1b1c3aad57548dc Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Tue, 1 Dec 2020 17:39:07 -0800 Subject: [PATCH 046/361] qlog: reflect the probe rename to the adapter --- misc/qlog-adapter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 39aa78e58..cfca5d0f2 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -35,7 +35,7 @@ def handle_packet_received(events, idx): # An ACK frame can't be re-composed in an iteration. Continue buffering # the ACK blocks until all the blocks are processed. - if ev["type"] == "quictrace-recv-ack": + if ev["type"] == "ack-block-received": acked.append([ev["ack-block-begin"],ev["ack-block-end"]]) continue elif ev["type"] == "quictrace-recv-ack-delay": From d8ed2fa9e5ad64e96ff136c4c7f9076dd4d6cda0 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Tue, 1 Dec 2020 22:33:14 -0800 Subject: [PATCH 047/361] dtrace: rename quictrace_recv_ack_delay to ack_delay_received --- lib/quicly.c | 2 +- quicly-probes.d | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index f4bb8f43e..ec94460f4 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -4746,7 +4746,7 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload if ((ret = on_ack_stream_ack_cached(conn)) != 0) return ret; - QUICLY_PROBE(QUICTRACE_RECV_ACK_DELAY, conn, conn->stash.now, frame.ack_delay); + QUICLY_PROBE(ACK_DELAY_RECEIVED, conn, conn->stash.now, frame.ack_delay); /* Update loss detection engine on ack. The function uses ack_delay only when the largest_newly_acked is also the largest acked * so far. So, it does not matter if the ack_delay being passed in does not apply to the largest_newly_acked. */ diff --git a/quicly-probes.d b/quicly-probes.d index fd5a48c29..b2a9f22eb 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -55,6 +55,7 @@ provider quicly { probe cc_congestion(struct st_quicly_conn_t *conn, int64_t at, uint64_t max_lost_pn, size_t inflight, uint32_t cwnd); probe ack_block_received(struct st_quicly_conn_t *conn, int64_t at, uint64_t ack_block_begin, uint64_t ack_block_end); + probe ack_delay_received(struct st_quicly_conn_t *conn, int64_t at, int64_t ack_delay); probe ack_send(struct st_quicly_conn_t *conn, int64_t at, uint64_t largest_acked, uint64_t ack_delay); probe ping_send(struct st_quicly_conn_t *conn, int64_t at); @@ -113,7 +114,6 @@ provider quicly { probe quictrace_send_stream(struct st_quicly_conn_t *conn, int64_t at, struct st_quicly_stream_t *stream, uint64_t off, size_t len, int fin); probe quictrace_recv_stream(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t off, size_t len, int fin); - probe quictrace_recv_ack_delay(struct st_quicly_conn_t *conn, int64_t at, int64_t ack_delay); probe quictrace_lost(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); probe quictrace_cc_ack(struct st_quicly_conn_t *conn, int64_t at, struct quicly_rtt_t *rtt, uint32_t cwnd, size_t inflight); probe quictrace_cc_lost(struct st_quicly_conn_t *conn, int64_t at, struct quicly_rtt_t *rtt, uint32_t cwnd, size_t inflight); From 632e35c7b2801564cb906b6ed3540f21914460d5 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Tue, 1 Dec 2020 22:41:09 -0800 Subject: [PATCH 048/361] qlog: reflect the rename of the ack-delay probe --- misc/qlog-adapter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index cfca5d0f2..048430b93 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -38,7 +38,7 @@ def handle_packet_received(events, idx): if ev["type"] == "ack-block-received": acked.append([ev["ack-block-begin"],ev["ack-block-end"]]) continue - elif ev["type"] == "quictrace-recv-ack-delay": + elif ev["type"] == "ack-delay-received": frames.append(render_ack_frame(acked)) continue From 7f510e2256f81a8f584bfc01f823150363503788 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Thu, 3 Dec 2020 13:28:43 -0800 Subject: [PATCH 049/361] dtrace: rename all "limit" fields to "maximum" --- misc/qlog-adapter.py | 18 +++++++++--------- quicly-probes.d | 20 ++++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 048430b93..1c6a4c9e6 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -97,13 +97,13 @@ def handle_handshake_done_send(event): def handle_max_data_receive(event): return { "frame_type": "max_data", - "maximum": event["limit"] + "maximum": event["maximum"] } def handle_max_data_send(event): return { "frame_type": "max_data", - "maximum": event["limit"] + "maximum": event["maximum"] } def handle_max_streams_send(event): @@ -114,21 +114,21 @@ def handle_max_streams_send(event): return { "frame_type": "max_streams", "stream_type": stream_type, - "maximum": event["limit"] + "maximum": event["maximum"] } def handle_max_stream_data_receive(event): return { "frame_type": "max_stream_data", "stream_id": event["stream-id"], - "maximum": event["limit"] + "maximum": event["maximum"] } def handle_max_stream_data_send(event): return { "frame_type": "max_stream_data", "stream_id": event["stream-id"], - "maximum": event["limit"] + "maximum": event["maximum"] } def handle_new_connection_id_receive(event): @@ -184,14 +184,14 @@ def handle_stream_data_blocked_receive(event): return { "frame_type": "stream_data_blocked", "stream_id": event["stream-id"], - "limit": event["limit"] + "maximum": event["maximum"] } def handle_stream_data_blocked_send(event): return { "frame_type": "stream_data_blocked", "stream_id": event["stream-id"], - "limit": event["limit"] + "maximum": event["maximum"] } def handle_stream_on_receive_reset(event): @@ -233,7 +233,7 @@ def handle_streams_blocked_receive(event): return { "frame_type": "streams_blocked", "stream_type": stream_type, - "limit": event["limit"] + "maximum": event["maximum"] } def handle_streams_blocked_send(event): @@ -244,7 +244,7 @@ def handle_streams_blocked_send(event): return { "frame_type": "streams_blocked", "stream_type": stream_type, - "limit": event["limit"] + "maximum": event["maximum"] } def handle_transport_close_receive(event): diff --git a/quicly-probes.d b/quicly-probes.d index b2a9f22eb..72881bf98 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -74,14 +74,14 @@ provider quicly { probe stream_acked(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t off, size_t len); probe stream_lost(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t off, size_t len); - probe max_data_send(struct st_quicly_conn_t *conn, int64_t at, uint64_t limit); - probe max_data_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t limit); + probe max_data_send(struct st_quicly_conn_t *conn, int64_t at, uint64_t maximum); + probe max_data_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t maximum); - probe max_streams_send(struct st_quicly_conn_t *conn, int64_t at, uint64_t limit, int is_unidirectional); - probe max_streams_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t limit, int is_unidirectional); + probe max_streams_send(struct st_quicly_conn_t *conn, int64_t at, uint64_t maximum, int is_unidirectional); + probe max_streams_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t maximum, int is_unidirectional); - probe max_stream_data_send(struct st_quicly_conn_t *conn, int64_t at, struct st_quicly_stream_t *stream, uint64_t limit); - probe max_stream_data_receive(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t limit); + probe max_stream_data_send(struct st_quicly_conn_t *conn, int64_t at, struct st_quicly_stream_t *stream, uint64_t maximum); + probe max_stream_data_receive(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t maximum); probe new_token_send(struct st_quicly_conn_t *conn, int64_t at, uint8_t *token, size_t token_len, uint64_t generation); probe new_token_acked(struct st_quicly_conn_t *conn, int64_t at, uint64_t generation); @@ -90,8 +90,8 @@ provider quicly { probe handshake_done_send(struct st_quicly_conn_t *conn, int64_t at); probe handshake_done_receive(struct st_quicly_conn_t *conn, int64_t at); - probe streams_blocked_send(struct st_quicly_conn_t *conn, int64_t at, uint64_t limit, int is_unidirectional); - probe streams_blocked_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t limit, int is_unidirectional); + probe streams_blocked_send(struct st_quicly_conn_t *conn, int64_t at, uint64_t maximum, int is_unidirectional); + probe streams_blocked_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t maximum, int is_unidirectional); probe new_connection_id_send(struct st_quicly_conn_t *conn, int64_t at, uint64_t sequence, uint64_t retire_prior_to, const char *cid, const char *stateless_reset_token); probe new_connection_id_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t sequence, uint64_t retire_prior_to, const char *cid, const char *stateless_reset_token); @@ -102,8 +102,8 @@ provider quicly { probe data_blocked_send(struct st_quicly_conn_t *conn, int64_t at, uint64_t off); probe data_blocked_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t off); - probe stream_data_blocked_send(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t limit); - probe stream_data_blocked_receive(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t limit); + probe stream_data_blocked_send(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t maximum); + probe stream_data_blocked_receive(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t maximum); probe datagram_send(struct st_quicly_conn_t *conn, int64_t at, const void *payload, size_t payload_len); probe datagram_receive(struct st_quicly_conn_t *conn, int64_t at, const void *payload, size_t payload_len); From 8009e91f16788c4a6177c47ec916c88406b6fb36 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Thu, 3 Dec 2020 15:55:04 -0800 Subject: [PATCH 050/361] dtrace: remove the quictrace_lost probe Because there's an identical packet_lost probe. --- lib/quicly.c | 1 - quicly-probes.d | 1 - 2 files changed, 2 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index ec94460f4..f547a3d33 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3571,7 +3571,6 @@ static void on_loss_detected(quicly_loss_t *loss, const quicly_sent_packet_t *lo lost_packet->packet_number, conn->egress.packet_number, conn->stash.now, conn->egress.max_udp_payload_size); QUICLY_PROBE(PACKET_LOST, conn, conn->stash.now, lost_packet->packet_number); - QUICLY_PROBE(QUICTRACE_LOST, conn, conn->stash.now, lost_packet->packet_number); QUICLY_PROBE(CC_CONGESTION, conn, conn->stash.now, lost_packet->packet_number + 1, conn->egress.loss.sentmap.bytes_in_flight, conn->egress.cc.cwnd); QUICLY_PROBE(QUICTRACE_CC_LOST, conn, conn->stash.now, &conn->egress.loss.rtt, conn->egress.cc.cwnd, diff --git a/quicly-probes.d b/quicly-probes.d index b2a9f22eb..597bc6860 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -114,7 +114,6 @@ provider quicly { probe quictrace_send_stream(struct st_quicly_conn_t *conn, int64_t at, struct st_quicly_stream_t *stream, uint64_t off, size_t len, int fin); probe quictrace_recv_stream(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t off, size_t len, int fin); - probe quictrace_lost(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); probe quictrace_cc_ack(struct st_quicly_conn_t *conn, int64_t at, struct quicly_rtt_t *rtt, uint32_t cwnd, size_t inflight); probe quictrace_cc_lost(struct st_quicly_conn_t *conn, int64_t at, struct quicly_rtt_t *rtt, uint32_t cwnd, size_t inflight); From 5fa09d5025417368f77a52324b20ff326d0fe4fd Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Mon, 7 Dec 2020 11:22:02 -0800 Subject: [PATCH 051/361] dtrace: emit packet_type from the packet_lost probe --- lib/quicly.c | 2 +- quicly-probes.d | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index f547a3d33..5ba640a96 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3570,7 +3570,7 @@ static void on_loss_detected(quicly_loss_t *loss, const quicly_sent_packet_t *lo conn->egress.cc.impl->cc_on_lost(&conn->egress.cc, &conn->egress.loss, lost_packet->cc_bytes_in_flight, lost_packet->packet_number, conn->egress.packet_number, conn->stash.now, conn->egress.max_udp_payload_size); - QUICLY_PROBE(PACKET_LOST, conn, conn->stash.now, lost_packet->packet_number); + QUICLY_PROBE(PACKET_LOST, conn, conn->stash.now, lost_packet->packet_number, lost_packet->ack_epoch); QUICLY_PROBE(CC_CONGESTION, conn, conn->stash.now, lost_packet->packet_number + 1, conn->egress.loss.sentmap.bytes_in_flight, conn->egress.cc.cwnd); QUICLY_PROBE(QUICTRACE_CC_LOST, conn, conn->stash.now, &conn->egress.loss.rtt, conn->egress.cc.cwnd, diff --git a/quicly-probes.d b/quicly-probes.d index 597bc6860..9d6becab3 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -46,7 +46,7 @@ provider quicly { probe packet_received(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, const void *decrypted, size_t decrypted_len, uint8_t packet_type); probe packet_prepare(struct st_quicly_conn_t *conn, int64_t at, uint8_t first_octet, const char *dcid); probe packet_acked(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, int is_late_ack); - probe packet_lost(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); + probe packet_lost(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn, uint8_t packet_type); probe packet_decryption_failed(struct st_quicly_conn_t *conn, int64_t at, uint64_t pn); probe pto(struct st_quicly_conn_t *conn, int64_t at, size_t inflight, uint32_t cwnd, int8_t pto_count); From 26f1bdce0d95faa5c8359b389361c4f54ad14084 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Mon, 7 Dec 2020 12:36:13 -0800 Subject: [PATCH 052/361] qlog: add a handler for the packet_lost event --- misc/qlog-adapter.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 048430b93..223fdeaff 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -25,6 +25,14 @@ PACKET_LABELS = ["initial", "0rtt", "handshake", "1rtt"] +def handle_packet_lost(events, idx): + return [events[idx]["time"], "recovery", "packet_lost", { + "packet_type": PACKET_LABELS[events[idx]["packet-type"]], + "header": { + "packet_number": events[idx]["pn"] + } + }] + def handle_packet_received(events, idx): frames = [] acked = [] @@ -270,6 +278,7 @@ def render_ack_frame(ranges): } QLOG_EVENT_HANDLERS = { + "packet-lost": handle_packet_lost, "packet-received": handle_packet_received, "packet-sent": handle_packet_sent } From f028776c1aed9c6b85c00a68ffe035a07ee6c54e Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 5 Jan 2021 17:13:53 +0900 Subject: [PATCH 053/361] Eliminate `is_active` flag, as it is fragile to bugs. The flag is only usable when there is a guarantee that there would not be more than one inflight sentmap carrying the same byte. But that does not stand for the FIN flag, causing assertion failures. `quicly_ranges_subtract` is going to be fast unless packet loss is involved (due to end offset being acked being no greater than the beginning offset of pending ranges), therefore this optimization is unnecessary. --- include/quicly/sendstate.h | 2 +- lib/quicly.c | 9 ++++----- lib/sendstate.c | 8 +++----- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/include/quicly/sendstate.h b/include/quicly/sendstate.h index 06ba87ef1..1797556e8 100644 --- a/include/quicly/sendstate.h +++ b/include/quicly/sendstate.h @@ -62,7 +62,7 @@ static int quicly_sendstate_is_open(quicly_sendstate_t *state); int quicly_sendstate_activate(quicly_sendstate_t *state); int quicly_sendstate_shutdown(quicly_sendstate_t *state, uint64_t final_size); void quicly_sendstate_reset(quicly_sendstate_t *state); -int quicly_sendstate_acked(quicly_sendstate_t *state, quicly_sendstate_sent_t *args, int is_active, size_t *bytes_to_shift); +int quicly_sendstate_acked(quicly_sendstate_t *state, quicly_sendstate_sent_t *args, size_t *bytes_to_shift); int quicly_sendstate_lost(quicly_sendstate_t *state, quicly_sendstate_sent_t *args); /* inline definitions */ diff --git a/lib/quicly.c b/lib/quicly.c index dd165d10c..1454ed18f 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -2484,7 +2484,7 @@ static int on_ack_ack(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, return 0; } -static int on_ack_stream_ack_one(quicly_conn_t *conn, quicly_stream_id_t stream_id, quicly_sendstate_sent_t *sent, int is_active) +static int on_ack_stream_ack_one(quicly_conn_t *conn, quicly_stream_id_t stream_id, quicly_sendstate_sent_t *sent) { quicly_stream_t *stream; int ret; @@ -2493,7 +2493,7 @@ static int on_ack_stream_ack_one(quicly_conn_t *conn, quicly_stream_id_t stream_ return 0; size_t bytes_to_shift; - if ((ret = quicly_sendstate_acked(&stream->sendstate, sent, is_active, &bytes_to_shift)) != 0) + if ((ret = quicly_sendstate_acked(&stream->sendstate, sent, &bytes_to_shift)) != 0) return ret; if (bytes_to_shift != 0) { QUICLY_PROBE(STREAM_ON_SEND_SHIFT, stream->conn, stream->conn->stash.now, stream, bytes_to_shift); @@ -2515,7 +2515,7 @@ static int on_ack_stream_ack_cached(quicly_conn_t *conn) if (conn->stash.on_ack_stream.active_acked_cache.stream_id == INT64_MIN) return 0; ret = on_ack_stream_ack_one(conn, conn->stash.on_ack_stream.active_acked_cache.stream_id, - &conn->stash.on_ack_stream.active_acked_cache.args, 1); + &conn->stash.on_ack_stream.active_acked_cache.args); conn->stash.on_ack_stream.active_acked_cache.stream_id = INT64_MIN; return ret; } @@ -2543,8 +2543,7 @@ static int on_ack_stream(quicly_sentmap_t *map, const quicly_sent_packet_t *pack conn->stash.on_ack_stream.active_acked_cache.stream_id = sent->data.stream.stream_id; conn->stash.on_ack_stream.active_acked_cache.args = sent->data.stream.args; } else { - if ((ret = on_ack_stream_ack_one(conn, sent->data.stream.stream_id, &sent->data.stream.args, - packet->frames_in_flight)) != 0) + if ((ret = on_ack_stream_ack_one(conn, sent->data.stream.stream_id, &sent->data.stream.args)) != 0) return ret; } } diff --git a/lib/sendstate.c b/lib/sendstate.c index 7336c7b37..35ff0e8f8 100644 --- a/lib/sendstate.c +++ b/lib/sendstate.c @@ -113,7 +113,7 @@ static int check_amount_of_state(quicly_sendstate_t *state) return 0; } -int quicly_sendstate_acked(quicly_sendstate_t *state, quicly_sendstate_sent_t *args, int is_active, size_t *bytes_to_shift) +int quicly_sendstate_acked(quicly_sendstate_t *state, quicly_sendstate_sent_t *args, size_t *bytes_to_shift) { uint64_t prev_sent_upto = state->acked.ranges[0].end; int ret; @@ -121,10 +121,8 @@ int quicly_sendstate_acked(quicly_sendstate_t *state, quicly_sendstate_sent_t *a /* adjust acked and pending ranges */ if ((ret = quicly_ranges_add(&state->acked, args->start, args->end)) != 0) return ret; - if (!is_active) { - if ((ret = quicly_ranges_subtract(&state->pending, args->start, args->end)) != 0) - return ret; - } + if ((ret = quicly_ranges_subtract(&state->pending, args->start, args->end)) != 0) + return ret; assert(state->pending.num_ranges == 0 || state->acked.ranges[0].end <= state->pending.ranges[0].start); /* calculate number of bytes that can be retired from the send buffer */ From 3d2ef227599100fbf759a3e383afed783d7decd3 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 26 Jan 2021 15:53:36 +0900 Subject: [PATCH 054/361] add knob to configure IW (by packets) --- include/quicly.h | 4 ++++ include/quicly/cc.h | 2 +- lib/cc-reno.c | 18 ++++++++++-------- lib/defaults.c | 3 +++ lib/quicly.c | 10 ++++++---- 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index 91d21dcc9..98190645c 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -272,6 +272,10 @@ struct st_quicly_context_t { * maximum number of bytes that can be transmitted on a CRYPTO stream (per each epoch) */ uint64_t max_crypto_bytes; + /** + * initial CWND in terms of packet numbers + */ + uint32_t initcwnd_packets; /** * (client-only) Initial QUIC protocol version used by the client. Setting this to a greased version will enforce version * negotiation. diff --git a/include/quicly/cc.h b/include/quicly/cc.h index 1185f89d3..031ed51af 100644 --- a/include/quicly/cc.h +++ b/include/quicly/cc.h @@ -168,7 +168,7 @@ extern struct st_quicly_init_cc_t quicly_cc_cubic_init; /** * Calculates the initial congestion window size given the maximum UDP payload size. */ -uint32_t quicly_cc_calc_initial_cwnd(uint16_t max_udp_payload_size); +uint32_t quicly_cc_calc_initial_cwnd(uint32_t max_packets, uint16_t max_udp_payload_size); #ifdef __cplusplus } diff --git a/lib/cc-reno.c b/lib/cc-reno.c index 583b91d3e..b1fe1e97d 100644 --- a/lib/cc-reno.c +++ b/lib/cc-reno.c @@ -98,13 +98,15 @@ static void reno_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwnd quicly_init_cc_t quicly_cc_reno_init = {reno_init}; -uint32_t quicly_cc_calc_initial_cwnd(uint16_t max_udp_payload_size) +uint32_t quicly_cc_calc_initial_cwnd(uint32_t max_packets, uint16_t max_udp_payload_size) { - static const uint32_t max_packets = 10, max_bytes = 14720; - uint32_t cwnd = max_packets * max_udp_payload_size; - if (cwnd > max_bytes) - cwnd = max_bytes; - if (cwnd < QUICLY_MIN_CWND * max_udp_payload_size) - cwnd = QUICLY_MIN_CWND * max_udp_payload_size; - return cwnd; + static const uint32_t mtu_max = 1472; + + /* apply filters to the two arguments */ + if (max_packets < QUICLY_MIN_CWND) + max_packets = QUICLY_MIN_CWND; + if (max_udp_payload_size > mtu_max) + max_udp_payload_size = mtu_max; + + return max_packets * max_udp_payload_size; } diff --git a/lib/defaults.c b/lib/defaults.c index 074d4ae93..063b88b4c 100644 --- a/lib/defaults.c +++ b/lib/defaults.c @@ -26,6 +26,7 @@ #define DEFAULT_MAX_UDP_PAYLOAD_SIZE 1472 #define DEFAULT_MAX_PACKETS_PER_KEY 16777216 #define DEFAULT_MAX_CRYPTO_BYTES 65536 +#define DEFAULT_INITCWND_PACKETS 10 #define DEFAULT_PRE_VALIDATION_AMPLIFICATION_LIMIT 3 /* profile that employs IETF specified values */ @@ -40,6 +41,7 @@ const quicly_context_t quicly_spec_context = {NULL, DEFAULT_MAX_UDP_PAYLOAD_SIZE}, DEFAULT_MAX_PACKETS_PER_KEY, DEFAULT_MAX_CRYPTO_BYTES, + DEFAULT_INITCWND_PACKETS, QUICLY_PROTOCOL_VERSION_CURRENT, DEFAULT_PRE_VALIDATION_AMPLIFICATION_LIMIT, 0, /* is_clustered */ @@ -67,6 +69,7 @@ const quicly_context_t quicly_performant_context = {NULL, DEFAULT_MAX_UDP_PAYLOAD_SIZE}, DEFAULT_MAX_PACKETS_PER_KEY, DEFAULT_MAX_CRYPTO_BYTES, + DEFAULT_INITCWND_PACKETS, QUICLY_PROTOCOL_VERSION_CURRENT, DEFAULT_PRE_VALIDATION_AMPLIFICATION_LIMIT, 0, /* is_clustered */ diff --git a/lib/quicly.c b/lib/quicly.c index 1454ed18f..a7354f7a0 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -2148,8 +2148,9 @@ int quicly_connect(quicly_conn_t **_conn, quicly_context_t *ctx, const char *ser } } - if ((conn = create_connection(ctx, ctx->initial_version, server_name, dest_addr, src_addr, NULL, new_cid, handshake_properties, - quicly_cc_calc_initial_cwnd(ctx->transport_params.max_udp_payload_size))) == NULL) { + if ((conn = create_connection( + ctx, ctx->initial_version, server_name, dest_addr, src_addr, NULL, new_cid, handshake_properties, + quicly_cc_calc_initial_cwnd(ctx->initcwnd_packets, ctx->transport_params.max_udp_payload_size))) == NULL) { ret = PTLS_ERROR_NO_MEMORY; goto Exit; } @@ -5485,8 +5486,9 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * } /* create connection */ - if ((*conn = create_connection(ctx, packet->version, NULL, src_addr, dest_addr, &packet->cid.src, new_cid, handshake_properties, - quicly_cc_calc_initial_cwnd(ctx->transport_params.max_udp_payload_size))) == NULL) { + if ((*conn = create_connection( + ctx, packet->version, NULL, src_addr, dest_addr, &packet->cid.src, new_cid, handshake_properties, + quicly_cc_calc_initial_cwnd(ctx->initcwnd_packets, ctx->transport_params.max_udp_payload_size))) == NULL) { ret = PTLS_ERROR_NO_MEMORY; goto Exit; } From 8048f8eec82d593b1465e75ebe9f7b853b9916e7 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 26 Jan 2021 16:23:24 +0900 Subject: [PATCH 055/361] add command line i/f --- src/cli.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/cli.c b/src/cli.c index be2219758..a87ffc676 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1057,6 +1057,7 @@ static void usage(const char *cmd) " -U size maximum size of UDP datagarm payload\n" " -V verify peer using the default certificates\n" " -v verbose mode (-vv emits packet dumps as well)\n" + " -w packets initial congestion window (default: 10)\n" " -x named-group named group to be used (default: secp256r1)\n" " -X max bidirectional stream count (default: 100)\n" " -y cipher-suite cipher-suite to be used (default: all)\n" @@ -1103,7 +1104,7 @@ int main(int argc, char **argv) address_token_aead.dec = ptls_aead_new(&ptls_openssl_aes128gcm, &ptls_openssl_sha256, 0, secret, ""); } - while ((ch = getopt(argc, argv, "a:b:B:c:C:Dd:k:Ee:Gi:I:K:l:M:m:NnOp:P:Rr:S:s:u:U:Vvx:X:y:h")) != -1) { + while ((ch = getopt(argc, argv, "a:b:B:c:C:Dd:k:Ee:Gi:I:K:l:M:m:NnOp:P:Rr:S:s:u:U:Vvw:x:X:y:h")) != -1) { switch (ch) { case 'a': assert(negotiated_protocols.count < PTLS_ELEMENTSOF(negotiated_protocols.list)); @@ -1252,6 +1253,12 @@ int main(int argc, char **argv) case 'v': ++verbosity; break; + case 'w': + if (sscanf(optarg, "%" SCNu32, &ctx.initcwnd_packets) != 1) { + fprintf(stderr, "invalid argument passed to `-w`\n"); + exit(1); + } + break; case 'x': { size_t i; for (i = 0; key_exchanges[i] != NULL; ++i) From c0daffc4520a3078a3646195e50babe885d11491 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 26 Jan 2021 16:41:15 +0900 Subject: [PATCH 056/361] send_window can become negative --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 1454ed18f..648127ecf 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3078,7 +3078,7 @@ static int _do_allocate_frame(quicly_conn_t *conn, quicly_send_context_t *s, siz } else { if (s->num_datagrams >= s->max_datagrams) return QUICLY_ERROR_SENDBUF_FULL; - if (ack_eliciting && s->send_window == 0) + if (ack_eliciting && s->send_window <= 0) return QUICLY_ERROR_SENDBUF_FULL; if (s->payload_buf.end - s->payload_buf.datagram < conn->egress.max_udp_payload_size) return QUICLY_ERROR_SENDBUF_FULL; From 4c1fffb990d44fda6b1039f3bf497401d241bee2 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 26 Jan 2021 19:49:26 +0900 Subject: [PATCH 057/361] update perf expectations --- t/lossy.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/t/lossy.c b/t/lossy.c index 8c4ec841f..14cc3ab6f 100644 --- a/t/lossy.c +++ b/t/lossy.c @@ -426,14 +426,14 @@ static void test_downstream(void) subtest("75%", loss_core); time_spent[i] = quic_now - 1; } - loss_check_stats(time_spent, 4, 13812, 3582, 17579); + loss_check_stats(time_spent, 4, 14193, 3610, 17579); for (i = 0; i != 100; ++i) { init_cond_rand(&loss_cond_down, 1, 2); subtest("50%", loss_core); time_spent[i] = quic_now - 1; } - loss_check_stats(time_spent, 0, 1941, 608, 3006); + loss_check_stats(time_spent, 0, 2220, 608, 2779); for (i = 0; i != 100; ++i) { init_cond_rand(&loss_cond_down, 1, 4); @@ -483,7 +483,7 @@ static void test_bidirectional(void) subtest("75%", loss_core); time_spent[i] = quic_now - 1; } - loss_check_stats(time_spent, 27, 266649.4, 102052, 649336); + loss_check_stats(time_spent, 20, 240012.7, 126541, 652328); for (i = 0; i != 100; ++i) { init_cond_rand(&loss_cond_down, 1, 2); @@ -491,7 +491,7 @@ static void test_bidirectional(void) subtest("50%", loss_core); time_spent[i] = quic_now - 1; } - loss_check_stats(time_spent, 1, 2283.5, 1171, 6424); + loss_check_stats(time_spent, 0, 2286.9, 1175, 6424); for (i = 0; i != 100; ++i) { init_cond_rand(&loss_cond_down, 1, 4); @@ -499,7 +499,7 @@ static void test_bidirectional(void) subtest("25%", loss_core); time_spent[i] = quic_now - 1; } - loss_check_stats(time_spent, 0, 331, 284, 635); + loss_check_stats(time_spent, 0, 328.7, 237, 530); for (i = 0; i != 100; ++i) { init_cond_rand(&loss_cond_down, 1, 10); @@ -507,7 +507,7 @@ static void test_bidirectional(void) subtest("10%", loss_core); time_spent[i] = quic_now - 1; } - loss_check_stats(time_spent, 0, 151.7, 80, 298); + loss_check_stats(time_spent, 0, 150.1, 80, 298); for (i = 0; i != 100; ++i) { init_cond_rand(&loss_cond_down, 1, 20); @@ -515,7 +515,7 @@ static void test_bidirectional(void) subtest("5%", loss_core); time_spent[i] = quic_now - 1; } - loss_check_stats(time_spent, 0, 110.4, 80, 230); + loss_check_stats(time_spent, 0, 103.5, 80, 192); for (i = 0; i != 100; ++i) { init_cond_rand(&loss_cond_down, 1, 40); @@ -523,7 +523,7 @@ static void test_bidirectional(void) subtest("2.5%", loss_core); time_spent[i] = quic_now - 1; } - loss_check_stats(time_spent, 0, 95.6, 80, 190); + loss_check_stats(time_spent, 0, 96.7, 80, 80); for (i = 0; i != 100; ++i) { init_cond_rand(&loss_cond_down, 1, 64); @@ -531,7 +531,7 @@ static void test_bidirectional(void) subtest("1.6%", loss_core); time_spent[i] = quic_now - 1; } - loss_check_stats(time_spent, 0, 95.8, 80, 190); + loss_check_stats(time_spent, 0, 96.7, 80, 190); } void test_lossy(void) From 8e9df7f8fc603d170ac903307e1933df3a2e5cf8 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Tue, 26 Jan 2021 17:02:10 +0000 Subject: [PATCH 058/361] Prevent potential NULL dereference `hp_ctx` is not guaranteed to be non-NULL. Fixes Coverity CID 1501098 --- lib/defaults.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/defaults.c b/lib/defaults.c index 074d4ae93..50013803d 100644 --- a/lib/defaults.c +++ b/lib/defaults.c @@ -414,7 +414,7 @@ static int default_setup_cipher(quicly_crypto_engine_t *engine, quicly_conn_t *c ptls_aead_free(*aead_ctx); *aead_ctx = NULL; } - if (*hp_ctx != NULL) { + if (hp_ctx != NULL && *hp_ctx != NULL) { ptls_cipher_free(*hp_ctx); *hp_ctx = NULL; } From 79d6178df52b9fa87a36689632a51919841a3651 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 27 Jan 2021 07:32:55 +0900 Subject: [PATCH 059/361] add comments --- lib/quicly.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 648127ecf..b23430482 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -2906,7 +2906,8 @@ struct st_quicly_send_context_t { uint8_t *end; } payload_buf; /** - * the currently available window for sending (in bytes) + * Currently available window for sending (in bytes); the value becomes negative when the sender uses more window than permitted + * permitted. That is because the sender operates at packet-level rather than byte-level. */ ssize_t send_window; /** @@ -3078,6 +3079,7 @@ static int _do_allocate_frame(quicly_conn_t *conn, quicly_send_context_t *s, siz } else { if (s->num_datagrams >= s->max_datagrams) return QUICLY_ERROR_SENDBUF_FULL; + /* note: send_window (ssize_t) can become negative; see doc-comment */ if (ack_eliciting && s->send_window <= 0) return QUICLY_ERROR_SENDBUF_FULL; if (s->payload_buf.end - s->payload_buf.datagram < conn->egress.max_udp_payload_size) From 84ca2f31169117230178cc41c2a980449097d8f4 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 27 Jan 2021 07:38:29 +0900 Subject: [PATCH 060/361] refine --- lib/quicly.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index b23430482..912a01cde 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -2906,8 +2906,8 @@ struct st_quicly_send_context_t { uint8_t *end; } payload_buf; /** - * Currently available window for sending (in bytes); the value becomes negative when the sender uses more window than permitted - * permitted. That is because the sender operates at packet-level rather than byte-level. + * Currently available window for sending (in bytes); the value becomes negative when the sender uses more space than permitted. + * That happens because the sender operates at packet-level rather than byte-level. */ ssize_t send_window; /** From 62059ab897bbab51bfd5f358a6e8e78cadb6dd82 Mon Sep 17 00:00:00 2001 From: Toru Maesaka Date: Fri, 29 Jan 2021 14:39:31 -0800 Subject: [PATCH 061/361] qlog: update the output format to draft-02 --- misc/qlog-adapter.py | 84 ++++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 8867d512a..dbcd4cf5f 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -26,12 +26,16 @@ PACKET_LABELS = ["initial", "0rtt", "handshake", "1rtt"] def handle_packet_lost(events, idx): - return [events[idx]["time"], "recovery", "packet_lost", { - "packet_type": PACKET_LABELS[events[idx]["packet-type"]], - "header": { - "packet_number": events[idx]["pn"] + return { + "time": events[idx]["time"], + "name": "recovery:packet_lost", + "data": { + "header": { + "packet_type": PACKET_LABELS[events[idx]["packet-type"]], + "packet_number": events[idx]["pn"] + } } - }] + } def handle_packet_received(events, idx): frames = [] @@ -54,13 +58,17 @@ def handle_packet_received(events, idx): if handler: frames.append(handler(ev)) - return [events[idx]["time"], "transport", "packet_received", { - "packet_type": PACKET_LABELS[events[idx]["packet-type"]], - "header": { - "packet_number": events[idx]["pn"] - }, - "frames": frames - }] + return { + "time": events[idx]["time"], + "name": "transport:packet_received", + "data": { + "header": { + "packet_type": PACKET_LABELS[events[idx]["packet-type"]], + "packet_number": events[idx]["pn"] + }, + "frames": frames + } + } def handle_packet_sent(events, idx): frames = [] @@ -71,13 +79,17 @@ def handle_packet_sent(events, idx): frames.append(handler(events[i])) i -= 1 - return [events[idx]["time"], "transport", "packet_sent", { - "packet_type": PACKET_LABELS[events[idx]["packet-type"]], - "header": { - "packet_number": events[idx]["pn"] - }, - "frames": frames - }] + return { + "time": events[idx]["time"], + "name": "transport:packet_sent", + "data": { + "header": { + "packet_type": PACKET_LABELS[events[idx]["packet-type"]], + "packet_number": events[idx]["pn"] + }, + "frames": frames + } + } def handle_ack_send(event): return render_ack_frame([[event["largest-acked"]]]) @@ -333,28 +345,24 @@ def main(): (_, infile) = sys.argv source_events = load_quicly_events(infile) - trace = { - "vantage_point": { - "type": "server" - }, - "event_fields": [ - "time", - "category", - "event", - "data" - ], - "events": [] - } - for i, event in enumerate(source_events): - handler = QLOG_EVENT_HANDLERS.get(event["type"]) - if handler: - trace["events"].append(handler(source_events, i)) - print(json.dumps({ - "qlog_version": "draft-02-wip", + "qlog_format": "NDJSON", + "qlog_version": "draft-02", "title": "h2o/quicly qlog", - "traces": [trace] + "trace": { + "vantage_point": { + "type": "server" + }, + "common_fields": { + "protocol_type": "QUIC_HTTP3", + "time_format": "absolute" + } + } })) + for i, event in enumerate(source_events): + handler = QLOG_EVENT_HANDLERS.get(event["type"]) + if handler: + print(json.dumps(handler(source_events, i))) if __name__ == "__main__": main() From a1b1bee94822115998b3bac0befbfb77ea5bf2c6 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 9 Feb 2021 10:52:03 +0900 Subject: [PATCH 062/361] turn on / off 0-RTT based on TLS config --- lib/quicly.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 9a4fb8b82..c67fed035 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5977,8 +5977,11 @@ void quicly_amend_ptls_context(ptls_context_t *ptls) static ptls_update_traffic_key_t update_traffic_key = {update_traffic_key_cb}; ptls->omit_end_of_early_data = 1; - ptls->max_early_data_size = UINT32_MAX; ptls->update_traffic_key = &update_traffic_key; + + /* if TLS 1.3 config permits use of early data, convert the value to 0xffffffff in accordance with QUIC-TLS */ + if (ptls->max_early_data_size != 0) + ptls->max_early_data_size = UINT32_MAX; } int quicly_encrypt_address_token(void (*random_bytes)(void *, size_t), ptls_aead_context_t *aead, ptls_buffer_t *buf, From 4e8b41fe03d76bafc359234b58f773cb0313497c Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 12 Feb 2021 14:18:17 +0900 Subject: [PATCH 063/361] remove unused flag --- include/quicly.h | 4 ---- include/quicly/cid.h | 3 +-- lib/defaults.c | 2 -- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index 98190645c..74b4fd37c 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -285,10 +285,6 @@ struct st_quicly_context_t { * (server-only) amplification limit before the peer address is validated */ uint16_t pre_validation_amplification_limit; - /** - * if inter-node routing is used (by utilising quicly_cid_plaintext_t::node_id) - */ - unsigned is_clustered : 1; /** * expand client hello so that it does not fit into one datagram */ diff --git a/include/quicly/cid.h b/include/quicly/cid.h index 235e6c8db..c143ca435 100644 --- a/include/quicly/cid.h +++ b/include/quicly/cid.h @@ -60,8 +60,7 @@ typedef struct st_quicly_cid_plaintext_t { */ uint32_t thread_id : 24; /** - * for inter-node routing; available only when using a 16-byte cipher to encrypt CIDs, otherwise set to zero. See - * quicly_context_t::is_clustered. + * for inter-node routing; available only when using a 16-byte cipher to encrypt CIDs, otherwise set to zero. */ uint64_t node_id; } quicly_cid_plaintext_t; diff --git a/lib/defaults.c b/lib/defaults.c index e4a35cab7..28d41a8e4 100644 --- a/lib/defaults.c +++ b/lib/defaults.c @@ -44,7 +44,6 @@ const quicly_context_t quicly_spec_context = {NULL, DEFAULT_INITCWND_PACKETS, QUICLY_PROTOCOL_VERSION_CURRENT, DEFAULT_PRE_VALIDATION_AMPLIFICATION_LIMIT, - 0, /* is_clustered */ 0, /* enlarge_client_hello */ NULL, NULL, /* on_stream_open */ @@ -72,7 +71,6 @@ const quicly_context_t quicly_performant_context = {NULL, DEFAULT_INITCWND_PACKETS, QUICLY_PROTOCOL_VERSION_CURRENT, DEFAULT_PRE_VALIDATION_AMPLIFICATION_LIMIT, - 0, /* is_clustered */ 0, /* enlarge_client_hello */ NULL, NULL, /* on_stream_open */ From 914b67bd4fe6dcdc9e37a615ea43be6ad791d145 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 12 Feb 2021 12:30:50 +0900 Subject: [PATCH 064/361] Change the contract; the only valid case when the CID is of an unexpected size is when handling Initial or Handshake packets carrying client-generated DCID. In such case, forwarding is never necessary and therefore no need to decrypt --- include/quicly.h | 7 +++++-- include/quicly/cid.h | 15 +++++++++++---- lib/defaults.c | 30 +++++++++++++----------------- lib/quicly.c | 23 ++++++++++++++++------- 4 files changed, 45 insertions(+), 30 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index 74b4fd37c..c02e441b2 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -670,11 +670,14 @@ typedef struct st_quicly_decoded_packet_t { */ ptls_iovec_t encrypted; /** - * the decrypted CID; note that the value is not authenticated + * The decrypted CID, or `quicly_cid_plaintext_invalid`. Assuming that `cid_decryptor` is non-NULL, this variable would + * contain a valid value whenever `might_be_client_generated` is false. When `might_be_client_generated` is true, this + * value might be set to `quicly_cid_plaintext_invalid`. Note however that, as the CID itself is not authenticated, + * a packet might be bogus regardless of the value of the CID. */ quicly_cid_plaintext_t plaintext; /** - * + * If destination CID might be one generated by a client. This flag would be set for Initial and 0-RTT packets. */ unsigned might_be_client_generated : 1; } dest; diff --git a/include/quicly/cid.h b/include/quicly/cid.h index c143ca435..1f83cb9d2 100644 --- a/include/quicly/cid.h +++ b/include/quicly/cid.h @@ -65,6 +65,12 @@ typedef struct st_quicly_cid_plaintext_t { uint64_t node_id; } quicly_cid_plaintext_t; +/** + * A CID used for indicating that a CID is invalid. Both .node_id and .thread_id are set to their maximum. Therefore, mappings must + * refrain from using those values. + */ +extern quicly_cid_plaintext_t quicly_cid_plaintext_invalid; + /** * CID encryption */ @@ -75,10 +81,11 @@ typedef struct st_quicly_cid_encryptor_t { void (*encrypt_cid)(struct st_quicly_cid_encryptor_t *self, quicly_cid_t *encrypted, void *stateless_reset_token, const quicly_cid_plaintext_t *plaintext); /** - * decrypts CID. plaintext->thread_id should contain a randomly distributed number when validation fails, so that the value can - * be used for distributing load among the threads within the process. - * @param len length of encrypted bytes if known, or 0 if unknown (short header packet) - * @return length of the CID, or SIZE_MAX if decryption failed + * decrypts a CID + * @param plaintext if successful, the decoded CID will be written + * @param encrypt the encrypted CID + * @param len length of the encrypted CID when the packet is a long header packet, or 0 if it is a short header packet + * @return length of the CID if successful, or SIZE_MAX if failed */ size_t (*decrypt_cid)(struct st_quicly_cid_encryptor_t *self, quicly_cid_plaintext_t *plaintext, const void *encrypted, size_t len); diff --git a/lib/defaults.c b/lib/defaults.c index 28d41a8e4..6377f090a 100644 --- a/lib/defaults.c +++ b/lib/defaults.c @@ -145,28 +145,24 @@ static size_t default_decrypt_cid(quicly_cid_encryptor_t *_self, quicly_cid_plai size_t len) { struct st_quicly_default_encrypt_cid_t *self = (void *)_self; - uint8_t ptbuf[16], tmpbuf[16]; + uint8_t ptbuf[16]; const uint8_t *p; - size_t cid_len; - - cid_len = self->cid_decrypt_ctx->algo->block_size; - - /* normalize the input, so that we would get consistent routing */ - if (len != 0 && len != cid_len) { - if (len > cid_len) - len = cid_len; - memcpy(tmpbuf, encrypted, cid_len); - if (len < cid_len) - memset(tmpbuf + len, 0, cid_len - len); - encrypted = tmpbuf; + + if (len != 0) { + /* long header packet; decrypt only if given Connection ID matches the expected size */ + if (len != self->cid_decrypt_ctx->algo->block_size) + return SIZE_MAX; + } else { + /* short header packet; we are the one to name the size */ + len = self->cid_decrypt_ctx->algo->block_size; } /* decrypt */ - ptls_cipher_encrypt(self->cid_decrypt_ctx, ptbuf, encrypted, cid_len); + ptls_cipher_encrypt(self->cid_decrypt_ctx, ptbuf, encrypted, len); /* decode */ p = ptbuf; - if (cid_len == 16) { + if (len == 16) { plaintext->node_id = quicly_decode64(&p); } else { plaintext->node_id = 0; @@ -174,9 +170,9 @@ static size_t default_decrypt_cid(quicly_cid_encryptor_t *_self, quicly_cid_plai plaintext->master_id = quicly_decode32(&p); plaintext->thread_id = quicly_decode24(&p); plaintext->path_id = *p++; - assert(p - ptbuf == cid_len); + assert(p - ptbuf == len); - return cid_len; + return len; } static int default_generate_reset_token(quicly_cid_encryptor_t *_self, void *token, const void *cid) diff --git a/lib/quicly.c b/lib/quicly.c index c67fed035..eb3079b76 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -428,6 +428,8 @@ static int initiate_close(quicly_conn_t *conn, int err, uint64_t frame_type, con static int handle_close(quicly_conn_t *conn, int err, uint64_t frame_type, ptls_iovec_t reason_phrase); static int discard_sentmap_by_epoch(quicly_conn_t *conn, unsigned ack_epochs); +quicly_cid_plaintext_t quicly_cid_plaintext_invalid = {.node_id = UINT64_MAX, .thread_id = 0xffffff}; + static const quicly_transport_parameters_t default_transport_params = {.max_udp_payload_size = QUICLY_DEFAULT_MAX_UDP_PAYLOAD_SIZE, .ack_delay_exponent = QUICLY_DEFAULT_ACK_DELAY_EXPONENT, .max_ack_delay = QUICLY_DEFAULT_MAX_ACK_DELAY, @@ -611,18 +613,25 @@ size_t quicly_decode_packet(quicly_context_t *ctx, quicly_decoded_packet_t *pack goto Error; packet->cid.src.base = (uint8_t *)src; src += packet->cid.src.len; - if (ctx->cid_encryptor != NULL) { - ctx->cid_encryptor->decrypt_cid(ctx->cid_encryptor, &packet->cid.dest.plaintext, packet->cid.dest.encrypted.base, - packet->cid.dest.encrypted.len); - } else { - packet->cid.dest.plaintext = (quicly_cid_plaintext_t){0}; - } switch (packet->octets.base[0] & QUICLY_PACKET_TYPE_BITMASK) { case QUICLY_PACKET_TYPE_INITIAL: case QUICLY_PACKET_TYPE_0RTT: + if (ctx->cid_encryptor != NULL && packet->cid.dest.encrypted.len != 0 && + ctx->cid_encryptor->decrypt_cid(ctx->cid_encryptor, &packet->cid.dest.plaintext, packet->cid.dest.encrypted.base, + packet->cid.dest.encrypted.len) == SIZE_MAX) + packet->cid.dest.plaintext = quicly_cid_plaintext_invalid; packet->cid.dest.might_be_client_generated = 1; break; default: + if (ctx->cid_encryptor != NULL) { + if (packet->cid.dest.encrypted.len == 0) + goto Error; + if (ctx->cid_encryptor->decrypt_cid(ctx->cid_encryptor, &packet->cid.dest.plaintext, + packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len) == SIZE_MAX) + goto Error; + } else { + packet->cid.dest.plaintext = quicly_cid_plaintext_invalid; + } packet->cid.dest.might_be_client_generated = 0; break; } @@ -676,7 +685,7 @@ size_t quicly_decode_packet(quicly_context_t *ctx, quicly_decoded_packet_t *pack src += local_cidl; } else { packet->cid.dest.encrypted = ptls_iovec_init(NULL, 0); - packet->cid.dest.plaintext = (quicly_cid_plaintext_t){0}; + packet->cid.dest.plaintext = quicly_cid_plaintext_invalid; } packet->cid.dest.might_be_client_generated = 0; packet->cid.src = ptls_iovec_init(NULL, 0); From 9506922a4f6e8da82105a6cd62eac02265be7ef4 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 18 Feb 2021 17:26:23 +0900 Subject: [PATCH 065/361] update picotls --- deps/picotls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/picotls b/deps/picotls index b833001ce..66793743e 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit b833001ce437e6887241d33c74eb8ebaf55af68d +Subproject commit 66793743ec678bee8115144f911cd21d72172f7e From 28f00f15791fa2e96d73c7f2809be317039f8b97 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 18 Feb 2021 17:45:08 +0900 Subject: [PATCH 066/361] add support for raw public keys (-W) --- src/cli.c | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/src/cli.c b/src/cli.c index a87ffc676..026d0fa5c 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1058,6 +1058,10 @@ static void usage(const char *cmd) " -V verify peer using the default certificates\n" " -v verbose mode (-vv emits packet dumps as well)\n" " -w packets initial congestion window (default: 10)\n" + " -W public-key-file use raw public keys (RFC 7250). When set and running as a\n" + " client, the argument specifies the public keys that the\n" + " server is expected to use. When running as a server, the\n" + " argument is ignored.\n" " -x named-group named group to be used (default: secp256r1)\n" " -X max bidirectional stream count (default: 100)\n" " -y cipher-suite cipher-suite to be used (default: all)\n" @@ -1079,7 +1083,7 @@ static void push_req(const char *path, int to_file) int main(int argc, char **argv) { - const char *host, *port, *cid_key = NULL; + const char *cert_file = NULL, *raw_pubkey_file = NULL, *host, *port, *cid_key = NULL; struct sockaddr_storage sa; socklen_t salen; unsigned udpbufsize = 0; @@ -1104,7 +1108,7 @@ int main(int argc, char **argv) address_token_aead.dec = ptls_aead_new(&ptls_openssl_aes128gcm, &ptls_openssl_sha256, 0, secret, ""); } - while ((ch = getopt(argc, argv, "a:b:B:c:C:Dd:k:Ee:Gi:I:K:l:M:m:NnOp:P:Rr:S:s:u:U:Vvw:x:X:y:h")) != -1) { + while ((ch = getopt(argc, argv, "a:b:B:c:C:Dd:k:Ee:Gi:I:K:l:M:m:NnOp:P:Rr:S:s:u:U:Vvw:W:x:X:y:h")) != -1) { switch (ch) { case 'a': assert(negotiated_protocols.count < PTLS_ELEMENTSOF(negotiated_protocols.list)); @@ -1120,7 +1124,7 @@ int main(int argc, char **argv) cid_key = optarg; break; case 'c': - load_certificate_chain(ctx.tls, optarg); + cert_file = optarg; break; case 'C': if (strcmp(optarg, "reno") == 0) { @@ -1259,6 +1263,9 @@ int main(int argc, char **argv) exit(1); } break; + case 'W': + raw_pubkey_file = optarg; + break; case 'x': { size_t i; for (i = 0; key_exchanges[i] != NULL; ++i) @@ -1356,12 +1363,20 @@ int main(int argc, char **argv) ctx.transport_params.max_datagram_frame_size = ctx.transport_params.max_udp_payload_size; } - if (ctx.tls->certificates.count != 0 || ctx.tls->sign_certificate != NULL) { + if (cert_file != NULL || ctx.tls->sign_certificate != NULL) { /* server */ - if (ctx.tls->certificates.count == 0 || ctx.tls->sign_certificate == NULL) { + if (cert_file == NULL || ctx.tls->sign_certificate == NULL) { fprintf(stderr, "-c and -k options must be used together\n"); exit(1); } + if (raw_pubkey_file != NULL) { + ctx.tls->certificates.list = malloc(sizeof(*ctx.tls->certificates.list)); + load_raw_public_key(ctx.tls->certificates.list, cert_file); + ctx.tls->certificates.count = 1; + ctx.tls->use_raw_public_keys = 1; + } else { + load_certificate_chain(ctx.tls, cert_file); + } if (cid_key == NULL) { static char random_key[17]; tlsctx.random_bytes(random_key, sizeof(random_key) - 1); @@ -1371,6 +1386,19 @@ int main(int argc, char **argv) ptls_iovec_init(cid_key, strlen(cid_key))); } else { /* client */ + if (raw_pubkey_file != NULL) { + ptls_iovec_t raw_pub_key; + EVP_PKEY *pubkey; + load_raw_public_key(&raw_pub_key, raw_pubkey_file); + pubkey = d2i_PUBKEY(NULL, (const unsigned char **)&raw_pub_key.base, raw_pub_key.len); + if (pubkey == NULL) { + fprintf(stderr, "Failed to create an EVP_PKEY from the key found in %s\n", raw_pubkey_file); + return 1; + } + setup_raw_pubkey_verify_certificate(ctx.tls, pubkey); + EVP_PKEY_free(pubkey); + ctx.tls->use_raw_public_keys = 1; + } hs_properties.client.negotiated_protocols.list = negotiated_protocols.list; hs_properties.client.negotiated_protocols.count = negotiated_protocols.count; if (session_file != NULL) From 60e24920cdc66fcedf839af6979c7b82424bb664 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 19 Feb 2021 11:18:18 +0900 Subject: [PATCH 067/361] use API that look like synchronous (because this has to become synchronous) --- include/quicly.h | 9 ++++---- lib/quicly.c | 53 ++++++++++++++++++++++++++++++++---------------- src/cli.c | 25 +++-------------------- 3 files changed, 44 insertions(+), 43 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index 98190645c..ba82d82d6 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -1052,11 +1052,12 @@ static int quicly_stream_has_receive_side(int is_client, quicly_stream_id_t stre */ static int quicly_stream_is_self_initiated(quicly_stream_t *stream); /** - * Registers a datagram frame payload to be sent. When the applications calls `quicly_send` the first time after registering the - * datagram frame payload, the payload is either sent or the reference is discarded. Until then, it is the caller's responsibility - * to retain the memory pointed to by `payload`. At the moment, DATAFRAM frames are not congestion controlled. + * Sends QUIC DATAGRAM frames. Some of the frames being provided may get dropped. + * Notes: + * * At the moment, emission of QUIC packets carrying DATAGRAM frames is not congestion controlled. + * * While the API is designed to look like synchronous, application still has to call `quicly_send` for the time being. */ -void quicly_set_datagram_frame(quicly_conn_t *conn, ptls_iovec_t payload); +void quicly_send_datagram_frames(quicly_conn_t *conn, ptls_iovec_t *datagrams, size_t num_datagrams); /** * */ diff --git a/lib/quicly.c b/lib/quicly.c index c67fed035..e56ce00d0 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -337,9 +337,12 @@ struct st_quicly_conn_t { */ quicly_retire_cid_set_t retire_cid; /** - * DATAGRAM frame payload to be sent + * payload of DATAGRAM frames to be sent */ - ptls_iovec_t datagram_frame_payload; + struct { + ptls_iovec_t payloads[10]; + size_t count; + } datagram_frame_payloads; } egress; /** * crypto data @@ -552,6 +555,15 @@ static void dispose_cipher(struct st_quicly_cipher_context_t *ctx) ptls_cipher_free(ctx->header_protection); } +static void clear_datagram_frame_payloads(quicly_conn_t *conn) +{ + for (size_t i = 0; i != conn->egress.datagram_frame_payloads.count; ++i) { + free(conn->egress.datagram_frame_payloads.payloads[i].base); + conn->egress.datagram_frame_payloads.payloads[i] = ptls_iovec_init(NULL, 0); + } + conn->egress.datagram_frame_payloads.count = 0; +} + static int is_retry(quicly_conn_t *conn) { return conn->retry_scid.len != UINT8_MAX; @@ -1495,6 +1507,7 @@ void quicly_free(quicly_conn_t *conn) #endif destroy_all_streams(conn, 0, 1); + clear_datagram_frame_payloads(conn); quicly_maxsender_dispose(&conn->ingress.max_data.sender); quicly_maxsender_dispose(&conn->ingress.max_streams.uni); @@ -2758,14 +2771,12 @@ static int on_ack_retire_connection_id(quicly_sentmap_t *map, const quicly_sent_ static int should_send_datagram_frame(quicly_conn_t *conn) { - if (conn->egress.datagram_frame_payload.base == NULL) + if (conn->egress.datagram_frame_payloads.count == 0) return 0; if (conn->application == NULL) return 0; if (conn->application->cipher.egress.key.aead == NULL) return 0; - if (conn->super.remote.transport_params.max_datagram_frame_size < conn->egress.datagram_frame_payload.len) - return 0; return 1; } @@ -4193,15 +4204,15 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) * This is because we do not have a way to retract the generation of a QUIC packet. * * Does not notify the application that the frame was dropped internally. */ if (should_send_datagram_frame(conn)) { - size_t required_space = quicly_datagram_frame_capacity(conn->egress.datagram_frame_payload); - if ((ret = _do_allocate_frame(conn, s, required_space, 1)) != 0) - goto Exit; - if (s->dst_end - s->dst >= required_space) { - s->dst = quicly_encode_datagram_frame(s->dst, conn->egress.datagram_frame_payload); - QUICLY_PROBE(DATAGRAM_SEND, conn, conn->stash.now, conn->egress.datagram_frame_payload.base, - conn->egress.datagram_frame_payload.len); - conn->egress.datagram_frame_payload = ptls_iovec_init(NULL, 0); - ++conn->super.stats.num_frames_sent.datagram; + for (size_t i = 0; i != conn->egress.datagram_frame_payloads.count; ++i) { + ptls_iovec_t *payload = conn->egress.datagram_frame_payloads.payloads + i; + size_t required_space = quicly_datagram_frame_capacity(*payload); + if ((ret = _do_allocate_frame(conn, s, required_space, 1)) != 0) + goto Exit; + if (s->dst_end - s->dst >= required_space) { + s->dst = quicly_encode_datagram_frame(s->dst, *payload); + QUICLY_PROBE(DATAGRAM_SEND, conn, conn->stash.now, payload->base, payload->len); + } } } if (!ack_only) { @@ -4332,9 +4343,17 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) return ret; } -void quicly_set_datagram_frame(quicly_conn_t *conn, ptls_iovec_t payload) +void quicly_send_datagram_frames(quicly_conn_t *conn, ptls_iovec_t *datagrams, size_t num_datagrams) { - conn->egress.datagram_frame_payload = payload; + for (size_t i = 0; i != num_datagrams; ++i) { + if (conn->egress.datagram_frame_payloads.count == PTLS_ELEMENTSOF(conn->egress.datagram_frame_payloads.payloads)) + break; + void *copied; + if ((copied = malloc(datagrams[i].len)) == NULL) + break; + memcpy(copied, datagrams[i].base, datagrams[i].len); + conn->egress.datagram_frame_payloads.payloads[conn->egress.datagram_frame_payloads.count++] = ptls_iovec_init(copied, datagrams[i].len); + } } int quicly_send(quicly_conn_t *conn, quicly_address_t *dest, quicly_address_t *src, struct iovec *datagrams, size_t *num_datagrams, @@ -4392,7 +4411,7 @@ int quicly_send(quicly_conn_t *conn, quicly_address_t *dest, quicly_address_t *s assert_consistency(conn, 1); Exit: - conn->egress.datagram_frame_payload = ptls_iovec_init(NULL, 0); + clear_datagram_frame_payloads(conn); if (s.num_datagrams != 0) { *dest = conn->super.remote.address; *src = conn->super.local.address; diff --git a/src/cli.c b/src/cli.c index a87ffc676..770fe7026 100644 --- a/src/cli.c +++ b/src/cli.c @@ -45,7 +45,6 @@ FILE *quicly_trace_fp = NULL; static unsigned verbosity = 0; static int suppress_output = 0, send_datagram_frame = 0; static int64_t enqueue_requests_at = 0, request_interval = 0; -static void *datagram_frame_payload_buf; static void hexdump(const char *title, const uint8_t *p, size_t l) { @@ -489,34 +488,15 @@ static int send_pending(int fd, quicly_conn_t *conn) if ((ret = quicly_send(conn, &dest, &src, packets, &num_packets, buf, sizeof(buf))) == 0 && num_packets != 0) send_packets(fd, &dest.sa, packets, num_packets); - if (datagram_frame_payload_buf != NULL) { - free(datagram_frame_payload_buf); - datagram_frame_payload_buf = NULL; - } - return ret; } -static void set_datagram_frame(quicly_conn_t *conn, ptls_iovec_t payload) -{ - if (datagram_frame_payload_buf != NULL) - free(datagram_frame_payload_buf); - - /* replace payload.base with an allocated buffer */ - datagram_frame_payload_buf = malloc(payload.len); - memcpy(datagram_frame_payload_buf, payload.base, payload.len); - payload.base = datagram_frame_payload_buf; - - /* set data to be sent. The buffer is being freed in `send_pending` after `quicly_send` is being called. */ - quicly_set_datagram_frame(conn, payload); -} - static void on_receive_datagram_frame(quicly_receive_datagram_frame_t *self, quicly_conn_t *conn, ptls_iovec_t payload) { printf("DATAGRAM: %.*s\n", (int)payload.len, payload.base); /* send responds with a datagram frame */ if (!quicly_is_client(conn)) - set_datagram_frame(conn, payload); + quicly_send_datagram_frames(conn, &payload, 1); } static void enqueue_requests(quicly_conn_t *conn) @@ -618,7 +598,8 @@ static int run_client(int fd, struct sockaddr *sa, const char *host) quicly_receive(conn, NULL, &sa, &packet); if (send_datagram_frame && quicly_connection_is_ready(conn)) { const char *message = "hello datagram!"; - set_datagram_frame(conn, ptls_iovec_init(message, strlen(message))); + ptls_iovec_t datagram = ptls_iovec_init(message, strlen(message)); + quicly_send_datagram_frames(conn, &datagram, 1); send_datagram_frame = 0; } } From cd9358c589a4e570eaab1719d5c9bca7fb33354e Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 19 Feb 2021 11:24:35 +0900 Subject: [PATCH 068/361] clang-format --- lib/quicly.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index e56ce00d0..77ce5efcf 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -4352,7 +4352,8 @@ void quicly_send_datagram_frames(quicly_conn_t *conn, ptls_iovec_t *datagrams, s if ((copied = malloc(datagrams[i].len)) == NULL) break; memcpy(copied, datagrams[i].base, datagrams[i].len); - conn->egress.datagram_frame_payloads.payloads[conn->egress.datagram_frame_payloads.count++] = ptls_iovec_init(copied, datagrams[i].len); + conn->egress.datagram_frame_payloads.payloads[conn->egress.datagram_frame_payloads.count++] = + ptls_iovec_init(copied, datagrams[i].len); } } From 6e88f866619d2b69316d436176a2d28e175b2b61 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 19 Feb 2021 21:12:28 +0900 Subject: [PATCH 069/361] pad to avoid crash when DATAGRAM does not fit into a QUIC packet --- lib/quicly.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/quicly.c b/lib/quicly.c index 77ce5efcf..57632d9d7 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -4212,6 +4212,10 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) if (s->dst_end - s->dst >= required_space) { s->dst = quicly_encode_datagram_frame(s->dst, *payload); QUICLY_PROBE(DATAGRAM_SEND, conn, conn->stash.now, payload->base, payload->len); + } else { + /* FIXME: At the moment, we add a padding because we do not have a way to reclaim allocated space, and because + * it is forbidden to send an empty QUIC packet. */ + *s->dst++ = QUICLY_FRAME_TYPE_PADDING; } } } From 771fc790c1facfbc174a8126e03c037b838445b5 Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Mon, 22 Feb 2021 14:18:36 -0800 Subject: [PATCH 070/361] Incrase number of inflight new token frames after emitting this Before this commit, the memory was left unintialized and would make the logic in `on_ack_new_token` inoperant: ``` ==1101999== Conditional jump or move depends on uninitialised value(s) ==1101999== at 0x36E093: on_ack_new_token (quicly.c:2732) ==1101999== by 0x37D6E8: quicly_sentmap_update (sentmap.c:162) ==1101999== by 0x36B198: mark_frames_on_pto (quicly.c:3565) ==1101999== by 0x35860A: do_send (quicly.c:4174) ==1101999== by 0x356E0B: quicly_send (quicly.c:4415) ==1101999== by 0x492CDD: h2o_quic_send (common.c:1149) ==1101999== by 0x4910F3: on_timeout (common.c:865) ==1101999== by 0x3A9C90: h2o_evloop_run (evloop.c.h:671) ==1101999== by 0x629A49: run_loop (main.c:3551) ==1101999== by 0x6269FF: main (main.c:4498) ``` --- lib/quicly.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/quicly.c b/lib/quicly.c index c67fed035..70315c228 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3731,6 +3731,8 @@ static int send_resumption_token(quicly_conn_t *conn, quicly_send_context_t *s) if ((ret = allocate_ack_eliciting_frame(conn, s, quicly_new_token_frame_capacity(ptls_iovec_init(tokenbuf.base, tokenbuf.off)), &sent, on_ack_new_token)) != 0) goto Exit; + ++conn->egress.new_token.num_inflight; + sent->data.new_token.is_inflight = 1; sent->data.new_token.generation = conn->egress.new_token.generation; s->dst = quicly_encode_new_token_frame(s->dst, ptls_iovec_init(tokenbuf.base, tokenbuf.off)); conn->egress.pending_flows &= ~QUICLY_PENDING_FLOW_NEW_TOKEN_BIT; From 0cc6a2bc8cb70cd22d14112dd54be15f0f31eb8c Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Tue, 23 Feb 2021 13:57:06 -0800 Subject: [PATCH 071/361] Add an end to end test for raw public keys --- t/assets/ec256-key-pair.pem | 5 +++++ t/assets/ec256-pub.pem | 4 ++++ t/e2e.t | 14 +++++++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 t/assets/ec256-key-pair.pem create mode 100644 t/assets/ec256-pub.pem diff --git a/t/assets/ec256-key-pair.pem b/t/assets/ec256-key-pair.pem new file mode 100644 index 000000000..ce786ed90 --- /dev/null +++ b/t/assets/ec256-key-pair.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIBswGBU5+SsrFYQupnJ/GVf1bYhBEmJiBpxLL4jXZRrpoAoGCCqGSM49 +AwEHoUQDQgAEWF0BvlHl/ZVaoApefcN5+emI6cjSDbR3aP843VWgMLfxNqvmWut0 +KsoRQC2OHJ+Z8HoLZcNnA7Mc3/ypHSUqrw== +-----END EC PRIVATE KEY----- diff --git a/t/assets/ec256-pub.pem b/t/assets/ec256-pub.pem new file mode 100644 index 000000000..76a339697 --- /dev/null +++ b/t/assets/ec256-pub.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWF0BvlHl/ZVaoApefcN5+emI6cjS +DbR3aP843VWgMLfxNqvmWut0KsoRQC2OHJ+Z8HoLZcNnA7Mc3/ypHSUqrw== +-----END PUBLIC KEY----- diff --git a/t/e2e.t b/t/e2e.t index ca671b397..d9ec76247 100755 --- a/t/e2e.t +++ b/t/e2e.t @@ -324,10 +324,22 @@ subtest "key-update" => sub { }; }; +subtest "raw-certificates-ec" => sub { + my $guard = spawn_server(qw(-W -)); + my $resp = `$cli -p /12 -W t/assets/ec256-pub.pem 127.0.0.1 $port 2> /dev/null`; + is $resp, "hello world\n"; +}; + + done_testing; sub spawn_server { - my @cmd = ($cli, "-k", "t/assets/server.key", "-c", "t/assets/server.crt", @_, "127.0.0.1", $port); + my @cmd; + if (grep(/^-W$/, @_)) { + @cmd = ($cli, "-k", "t/assets/ec256-key-pair.pem", "-c", "t/assets/ec256-pub.pem", @_, "127.0.0.1", $port); + } else { + @cmd = ($cli, "-k", "t/assets/server.key", "-c", "t/assets/server.crt", @_, "127.0.0.1", $port); + } my $pid = fork; die "fork failed:$!" unless defined $pid; From 4ecfb48e8c124dca85bb1822ce40a6a4a70ebd54 Mon Sep 17 00:00:00 2001 From: Mike Kosek Date: Mon, 1 Mar 2021 11:01:59 +0100 Subject: [PATCH 072/361] Fixed traffic secret labels according to NSS Key Log Format --- lib/quicly.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index c67fed035..e9589cc51 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -4038,8 +4038,8 @@ static int update_traffic_key_cb(ptls_update_traffic_key_t *self, ptls_t *tls, i ptls_aead_context_t **aead_slot; int ret; static const char *log_labels[2][4] = { - {NULL, "QUIC_CLIENT_EARLY_TRAFFIC_SECRET", "QUIC_CLIENT_HANDSHAKE_TRAFFIC_SECRET", "QUIC_CLIENT_TRAFFIC_SECRET_0"}, - {NULL, NULL, "QUIC_SERVER_HANDSHAKE_TRAFFIC_SECRET", "QUIC_SERVER_TRAFFIC_SECRET_0"}}; + {NULL, "CLIENT_EARLY_TRAFFIC_SECRET", "CLIENT_HANDSHAKE_TRAFFIC_SECRET", "CLIENT_TRAFFIC_SECRET_0"}, + {NULL, NULL, "SERVER_HANDSHAKE_TRAFFIC_SECRET", "SERVER_TRAFFIC_SECRET_0"}}; const char *log_label = log_labels[ptls_is_server(tls) == is_enc][epoch]; QUICLY_PROBE(CRYPTO_UPDATE_SECRET, conn, conn->stash.now, is_enc, epoch, log_label, From b0023cc5a6a213d9801d0c6a67748ce60957c002 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Mon, 22 Mar 2021 06:55:17 +0000 Subject: [PATCH 073/361] add appdata annotations to quicly-probes.d --- quicly-probes.d | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/quicly-probes.d b/quicly-probes.d index 2f5d8a54f..5547737f5 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -20,6 +20,24 @@ * IN THE SOFTWARE. */ +/* @appdata +{ + "receive": ["bytes"], + "packet_received": ["decrypted"], + "stream_on_receive": ["src"], + "new_token_send": ["token"], + "new_token_receive": ["token"], + "new_connection_id_send": ["stateless_reset_token"], + "new_connection_id_receive": ["stateless_reset_token"], + "datagram_send": ["payload"], + "datagram_receive": ["payload"], + "crypto_update_secret": ["secret"], + "crypto_send_key_update": ["secret"], + "crypto_receive_key_update": ["secret"], + "crypto_receive_key_update_prepare": ["secret"] +} +*/ + /** * Providers of quicly. Name of the arguments are important - they are used as the names of JSON fields when the dtrace script is * generated. From d3b3eeede11a248366ac862821b5d6db235c2a37 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Mon, 22 Mar 2021 06:55:39 +0000 Subject: [PATCH 074/361] add first_octet in quicly:receive probe --- lib/quicly.c | 4 ++-- quicly-probes.d | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 82ba62708..53d215a78 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5558,8 +5558,8 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka lock_now(conn, 0); QUICLY_PROBE(RECEIVE, conn, conn->stash.now, - QUICLY_PROBE_HEXDUMP(packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len), packet->octets.base, - packet->octets.len); + QUICLY_PROBE_HEXDUMP(packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len), packet->octects.base[0], + packet->octets.base, packet->octets.len); if (is_stateless_reset(conn, packet)) { ret = handle_stateless_reset(conn); diff --git a/quicly-probes.d b/quicly-probes.d index 5547737f5..dbaf36320 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -48,7 +48,7 @@ provider quicly { struct st_quicly_address_token_plaintext_t *address_token); probe free(struct st_quicly_conn_t *conn, int64_t at); probe send(struct st_quicly_conn_t *conn, int64_t at, int state, const char *dcid); - probe receive(struct st_quicly_conn_t *conn, int64_t at, const char *dcid, const void *bytes, size_t bytes_len); + probe receive(struct st_quicly_conn_t *conn, int64_t at, const char *dcid, uint8_t first_octet, const void *bytes, size_t bytes_len); probe version_switch(struct st_quicly_conn_t *conn, int64_t at, uint32_t new_version); probe idle_timeout(struct st_quicly_conn_t *conn, int64_t at); probe stateless_reset_receive(struct st_quicly_conn_t *conn, int64_t at); From c5f812e04669e2f3be038d6fea36b18c108459a0 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Tue, 23 Mar 2021 02:00:24 +0000 Subject: [PATCH 075/361] Revert "add first_octet in quicly:receive probe" This reverts commit d3b3eeede11a248366ac862821b5d6db235c2a37. --- lib/quicly.c | 4 ++-- quicly-probes.d | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 53d215a78..82ba62708 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5558,8 +5558,8 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka lock_now(conn, 0); QUICLY_PROBE(RECEIVE, conn, conn->stash.now, - QUICLY_PROBE_HEXDUMP(packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len), packet->octects.base[0], - packet->octets.base, packet->octets.len); + QUICLY_PROBE_HEXDUMP(packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len), packet->octets.base, + packet->octets.len); if (is_stateless_reset(conn, packet)) { ret = handle_stateless_reset(conn); diff --git a/quicly-probes.d b/quicly-probes.d index dbaf36320..5547737f5 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -48,7 +48,7 @@ provider quicly { struct st_quicly_address_token_plaintext_t *address_token); probe free(struct st_quicly_conn_t *conn, int64_t at); probe send(struct st_quicly_conn_t *conn, int64_t at, int state, const char *dcid); - probe receive(struct st_quicly_conn_t *conn, int64_t at, const char *dcid, uint8_t first_octet, const void *bytes, size_t bytes_len); + probe receive(struct st_quicly_conn_t *conn, int64_t at, const char *dcid, const void *bytes, size_t bytes_len); probe version_switch(struct st_quicly_conn_t *conn, int64_t at, uint32_t new_version); probe idle_timeout(struct st_quicly_conn_t *conn, int64_t at); probe stateless_reset_receive(struct st_quicly_conn_t *conn, int64_t at); From 5b7375b62d17da89b5e412e7e9b762624ee7aaad Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Tue, 23 Mar 2021 02:01:37 +0000 Subject: [PATCH 076/361] probes: these four are (or might be) transmitted on the wire --- quicly-probes.d | 5 ----- 1 file changed, 5 deletions(-) diff --git a/quicly-probes.d b/quicly-probes.d index 5547737f5..18fb9d408 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -22,13 +22,8 @@ /* @appdata { - "receive": ["bytes"], "packet_received": ["decrypted"], "stream_on_receive": ["src"], - "new_token_send": ["token"], - "new_token_receive": ["token"], - "new_connection_id_send": ["stateless_reset_token"], - "new_connection_id_receive": ["stateless_reset_token"], "datagram_send": ["payload"], "datagram_receive": ["payload"], "crypto_update_secret": ["secret"], From a924643282d6bca17c4ee2402fe9ce75e141b4ff Mon Sep 17 00:00:00 2001 From: FUJI Goro Date: Tue, 6 Apr 2021 10:22:53 +0900 Subject: [PATCH 077/361] add a hook to implement reference counting of quicly_context_t --- include/quicly.h | 9 +++++++++ lib/quicly.c | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/include/quicly.h b/include/quicly.h index 98190645c..dc20e7c73 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -155,6 +155,11 @@ QUICLY_CALLBACK_TYPE(int, generate_resumption_token, quicly_conn_t *conn, ptls_b * should in turn call one of the quicly_cc_*_init functions from cc.h with customized parameters. */ QUICLY_CALLBACK_TYPE(void, init_cc, quicly_cc_t *cc, uint32_t initcwnd, int64_t now); +/** + * reference counting. + * delta must be either 1 or -1. + */ +QUICLY_CALLBACK_TYPE(void, update_open_count, ssize_t delta); /** * crypto offload API */ @@ -333,6 +338,10 @@ struct st_quicly_context_t { * initializes a congestion controller for given connection. */ quicly_init_cc_t *init_cc; + /** + * optional refcount callback + */ + quicly_update_open_count_t *update_open_count; }; /** diff --git a/lib/quicly.c b/lib/quicly.c index 82ba62708..5df0a2e29 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1480,6 +1480,12 @@ static int received_key_update(quicly_conn_t *conn, uint64_t newly_decrypted_key } } +static inline void update_open_count(quicly_context_t *ctx, ssize_t delta) +{ + if (ctx->update_open_count != NULL) + ctx->update_open_count->cb(ctx->update_open_count, delta); +} + void quicly_free(quicly_conn_t *conn) { lock_now(conn, 0); @@ -1493,6 +1499,7 @@ void quicly_free(quicly_conn_t *conn) QUICLY_PROBE(CONN_STATS, conn, conn->stash.now, &stats, sizeof(stats)); } #endif + update_open_count(conn->super.ctx, -1); destroy_all_streams(conn, 0, 1); @@ -2046,6 +2053,8 @@ static quicly_conn_t *create_connection(quicly_context_t *ctx, uint32_t protocol *ptls_get_data_ptr(tls) = conn; + update_open_count(conn->super.ctx, 1); + return conn; } From 5d5eb5ed60c4b2fd4a73a49059c2277a78d57164 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 9 Apr 2021 08:51:20 +0900 Subject: [PATCH 078/361] release AEAD contexts when decryption fails --- lib/quicly.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/quicly.c b/lib/quicly.c index 82ba62708..99687a398 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5485,6 +5485,8 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * next_expected_pn = 0; /* is this correct? do we need to take care of underflow? */ if ((ret = decrypt_packet(ingress_cipher.header_protection, aead_decrypt_fixed_key, ingress_cipher.aead, &next_expected_pn, packet, &pn, &payload)) != 0) { + dispose_cipher(&ingress_cipher); + dispose_cipher(&egress_cipher); ret = QUICLY_ERROR_DECRYPTION_FAILED; goto Exit; } From 3d49d1d1dd498f042ab48e48fe755cde70928e3d Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 9 Apr 2021 09:57:51 +0900 Subject: [PATCH 079/361] use the exit path to dispose resources (and doing so takes care of the case when `create_connection` fails) --- lib/quicly.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 99687a398..b972f5d0a 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5455,7 +5455,10 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * const quicly_cid_plaintext_t *new_cid, ptls_handshake_properties_t *handshake_properties) { const struct st_ptls_salt_t *salt; - struct st_quicly_cipher_context_t ingress_cipher = {NULL}, egress_cipher = {NULL}; + struct { + struct st_quicly_cipher_context_t ingress, egress; + int alive; + } cipher = {}; ptls_iovec_t payload; uint64_t next_expected_pn, pn, offending_frame_type = QUICLY_FRAME_TYPE_PADDING; int is_ack_only, ret; @@ -5479,14 +5482,13 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * ret = QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; goto Exit; } - if ((ret = setup_initial_encryption(get_aes128gcmsha256(ctx), &ingress_cipher, &egress_cipher, packet->cid.dest.encrypted, 0, + if ((ret = setup_initial_encryption(get_aes128gcmsha256(ctx), &cipher.ingress, &cipher.egress, packet->cid.dest.encrypted, 0, ptls_iovec_init(salt->initial, sizeof(salt->initial)), NULL)) != 0) goto Exit; + cipher.alive = 1; next_expected_pn = 0; /* is this correct? do we need to take care of underflow? */ - if ((ret = decrypt_packet(ingress_cipher.header_protection, aead_decrypt_fixed_key, ingress_cipher.aead, &next_expected_pn, + if ((ret = decrypt_packet(cipher.ingress.header_protection, aead_decrypt_fixed_key, cipher.ingress.aead, &next_expected_pn, packet, &pn, &payload)) != 0) { - dispose_cipher(&ingress_cipher); - dispose_cipher(&egress_cipher); ret = QUICLY_ERROR_DECRYPTION_FAILED; goto Exit; } @@ -5510,10 +5512,9 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * if ((ret = setup_handshake_space_and_flow(*conn, QUICLY_EPOCH_INITIAL)) != 0) goto Exit; (*conn)->initial->super.next_expected_packet_number = next_expected_pn; - (*conn)->initial->cipher.ingress = ingress_cipher; - ingress_cipher = (struct st_quicly_cipher_context_t){NULL}; - (*conn)->initial->cipher.egress = egress_cipher; - egress_cipher = (struct st_quicly_cipher_context_t){NULL}; + (*conn)->initial->cipher.ingress = cipher.ingress; + (*conn)->initial->cipher.egress = cipher.egress; + cipher.alive = 0; (*conn)->crypto.handshake_properties.collected_extensions = server_collected_extensions; (*conn)->initial->largest_ingress_udp_payload_size = packet->datagram_size; @@ -5539,6 +5540,10 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * } unlock_now(*conn); } + if (cipher.alive) { + dispose_cipher(&cipher.ingress); + dispose_cipher(&cipher.egress); + } return ret; } From ef03c591479d06335e5e687bc8e679afc87308f6 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sun, 18 Apr 2021 16:46:31 +0900 Subject: [PATCH 080/361] follow API change in picotls/t/util.h --- deps/picotls | 2 +- src/cli.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deps/picotls b/deps/picotls index 66793743e..ea3e079d1 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit 66793743ec678bee8115144f911cd21d72172f7e +Subproject commit ea3e079d1616114b81a2d964e78cf7274e5d795b diff --git a/src/cli.c b/src/cli.c index 026d0fa5c..89e30d359 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1252,7 +1252,7 @@ int main(int argc, char **argv) } break; case 'V': - setup_verify_certificate(ctx.tls); + setup_verify_certificate(ctx.tls, NULL); break; case 'v': ++verbosity; From ee3331617e48a9a0d83a8ec05293b02353b5c129 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 4 May 2021 14:23:48 +0900 Subject: [PATCH 081/361] set `dest.plaintext` to invalid when encryptor is unavailable or when CIDL is zero --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index edb3d466e..511df4f0c 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -628,7 +628,7 @@ size_t quicly_decode_packet(quicly_context_t *ctx, quicly_decoded_packet_t *pack switch (packet->octets.base[0] & QUICLY_PACKET_TYPE_BITMASK) { case QUICLY_PACKET_TYPE_INITIAL: case QUICLY_PACKET_TYPE_0RTT: - if (ctx->cid_encryptor != NULL && packet->cid.dest.encrypted.len != 0 && + if (ctx->cid_encryptor == NULL || packet->cid.dest.encrypted.len == 0 || ctx->cid_encryptor->decrypt_cid(ctx->cid_encryptor, &packet->cid.dest.plaintext, packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len) == SIZE_MAX) packet->cid.dest.plaintext = quicly_cid_plaintext_invalid; From 884426233591fc4cf0f5e82de143fa78a099f024 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 4 May 2021 14:26:35 +0900 Subject: [PATCH 082/361] update doc --- include/quicly.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/quicly.h b/include/quicly.h index 75a45367d..c2b0d7684 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -679,10 +679,11 @@ typedef struct st_quicly_decoded_packet_t { */ ptls_iovec_t encrypted; /** - * The decrypted CID, or `quicly_cid_plaintext_invalid`. Assuming that `cid_decryptor` is non-NULL, this variable would + * The decrypted CID, or `quicly_cid_plaintext_invalid`. Assuming that `cid_encryptor` is non-NULL, this variable would * contain a valid value whenever `might_be_client_generated` is false. When `might_be_client_generated` is true, this * value might be set to `quicly_cid_plaintext_invalid`. Note however that, as the CID itself is not authenticated, * a packet might be bogus regardless of the value of the CID. + * When `cid_encryptor` is NULL, the value is always set to `quicly_cid_plaintext_invalid`. */ quicly_cid_plaintext_t plaintext; /** From bd497a6f7efdf4f58ec89daa193195800f5acffd Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sat, 15 May 2021 15:47:01 +0900 Subject: [PATCH 083/361] use PRIu64 for uint64_t --- misc/probe2trace.pl | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/misc/probe2trace.pl b/misc/probe2trace.pl index 2667de06a..6c7731652 100755 --- a/misc/probe2trace.pl +++ b/misc/probe2trace.pl @@ -122,12 +122,12 @@ my @fields; push @fields, map {["rtt.$_" => '%u']} qw(minimum smoothed variance); push @fields, map {["cc.$_" => '%u']} qw(impl->type cwnd ssthresh cwnd_initial cwnd_exiting_slow_start cwnd_minimum cwnd_maximum num_loss_episodes); - push @fields, map {["num_packets.$_" => '%llu']} qw(sent ack_received lost lost_time_threshold late_acked received decryption_failed); - push @fields, map {["num_bytes.$_" => '%llu']} qw(sent received); - for my $container (qw(num_frames_sent num_frames_received)) { - push @fields, map{["$container.$_" => '%llu']} qw(padding ping ack reset_stream stop_sending crypto new_token stream max_data max_stream_data max_streams_bidi max_streams_uni data_blocked stream_data_blocked streams_blocked new_connection_id retire_connection_id path_challenge path_response transport_close application_close handshake_done ack_frequency); - } - push @fields, ["num_ptos" => '%llu']; + push @fields, map {["num_packets.$_" => $arch eq 'embedded' ? '%" PRIu64 "' : '%llu']} qw(sent ack_received lost lost_time_threshold late_acked received decryption_failed); + push @fields, map {["num_bytes.$_" => $arch eq 'embedded' ? '%" PRIu64 "' : '%llu']} qw(sent received); + for my $container (qw(num_frames_sent num_frames_received)) { + push @fields, map{["$container.$_" => $arch eq 'embedded' ? '%" PRIu64 "' : '%llu']} qw(padding ping ack reset_stream stop_sending crypto new_token stream max_data max_stream_data max_streams_bidi max_streams_uni data_blocked stream_data_blocked streams_blocked new_connection_id retire_connection_id path_challenge path_response transport_close application_close handshake_done ack_frequency); + } + push @fields, ["num_ptos" => $arch eq 'embedded' ? '%" PRIu64 "' : '%llu']; # generate @fmt, @ap push @fmt, map {my $n = $_->[0]; $n =~ tr/./_/; sprintf '"%s":%s', $n, $_->[1]} @fields; if ($arch eq 'linux') { @@ -218,6 +218,7 @@ } else { my $fmt = join ', ', @fmt; $fmt =~ s/\"/\\\"/g; + $fmt =~ s/\%\\" ([A-Za-z0-9]+) \\"/\%" $1 "/g; # nasty hack to revert `"` -> `\"` right above for PRItNN print << "EOT"; #define QUICLY_@{[ uc $probe->[0] ]}_ENABLED() (quicly_trace_fp != NULL) From fc390276c5f4777b5e3b9aa94e35d7872fbc59f1 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sat, 15 May 2021 16:08:51 +0900 Subject: [PATCH 084/361] stream_id is signed --- include/quicly/frame.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/quicly/frame.h b/include/quicly/frame.h index c0ffc4653..42248892b 100644 --- a/include/quicly/frame.h +++ b/include/quicly/frame.h @@ -597,7 +597,7 @@ inline uint8_t *quicly_encode_stream_data_blocked_frame(uint8_t *dst, quicly_str inline int quicly_decode_stream_data_blocked_frame(const uint8_t **src, const uint8_t *end, quicly_stream_data_blocked_frame_t *frame) { - if ((frame->stream_id = quicly_decodev(src, end)) == UINT64_MAX) + if ((frame->stream_id = quicly_decodev(src, end)) == -1) goto Error; if ((frame->offset = quicly_decodev(src, end)) == UINT64_MAX) goto Error; From 0d36675f215556d509495c3f302031a717de63cd Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sat, 15 May 2021 16:09:51 +0900 Subject: [PATCH 085/361] sent->value is declared as `uint64_t:63` to conserve space, therefore, to avoid warning, explicitly promote to int64_t --- include/quicly/maxsender.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/quicly/maxsender.h b/include/quicly/maxsender.h index 23ebba360..cc0e9e2a7 100644 --- a/include/quicly/maxsender.h +++ b/include/quicly/maxsender.h @@ -112,7 +112,7 @@ inline void quicly_maxsender_record(quicly_maxsender_t *m, int64_t value, quicly inline void quicly_maxsender_acked(quicly_maxsender_t *m, quicly_maxsender_sent_t *sent) { - if (m->max_acked < sent->value) + if (m->max_acked < (int64_t)sent->value) m->max_acked = sent->value; /* num_inflight should not be adjusted in case of a late ACK */ if (sent->inflight) { From a2c81af7dd47ace8088764851379a68daad38408 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 17 May 2021 14:48:32 +0900 Subject: [PATCH 086/361] wrap help message at 80 columns --- src/cli.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/cli.c b/src/cli.c index 39e2e1614..3ff1f50dc 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1007,15 +1007,17 @@ static void usage(const char *cmd) "Options:\n" " -a ALPN identifier; repeat the option to set multiple\n" " candidates\n" - " -b specifies the size of the send / receive buffer in bytes\n" + " -b specifies the size of the send / receive buffer in\n" + " bytes\n" " -B CID encryption key (server-only). Randomly generated\n" " if omitted.\n" " -c certificate-file\n" " -k key-file specifies the credentials to be used for running the\n" " server. If omitted, the command runs as a client.\n" - " -C the congestion control algorithm; either \"reno\" (default) or\n" - " \"cubic\"\n" - " -d draft-number specifies the draft version number to be used (e.g., 29)\n" + " -C the congestion control algorithm; either \"reno\"\n" + " (default) or \"cubic\"\n" + " -d draft-number specifies the draft version number to be used (e.g.,\n" + " 29)\n" " -e event-log-file file to log events\n" " -E expand Client Hello (sends multiple client Initials)\n" " -G enable UDP generic segmentation offload\n" @@ -1029,7 +1031,8 @@ static void usage(const char *cmd) " -n enforce version negotiation (client-only)\n" " -O suppress output\n" " -p path path to request (can be set multiple times)\n" - " -P path path to request, store response to file (can be set multiple times)\n" + " -P path path to request, store response to file (can be set\n" + " multiple times)\n" " -R require Retry (server only)\n" " -r [initial-pto] initial PTO (in milliseconds)\n" " -S [num-speculative-ptos] number of speculative PTOs\n" @@ -1039,10 +1042,10 @@ static void usage(const char *cmd) " -V verify peer using the default certificates\n" " -v verbose mode (-vv emits packet dumps as well)\n" " -w packets initial congestion window (default: 10)\n" - " -W public-key-file use raw public keys (RFC 7250). When set and running as a\n" - " client, the argument specifies the public keys that the\n" - " server is expected to use. When running as a server, the\n" - " argument is ignored.\n" + " -W public-key-file use raw public keys (RFC 7250). When set and running\n" + " as a client, the argument specifies the public keys\n" + " that the server is expected to use. When running as\n" + " a server, the argument is ignored.\n" " -x named-group named group to be used (default: secp256r1)\n" " -X max bidirectional stream count (default: 100)\n" " -y cipher-suite cipher-suite to be used (default: all)\n" From 9fa67466feef7888788fbf3c57a880853069ecbd Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Thu, 27 May 2021 15:24:00 +0200 Subject: [PATCH 087/361] Using PROJECT_SOURCE_DIR in path to probe2trace.pl --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5142bacb0..49ed65eac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,7 +97,7 @@ TARGET_LINK_LIBRARIES(quicly LINK_PUBLIC m) ADD_CUSTOM_COMMAND( OUTPUT embedded-probes.h - COMMAND ${CMAKE_SOURCE_DIR}/misc/probe2trace.pl -a embedded < ${CMAKE_SOURCE_DIR}/quicly-probes.d > ${CMAKE_CURRENT_BINARY_DIR}/embedded-probes.h + COMMAND ${PROJECT_SOURCE_DIR}/misc/probe2trace.pl -a embedded < ${PROJECT_SOURCE_DIR}/quicly-probes.d > ${CMAKE_CURRENT_BINARY_DIR}/embedded-probes.h DEPENDS quicly-probes.d misc/probe2trace.pl VERBATIM) SET(CLI_FILES ${PICOTLS_OPENSSL_FILES} ${QUICLY_LIBRARY_FILES} src/cli.c embedded-probes.h) From 5c6cf04504e1aca571aa99c8b952d1e889236a7b Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sat, 29 May 2021 16:30:59 +0900 Subject: [PATCH 088/361] avoid UB, by skipping the operation to add token altogether --- lib/quicly.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 511df4f0c..16120f8c0 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3135,9 +3135,11 @@ static int _do_allocate_frame(quicly_conn_t *conn, quicly_send_context_t *s, siz /* token */ if (s->current.first_byte == QUICLY_PACKET_TYPE_INITIAL) { s->dst = quicly_encodev(s->dst, conn->token.len); - assert(s->dst_end - s->dst > conn->token.len); - memcpy(s->dst, conn->token.base, conn->token.len); - s->dst += conn->token.len; + if (conn->token.len != 0) { + assert(s->dst_end - s->dst > conn->token.len); + memcpy(s->dst, conn->token.base, conn->token.len); + s->dst += conn->token.len; + } } /* payload length is filled laterwards (see commit_send_packet) */ *s->dst++ = 0; From 5a88ee2fd34f8e39be2042b8da702a21496f38cd Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Mon, 14 Jun 2021 15:59:02 -0700 Subject: [PATCH 089/361] `quicly_sentmap_update` failing is a fatal error Make sure the error is propagated callers --- include/quicly/loss.h | 4 ++-- lib/loss.c | 15 ++++++++++----- lib/quicly.c | 27 +++++++++++++++++---------- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/include/quicly/loss.h b/include/quicly/loss.h index 389340ae9..e2af4a609 100644 --- a/include/quicly/loss.h +++ b/include/quicly/loss.h @@ -173,8 +173,8 @@ int quicly_loss_detect_loss(quicly_loss_t *r, int64_t now, uint32_t max_ack_dela /** * initializes the sentmap iterator, evicting the entries considered too old. */ -void quicly_loss_init_sentmap_iter(quicly_loss_t *loss, quicly_sentmap_iter_t *iter, int64_t now, uint32_t max_ack_delay, - int is_closing); +int quicly_loss_init_sentmap_iter(quicly_loss_t *loss, quicly_sentmap_iter_t *iter, int64_t now, uint32_t max_ack_delay, + int is_closing); /** * Returns the timeout for sentmap entries. This timeout is also used as the duration of CLOSING / DRAINING state, and therefore be * longer than 3PTO. At the moment, the value is 4PTO. diff --git a/lib/loss.c b/lib/loss.c index 3e11fa9c4..6655b2e11 100644 --- a/lib/loss.c +++ b/lib/loss.c @@ -21,8 +21,8 @@ */ #include "quicly/loss.h" -void quicly_loss_init_sentmap_iter(quicly_loss_t *loss, quicly_sentmap_iter_t *iter, int64_t now, uint32_t max_ack_delay, - int is_closing) +int quicly_loss_init_sentmap_iter(quicly_loss_t *loss, quicly_sentmap_iter_t *iter, int64_t now, uint32_t max_ack_delay, + int is_closing) { quicly_sentmap_init_iter(&loss->sentmap, iter); @@ -33,10 +33,13 @@ void quicly_loss_init_sentmap_iter(quicly_loss_t *loss, quicly_sentmap_iter_t *i * heavy loss; in such case, 32 is more than enough, yet small enough that the memory footprint does not matter. */ const quicly_sent_packet_t *sent; while ((sent = quicly_sentmap_get(iter))->sent_at <= retire_before && sent->cc_bytes_in_flight == 0) { + int ret; if (!is_closing && loss->sentmap.num_packets < 32) break; - quicly_sentmap_update(&loss->sentmap, iter, QUICLY_SENTMAP_EVENT_EXPIRED); + if ((ret = quicly_sentmap_update(&loss->sentmap, iter, QUICLY_SENTMAP_EVENT_EXPIRED)) != 0) + return ret; } + return 0; } int quicly_loss_detect_loss(quicly_loss_t *loss, int64_t now, uint32_t max_ack_delay, int is_1rtt_only, @@ -52,7 +55,8 @@ int quicly_loss_detect_loss(quicly_loss_t *loss, int64_t now, uint32_t max_ack_d loss->loss_time = INT64_MAX; - quicly_loss_init_sentmap_iter(loss, &iter, now, max_ack_delay, 0); + if ((ret = quicly_loss_init_sentmap_iter(loss, &iter, now, max_ack_delay, 0)) != 0) + return ret; /* Mark packets as lost if they are smaller than the largest_acked and outside either time-threshold or packet-threshold * windows. Once marked as lost, cc_bytes_in_flight becomes zero. */ @@ -79,7 +83,8 @@ int quicly_loss_detect_loss(quicly_loss_t *loss, int64_t now, uint32_t max_ack_d } if (!is_1rtt_only) { - quicly_loss_init_sentmap_iter(loss, &iter, now, max_ack_delay, 0); + if ((ret = quicly_loss_init_sentmap_iter(loss, &iter, now, max_ack_delay, 0)) != 0) + return ret; sent = quicly_sentmap_get(&iter); } diff --git a/lib/quicly.c b/lib/quicly.c index 16120f8c0..6efecf8fd 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -974,8 +974,11 @@ void crypto_stream_receive(quicly_stream_t *stream, size_t off, const void *src, if (conn->crypto.handshake_properties.client.early_data_acceptance == PTLS_EARLY_DATA_REJECTED) { dispose_cipher(&conn->application->cipher.egress.key); conn->application->cipher.egress.key = (struct st_quicly_cipher_context_t){NULL}; - discard_sentmap_by_epoch( - conn, 1u << QUICLY_EPOCH_1RTT); /* retire all packets with ack_epoch == 3; they are all 0-RTT packets */ + /* retire all packets with ack_epoch == 3; they are all 0-RTT packets */ + if (discard_sentmap_by_epoch(conn, 1u << QUICLY_EPOCH_1RTT) != 0) { + initiate_close(conn, QUICLY_TRANSPORT_ERROR_INTERNAL, QUICLY_FRAME_TYPE_CRYPTO, NULL); + goto Exit; + } } } } @@ -3540,19 +3543,21 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) return 0; } -static inline void init_acks_iter(quicly_conn_t *conn, quicly_sentmap_iter_t *iter) +static inline int init_acks_iter(quicly_conn_t *conn, quicly_sentmap_iter_t *iter) { - quicly_loss_init_sentmap_iter(&conn->egress.loss, iter, conn->stash.now, conn->super.remote.transport_params.max_ack_delay, - conn->super.state >= QUICLY_STATE_CLOSING); + return quicly_loss_init_sentmap_iter(&conn->egress.loss, iter, conn->stash.now, + conn->super.remote.transport_params.max_ack_delay, + conn->super.state >= QUICLY_STATE_CLOSING); } int discard_sentmap_by_epoch(quicly_conn_t *conn, unsigned ack_epochs) { quicly_sentmap_iter_t iter; const quicly_sent_packet_t *sent; - int ret = 0; + int ret; - init_acks_iter(conn, &iter); + if ((ret = init_acks_iter(conn, &iter)) != 0) + return ret; while ((sent = quicly_sentmap_get(&iter))->packet_number != UINT64_MAX) { if ((ack_epochs & (1u << sent->ack_epoch)) != 0) { @@ -3575,7 +3580,8 @@ static int mark_frames_on_pto(quicly_conn_t *conn, uint8_t ack_epoch, size_t *by const quicly_sent_packet_t *sent; int ret; - init_acks_iter(conn, &iter); + if ((ret = init_acks_iter(conn, &iter)) != 0) + return ret; while ((sent = quicly_sentmap_get(&iter))->packet_number != UINT64_MAX) { if (sent->ack_epoch == ack_epoch && sent->frames_in_flight) { @@ -4813,8 +4819,9 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload conn->egress.loss.sentmap.bytes_in_flight); /* loss-detection */ - quicly_loss_detect_loss(&conn->egress.loss, conn->stash.now, conn->super.remote.transport_params.max_ack_delay, - conn->initial == NULL && conn->handshake == NULL, on_loss_detected); + if ((ret = quicly_loss_detect_loss(&conn->egress.loss, conn->stash.now, conn->super.remote.transport_params.max_ack_delay, + conn->initial == NULL && conn->handshake == NULL, on_loss_detected)) != 0) + return ret; update_loss_alarm(conn, 0); return 0; From 30d8024baa570af48d5147678e1b0fdaabb7800f Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Mon, 14 Jun 2021 17:39:28 -0700 Subject: [PATCH 090/361] It is the responsibility of initiate_close function to convert the error code to an appropriate value. Co-authored-by: Kazuho Oku --- lib/quicly.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 6efecf8fd..a8e2017e8 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -975,8 +975,9 @@ void crypto_stream_receive(quicly_stream_t *stream, size_t off, const void *src, dispose_cipher(&conn->application->cipher.egress.key); conn->application->cipher.egress.key = (struct st_quicly_cipher_context_t){NULL}; /* retire all packets with ack_epoch == 3; they are all 0-RTT packets */ - if (discard_sentmap_by_epoch(conn, 1u << QUICLY_EPOCH_1RTT) != 0) { - initiate_close(conn, QUICLY_TRANSPORT_ERROR_INTERNAL, QUICLY_FRAME_TYPE_CRYPTO, NULL); + int ret; + if ((ret = discard_sentmap_by_epoch(conn, 1u << QUICLY_EPOCH_1RTT)) != 0) { + initiate_close(conn, ret, QUICLY_FRAME_TYPE_CRYPTO, NULL); goto Exit; } } From 391e49c4cf2c64a5629dda3884ff38d85d63f41b Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 15 Jun 2021 10:41:51 +0900 Subject: [PATCH 091/361] set minimum fragments relative to stream-level concurrency --- lib/quicly.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index a8e2017e8..5f37a3394 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1020,11 +1020,15 @@ static void init_stream_properties(quicly_stream_t *stream, uint32_t initial_max /* Set the number of max ranges to be capable of handling following case: * * every one of the two packets being sent are lost - * * average size of a STREAM frame found in a packet is >= ~512 bytes + * * average size of a STREAM frame found in a packet is >= ~512 bytes, or small STREAM frame is sent for every other stream + * being opened (e.g., sending QPACK encoder/decoder stream frame for each HTTP/3 request) * See also: the doc-comment on `_recv_aux.max_ranges`. */ - if ((stream->_recv_aux.max_ranges = initial_max_stream_data_local / 1024) < 63) - stream->_recv_aux.max_ranges = 63; + uint32_t fragments_minmax = (uint32_t)(stream->conn->super.ctx->transport_params.max_streams_uni + stream->conn->super.ctx->transport_params.max_streams_bidi); + if (fragments_minmax < 63) + fragments_minmax = 63; + if ((stream->_recv_aux.max_ranges = initial_max_stream_data_local / 1024) < fragments_minmax) + stream->_recv_aux.max_ranges = fragments_minmax; } static void dispose_stream_properties(quicly_stream_t *stream) From eb36d245f6b733baa8bad4c7bf82888b5c6fc2b3 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 15 Jun 2021 10:43:08 +0900 Subject: [PATCH 092/361] relax the state restriction --- lib/sendstate.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/sendstate.c b/lib/sendstate.c index 35ff0e8f8..96cde7696 100644 --- a/lib/sendstate.c +++ b/lib/sendstate.c @@ -98,8 +98,12 @@ static int check_amount_of_state(quicly_sendstate_t *state) { size_t num_ranges = state->acked.num_ranges + state->pending.num_ranges; - /* bail out if number of gaps are small */ - if (PTLS_LIKELY(num_ranges < 32)) + /* Bail out if number of gaps are small. + * In case of HTTP/3, the worst case is when each HTTP request is received as a separate QUIC packet, and sending a small STREAM + * frame carrying a HPACK encoder / decoder in response. If half of those STREAM frames are lost (note: loss of every other + * packet can happen during slow start), `num_ranges` can become as large as `request_concurrency * 2`, as each gaps will be + * recognized in `acked.num_ranges` and `pending.num_ranges`. */ + if (PTLS_LIKELY(num_ranges < 256)) return 0; /* When there are large number of gaps, make sure that the amount of state retained in quicly is relatively smaller than the @@ -107,8 +111,8 @@ static int check_amount_of_state(quicly_sendstate_t *state) * assumption that the STREAM frames that have been sent are on average at least 512 bytes long, when seeing excess number of * gaps. */ int64_t bytes_buffered = (int64_t)state->size_inflight - (int64_t)state->acked.ranges[0].end; - if ((int64_t)num_ranges * 512 > bytes_buffered) - return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; + if ((int64_t)num_ranges * 128 > bytes_buffered) + return QUICLY_ERROR_STATE_EXHAUSTION; return 0; } From 068a21a4a9dd2a69f1f74f944853a5f879c8f02b Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 15 Jun 2021 14:03:51 +0900 Subject: [PATCH 093/361] clang-format --- lib/quicly.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 5f37a3394..651aa0527 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1024,7 +1024,8 @@ static void init_stream_properties(quicly_stream_t *stream, uint32_t initial_max * being opened (e.g., sending QPACK encoder/decoder stream frame for each HTTP/3 request) * See also: the doc-comment on `_recv_aux.max_ranges`. */ - uint32_t fragments_minmax = (uint32_t)(stream->conn->super.ctx->transport_params.max_streams_uni + stream->conn->super.ctx->transport_params.max_streams_bidi); + uint32_t fragments_minmax = (uint32_t)(stream->conn->super.ctx->transport_params.max_streams_uni + + stream->conn->super.ctx->transport_params.max_streams_bidi); if (fragments_minmax < 63) fragments_minmax = 63; if ((stream->_recv_aux.max_ranges = initial_max_stream_data_local / 1024) < fragments_minmax) From 56ecc220dd17eccec1fd40745a8c49482d3a4791 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 16 Jun 2021 14:11:21 +0900 Subject: [PATCH 094/361] exempt DATAGRAM frame from CC (as we have promised) --- lib/quicly.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 651aa0527..3156d221d 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3070,7 +3070,13 @@ static inline uint8_t *emit_cid(uint8_t *dst, const quicly_cid_t *cid) return dst; } -static int _do_allocate_frame(quicly_conn_t *conn, quicly_send_context_t *s, size_t min_space, int ack_eliciting) +enum allocate_frame_type { + ALLOCATE_FRAME_TYPE_NON_ACK_ELICITING, + ALLOCATE_FRAME_TYPE_ACK_ELICITING, + ALLOCATE_FRAME_TYPE_ACK_ELICITING_NO_CC, +}; + +static int do_allocate_frame(quicly_conn_t *conn, quicly_send_context_t *s, size_t min_space, enum allocate_frame_type frame_type) { int coalescible, ret; @@ -3119,7 +3125,7 @@ static int _do_allocate_frame(quicly_conn_t *conn, quicly_send_context_t *s, siz if (s->num_datagrams >= s->max_datagrams) return QUICLY_ERROR_SENDBUF_FULL; /* note: send_window (ssize_t) can become negative; see doc-comment */ - if (ack_eliciting && s->send_window <= 0) + if (frame_type == ALLOCATE_FRAME_TYPE_ACK_ELICITING && s->send_window <= 0) return QUICLY_ERROR_SENDBUF_FULL; if (s->payload_buf.end - s->payload_buf.datagram < conn->egress.max_udp_payload_size) return QUICLY_ERROR_SENDBUF_FULL; @@ -3188,24 +3194,19 @@ static int _do_allocate_frame(quicly_conn_t *conn, quicly_send_context_t *s, siz } TargetReady: - if (ack_eliciting) { + if (frame_type != ALLOCATE_FRAME_TYPE_NON_ACK_ELICITING) { s->target.ack_eliciting = 1; conn->egress.last_retransmittable_sent_at = conn->stash.now; } return 0; } -static int allocate_frame(quicly_conn_t *conn, quicly_send_context_t *s, size_t min_space) -{ - return _do_allocate_frame(conn, s, min_space, 0); -} - static int allocate_ack_eliciting_frame(quicly_conn_t *conn, quicly_send_context_t *s, size_t min_space, quicly_sent_t **sent, quicly_sent_acked_cb acked) { int ret; - if ((ret = _do_allocate_frame(conn, s, min_space, 1)) != 0) + if ((ret = do_allocate_frame(conn, s, min_space, ALLOCATE_FRAME_TYPE_ACK_ELICITING)) != 0) return ret; if ((*sent = quicly_sentmap_allocate(&conn->egress.loss.sentmap, acked)) == NULL) return PTLS_ERROR_NO_MEMORY; @@ -3231,7 +3232,7 @@ static int send_ack(quicly_conn_t *conn, struct st_quicly_pn_space_t *space, qui } Emit: /* emit an ACK frame */ - if ((ret = allocate_frame(conn, s, QUICLY_ACK_FRAME_CAPACITY)) != 0) + if ((ret = do_allocate_frame(conn, s, QUICLY_ACK_FRAME_CAPACITY, ALLOCATE_FRAME_TYPE_NON_ACK_ELICITING)) != 0) return ret; uint8_t *dst = s->dst; dst = quicly_encode_ack_frame(dst, s->dst_end, &space->ack_queue, ack_delay); @@ -3976,7 +3977,7 @@ static int send_handshake_flow(quicly_conn_t *conn, size_t epoch, quicly_send_co /* send probe if requested */ if (send_probe) { - if ((ret = _do_allocate_frame(conn, s, 1, 1)) != 0) + if ((ret = do_allocate_frame(conn, s, 1, ALLOCATE_FRAME_TYPE_ACK_ELICITING)) != 0) goto Exit; *s->dst++ = QUICLY_FRAME_TYPE_PING; conn->egress.last_retransmittable_sent_at = conn->stash.now; @@ -4015,7 +4016,8 @@ static int send_connection_close(quicly_conn_t *conn, size_t epoch, quicly_send_ } /* write frame */ - if ((ret = allocate_frame(conn, s, quicly_close_frame_capacity(error_code, offending_frame_type, reason_phrase))) != 0) + if ((ret = do_allocate_frame(conn, s, quicly_close_frame_capacity(error_code, offending_frame_type, reason_phrase), + ALLOCATE_FRAME_TYPE_NON_ACK_ELICITING)) != 0) return ret; s->dst = quicly_encode_close_frame(s->dst, error_code, offending_frame_type, reason_phrase); @@ -4241,7 +4243,7 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) for (size_t i = 0; i != conn->egress.datagram_frame_payloads.count; ++i) { ptls_iovec_t *payload = conn->egress.datagram_frame_payloads.payloads + i; size_t required_space = quicly_datagram_frame_capacity(*payload); - if ((ret = _do_allocate_frame(conn, s, required_space, 1)) != 0) + if ((ret = do_allocate_frame(conn, s, required_space, ALLOCATE_FRAME_TYPE_ACK_ELICITING_NO_CC)) != 0) goto Exit; if (s->dst_end - s->dst >= required_space) { s->dst = quicly_encode_datagram_frame(s->dst, *payload); @@ -4256,7 +4258,7 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) if (!ack_only) { /* PTO or loss detection timeout, always send PING. This is the easiest thing to do in terms of timer control. */ if (min_packets_to_send != 0) { - if ((ret = _do_allocate_frame(conn, s, 1, 1)) != 0) + if ((ret = do_allocate_frame(conn, s, 1, ALLOCATE_FRAME_TYPE_ACK_ELICITING)) != 0) goto Exit; *s->dst++ = QUICLY_FRAME_TYPE_PING; ++conn->super.stats.num_frames_sent.ping; @@ -4280,7 +4282,8 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) if (conn->egress.path_challenge.head != NULL) { do { struct st_quicly_pending_path_challenge_t *c = conn->egress.path_challenge.head; - if ((ret = allocate_frame(conn, s, QUICLY_PATH_CHALLENGE_FRAME_CAPACITY)) != 0) + if ((ret = do_allocate_frame(conn, s, QUICLY_PATH_CHALLENGE_FRAME_CAPACITY, + ALLOCATE_FRAME_TYPE_NON_ACK_ELICITING)) != 0) goto Exit; s->dst = quicly_encode_path_challenge_frame(s->dst, c->is_response, c->data); if (c->is_response) { From d99de847b0aec6c1e0b50dc61b3989a6ff75258d Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 17 Jun 2021 16:16:30 +0900 Subject: [PATCH 095/361] add API to obtain number of streams per type --- include/quicly.h | 4 ++++ lib/quicly.c | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/include/quicly.h b/include/quicly.h index c2b0d7684..30ac27232 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -810,6 +810,10 @@ int quicly_connection_is_ready(quicly_conn_t *conn); * */ static uint32_t quicly_num_streams(quicly_conn_t *conn); +/** + * + */ +uint32_t quicly_num_streams_by_group(quicly_conn_t *conn, int uni, int locally_initiated); /** * */ diff --git a/lib/quicly.c b/lib/quicly.c index 651aa0527..ddc899c13 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1172,6 +1172,13 @@ ptls_t *quicly_get_tls(quicly_conn_t *conn) return conn->crypto.tls; } +uint32_t quicly_num_streams_by_group(quicly_conn_t *conn, int uni, int locally_initiated) +{ + int server_initiated = quicly_is_client(conn) != locally_initiated; + struct st_quicly_conn_streamgroup_state_t *state = get_streamgroup_state(conn, uni * 2 + server_initiated); + return state->num_streams; +} + int quicly_get_stats(quicly_conn_t *conn, quicly_stats_t *stats) { /* copy the pre-built stats fields */ From 8dd4090232a556e1b54682fcefee1cf4a6932730 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 17 Jun 2021 16:16:55 +0900 Subject: [PATCH 096/361] add API for self-tracing --- CMakeLists.txt | 17 +++++++--- include/quicly.h | 11 +++++++ lib/quicly.c | 19 ++++++++--- misc/probe2trace.pl | 54 +++++++++++++++++++++++++------- quicly.xcodeproj/project.pbxproj | 28 +++++++++++++++++ 5 files changed, 108 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 49ed65eac..4cc2524f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ OPTION(WITH_FUSION "whether or not to use the Fusion AES-GCM engine in the cli b IF(NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE Release) ENDIF(NOT CMAKE_BUILD_TYPE) -SET(CMAKE_C_FLAGS "-std=c99 -Wall -g ${CC_WARNING_FLAGS} ${CMAKE_C_FLAGS}") +SET(CMAKE_C_FLAGS "-std=c99 -Wall -g -DQUICLY_USE_TRACER=1 ${CC_WARNING_FLAGS} ${CMAKE_C_FLAGS}") SET(CMAKE_C_FLAGS_DEBUG "-O0") SET(CMAKE_C_FLAGS_RELEASE "-O2") @@ -61,7 +61,8 @@ SET(QUICLY_LIBRARY_FILES lib/retire_cid.c lib/sendstate.c lib/sentmap.c - lib/streambuf.c) + lib/streambuf.c + ${CMAKE_CURRENT_BINARY_DIR}/quicly-tracer.h) SET(UNITTEST_SOURCE_FILES deps/picotest/picotest.c @@ -92,14 +93,20 @@ IF (WITH_DTRACE) ENDIF () ENDIF () -ADD_LIBRARY(quicly ${QUICLY_LIBRARY_FILES}) -TARGET_LINK_LIBRARIES(quicly LINK_PUBLIC m) - ADD_CUSTOM_COMMAND( OUTPUT embedded-probes.h COMMAND ${PROJECT_SOURCE_DIR}/misc/probe2trace.pl -a embedded < ${PROJECT_SOURCE_DIR}/quicly-probes.d > ${CMAKE_CURRENT_BINARY_DIR}/embedded-probes.h DEPENDS quicly-probes.d misc/probe2trace.pl VERBATIM) +ADD_CUSTOM_COMMAND( + OUTPUT quicly-tracer.h + COMMAND ${PROJECT_SOURCE_DIR}/misc/probe2trace.pl -a tracer < ${PROJECT_SOURCE_DIR}/quicly-probes.d > ${CMAKE_CURRENT_BINARY_DIR}/quicly-tracer.h + DEPENDS quicly-probes.d misc/probe2trace.pl + VERBATIM) + +ADD_LIBRARY(quicly ${QUICLY_LIBRARY_FILES}) +TARGET_LINK_LIBRARIES(quicly LINK_PUBLIC m) + SET(CLI_FILES ${PICOTLS_OPENSSL_FILES} ${QUICLY_LIBRARY_FILES} src/cli.c embedded-probes.h) SET(CLI_COMPILE_FLAGS "-DQUICLY_USE_EMBEDDED_PROBES=1") IF (WITH_FUSION) diff --git a/include/quicly.h b/include/quicly.h index 30ac27232..e4a916a78 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -160,6 +160,7 @@ QUICLY_CALLBACK_TYPE(void, init_cc, quicly_cc_t *cc, uint32_t initcwnd, int64_t * delta must be either 1 or -1. */ QUICLY_CALLBACK_TYPE(void, update_open_count, ssize_t delta); + /** * crypto offload API */ @@ -191,6 +192,12 @@ typedef struct st_quicly_crypto_engine_t { size_t payload_from, uint64_t packet_number, int coalesced); } quicly_crypto_engine_t; +typedef void (*quicly_trace_cb)(quicly_conn_t *conn, const char *fmt, ...) __attribute__((format(printf, 2, 3))); +/** + * Returns the tracer callback + */ +QUICLY_CALLBACK_TYPE(quicly_trace_cb, get_tracer, quicly_conn_t *conn); + typedef struct st_quicly_max_stream_data_t { uint64_t bidi_local, bidi_remote, uni; } quicly_max_stream_data_t; @@ -338,6 +345,10 @@ struct st_quicly_context_t { * optional refcount callback */ quicly_update_open_count_t *update_open_count; + /** + * optional callback + */ + quicly_get_tracer_t *get_tracer; }; /** diff --git a/lib/quicly.c b/lib/quicly.c index ddc899c13..ca383c8a2 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -75,13 +75,23 @@ KHASH_MAP_INIT_INT64(quicly_stream_t, quicly_stream_t *) +#if QUICLY_USE_TRACER +#define QUICLY_TRACER(label, conn, ...) QUICLY_TRACER_##label(conn, __VA_ARGS__) +#else +#define QUICLY_TRACER(...) +#endif + #if QUICLY_USE_EMBEDDED_PROBES || QUICLY_USE_DTRACE #define QUICLY_PROBE(label, conn, ...) \ do { \ quicly_conn_t *_conn = (conn); \ if (PTLS_UNLIKELY(QUICLY_##label##_ENABLED()) && !ptls_skip_tracing(_conn->crypto.tls)) \ QUICLY_##label(_conn, __VA_ARGS__); \ + QUICLY_TRACER(label, _conn, __VA_ARGS__); \ } while (0) +#else +#define QUICLY_PROBE(label, conn, ...) QUICLY_TRACER(label, conn, __VA_ARGS__) +#endif #define QUICLY_PROBE_HEXDUMP(s, l) \ ({ \ size_t _l = (l); \ @@ -92,11 +102,6 @@ KHASH_MAP_INIT_INT64(quicly_stream_t, quicly_stream_t *) size_t _l = (l); \ quicly_escape_unsafe_string(alloca(_l * 4 + 1), (s), _l); \ }) -#else -#define QUICLY_PROBE(label, conn, ...) -#define QUICLY_PROBE_HEXDUMP(s, l) -#define QUICLY_PROBE_ESCAPE_UNSAFE_STRING(s, l) -#endif struct st_quicly_cipher_context_t { ptls_aead_context_t *aead; @@ -407,6 +412,10 @@ struct st_quicly_conn_t { } stash; }; +#if QUICLY_USE_TRACER +#include "quicly-tracer.h" +#endif + struct st_quicly_handle_payload_state_t { const uint8_t *src, *const end; size_t epoch; diff --git a/misc/probe2trace.pl b/misc/probe2trace.pl index 6c7731652..aa9799e2c 100755 --- a/misc/probe2trace.pl +++ b/misc/probe2trace.pl @@ -7,6 +7,7 @@ use Getopt::Long; my $arch = $^O; +my %tracer_probes = map { uc($_) => 1 } qw(packet_sent packet_received packet_prepare packet_acked packet_lost packet_decryption_failed pto cc_ack_received cc_congestion max_data_send max_data_receive max_stream_data_send max_stream_data_receive streams_blocked_send streams_blocked_receive stream_on_open stream_on_destroy); GetOptions("arch=s" => \$arch) or die "invalid command option\n"; @@ -73,12 +74,18 @@ EOT } elsif ($arch eq 'darwin') { -} else { +} elsif ($arch eq 'embedded') { print << 'EOT'; #ifndef embedded_probes_h #define embedded_probes_h extern FILE *quicly_trace_fp; +EOT +} else { + print << 'EOT'; +#ifndef callback_probes_h +#define callback_probes_h + EOT } @@ -91,13 +98,15 @@ for (my $i = 0; $i < @{$probe->[1]}; ++$i) { my ($name, $type) = @{$probe->[1]->[$i]}; if ($type eq 'struct st_quicly_conn_t *') { - push @fmt, '"conn":%u'; - if ($arch eq 'linux') { - push @ap, "arg$i" . ' != NULL ? ((struct st_quicly_conn_t *)arg' . $i . ')->master_id : 0'; - } elsif ($arch eq 'darwin') { - push @ap, "arg$i" . ' != NULL ? *(uint32_t *)copyin(arg' . $i . ' + 16, 4) : 0'; - } else { - push @ap, "arg$i != NULL ? ((struct _st_quicly_conn_public_t *)arg$i)->local.cid_set.plaintext.master_id : 0"; + if ($arch ne 'tracer') { + push @fmt, '"conn":%u'; + if ($arch eq 'linux') { + push @ap, "arg$i" . ' != NULL ? ((struct st_quicly_conn_t *)arg' . $i . ')->master_id : 0'; + } elsif ($arch eq 'darwin') { + push @ap, "arg$i" . ' != NULL ? *(uint32_t *)copyin(arg' . $i . ' + 16, 4) : 0'; + } else { + push @ap, "arg$i != NULL ? ((struct _st_quicly_conn_public_t *)arg$i)->local.cid_set.plaintext.master_id : 0"; + } } } elsif ($type eq 'struct st_quicly_stream_t *') { push @fmt, '"stream-id":%d'; @@ -219,19 +228,42 @@ my $fmt = join ', ', @fmt; $fmt =~ s/\"/\\\"/g; $fmt =~ s/\%\\" ([A-Za-z0-9]+) \\"/\%" $1 "/g; # nasty hack to revert `"` -> `\"` right above for PRItNN - print << "EOT"; + my $params = join ", ", map { "$probe->[1]->[$_]->[1] arg$_" } 0..$#{$probe->[1]}; + if ($arch eq 'embedded') { + print << "EOT"; #define QUICLY_@{[ uc $probe->[0] ]}_ENABLED() (quicly_trace_fp != NULL) -static void QUICLY_@{[ uc $probe->[0] ]}(@{[ join ", ", map { "$probe->[1]->[$_]->[1] arg$_" } 0..$#{$probe->[1]}]}) +static void QUICLY_@{[ uc $probe->[0] ]}($params) { fprintf(quicly_trace_fp, "{$fmt}\\n", @{[join ', ', @ap]}); } EOT + } else { + # callback probes, the ones not specified are no-op + if ($tracer_probes{uc $probe->[0]}) { + print << "EOT"; + +static inline void QUICLY_TRACER_@{[ uc $probe->[0] ]}($params) +{ + if (arg0->super.ctx->get_tracer != NULL) { + quicly_trace_cb tracer = arg0->super.ctx->get_tracer->cb(arg0->super.ctx->get_tracer, arg0); + if (tracer != NULL) + tracer(arg0, "{$fmt}\\n", @{[join ', ', @ap]}); + } +} +EOT + } else { + print << "EOT"; + +#define QUICLY_TRACER_@{[uc $probe->[0] ]}(...) +EOT + } + } } } -if ($arch eq 'embedded') { +if ($arch eq 'embedded' || $arch eq 'tracer') { print << 'EOT'; #endif diff --git a/quicly.xcodeproj/project.pbxproj b/quicly.xcodeproj/project.pbxproj index da8de6ed9..65ad024ea 100644 --- a/quicly.xcodeproj/project.pbxproj +++ b/quicly.xcodeproj/project.pbxproj @@ -526,6 +526,7 @@ isa = PBXNativeTarget; buildConfigurationList = E984481B1EA48BD400390927 /* Build configuration list for PBXNativeTarget "quicly" */; buildPhases = ( + 08CEA9DF267B461700B4BB6B /* ShellScript */, E98448131EA48BD400390927 /* Sources */, E98448141EA48BD400390927 /* Frameworks */, E98448151EA48BD400390927 /* Headers */, @@ -632,6 +633,25 @@ /* End PBXProject section */ /* Begin PBXShellScriptBuildPhase section */ + 08CEA9DF267B461700B4BB6B /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "$(SRCROOT)/quicly-probes.d", + ); + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILES_DIR)/quicly-cbp-probes.h", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\nexec $SRCROOT/misc/probe2trace.pl -a tracer < $SRCROOT/quicly-probes.d > $DERIVED_FILES_DIR/quicly-tracer.h\n"; + }; E941428B23B0B70F002D3CE0 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -899,6 +919,10 @@ isa = XCBuildConfiguration; buildSettings = { EXECUTABLE_PREFIX = lib; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "QUICLY_USE_TRACER=1", + ); PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -907,6 +931,10 @@ isa = XCBuildConfiguration; buildSettings = { EXECUTABLE_PREFIX = lib; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "QUICLY_USE_TRACER=1", + ); PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; From 7361ca5b755ed95e36334596acf26a7c7b0945c6 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 17 Jun 2021 19:58:29 +0900 Subject: [PATCH 097/361] fix filename --- quicly.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quicly.xcodeproj/project.pbxproj b/quicly.xcodeproj/project.pbxproj index 65ad024ea..91050d834 100644 --- a/quicly.xcodeproj/project.pbxproj +++ b/quicly.xcodeproj/project.pbxproj @@ -646,7 +646,7 @@ outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILES_DIR)/quicly-cbp-probes.h", + "$(DERIVED_FILES_DIR)/quicly-tracer.h", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; From b2fddb922daaa12d4e6a2ac51ff05d0cc255c4ef Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 17 Jun 2021 21:11:43 +0900 Subject: [PATCH 098/361] maybe we can reduce one event --- misc/probe2trace.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/probe2trace.pl b/misc/probe2trace.pl index aa9799e2c..918d484f6 100755 --- a/misc/probe2trace.pl +++ b/misc/probe2trace.pl @@ -7,7 +7,7 @@ use Getopt::Long; my $arch = $^O; -my %tracer_probes = map { uc($_) => 1 } qw(packet_sent packet_received packet_prepare packet_acked packet_lost packet_decryption_failed pto cc_ack_received cc_congestion max_data_send max_data_receive max_stream_data_send max_stream_data_receive streams_blocked_send streams_blocked_receive stream_on_open stream_on_destroy); +my %tracer_probes = map { uc($_) => 1 } qw(packet_sent packet_received packet_acked packet_lost packet_decryption_failed pto cc_ack_received cc_congestion max_data_send max_data_receive max_stream_data_send max_stream_data_receive streams_blocked_send streams_blocked_receive stream_on_open stream_on_destroy); GetOptions("arch=s" => \$arch) or die "invalid command option\n"; From 20e04f932f481ea1063627ad85c73af0c2ad70d4 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 17 Jun 2021 21:25:15 +0900 Subject: [PATCH 099/361] fix type specifier --- misc/probe2trace.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/probe2trace.pl b/misc/probe2trace.pl index 918d484f6..f7c9ae5af 100755 --- a/misc/probe2trace.pl +++ b/misc/probe2trace.pl @@ -160,7 +160,7 @@ push @ap, "(unsigned long long)arg$i"; } } elsif ($type =~ /^int(?:([0-9]+)_t|)$/) { - if ($arch ne 'embedded') { + if ($arch ne 'embedded' && $arch ne 'tracer') { push @fmt, qq!"$name":\%@{[$1 && $1 == 64 ? 'ld' : 'd']}!; push @ap, "arg$i"; } else { From 819611da000d33b386cdab92b0dea5f2dfddfcfd Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 17 Jun 2021 21:25:22 +0900 Subject: [PATCH 100/361] configure at the instance level --- include/quicly.h | 34 +++++++++++++++++++++++++++------- misc/probe2trace.pl | 7 ++----- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index e4a916a78..adbc992bf 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -192,11 +192,19 @@ typedef struct st_quicly_crypto_engine_t { size_t payload_from, uint64_t packet_number, int coalesced); } quicly_crypto_engine_t; -typedef void (*quicly_trace_cb)(quicly_conn_t *conn, const char *fmt, ...) __attribute__((format(printf, 2, 3))); /** - * Returns the tracer callback + * data structure used for self-tracing */ -QUICLY_CALLBACK_TYPE(quicly_trace_cb, get_tracer, quicly_conn_t *conn); +typedef struct st_quicly_tracer_t { + /** + * NULL when not used + */ + void (*cb)(void *ctx, const char *fmt, ...) __attribute__((format(printf, 2, 3))); + /** + * + */ + void *ctx; +} quicly_tracer_t; typedef struct st_quicly_max_stream_data_t { uint64_t bidi_local, bidi_remote, uni; @@ -345,10 +353,6 @@ struct st_quicly_context_t { * optional refcount callback */ quicly_update_open_count_t *update_open_count; - /** - * optional callback - */ - quicly_get_tracer_t *get_tracer; }; /** @@ -470,6 +474,8 @@ struct st_quicly_default_scheduler_state_t { quicly_linklist_t blocked; }; +typedef void (*quicly_trace_cb)(void *ctx, const char *fmt, ...) __attribute__((format(printf, 2, 3))); + struct _st_quicly_conn_public_t { quicly_context_t *ctx; quicly_state_t state; @@ -525,6 +531,10 @@ struct _st_quicly_conn_public_t { } stats; uint32_t version; void *data; + /** + * trace callback (cb != NULL when used) + */ + quicly_tracer_t tracer; }; typedef enum { @@ -857,6 +867,10 @@ void quicly_get_max_data(quicly_conn_t *conn, uint64_t *send_permitted, uint64_t * */ static void **quicly_get_data(quicly_conn_t *conn); +/** + * + */ +static quicly_tracer_t *quicly_get_tracer(quicly_conn_t *conn); /** * destroys a connection object. */ @@ -1245,6 +1259,12 @@ inline void **quicly_get_data(quicly_conn_t *conn) return &c->data; } +inline quicly_tracer_t *quicly_get_tracer(quicly_conn_t *conn) +{ + struct _st_quicly_conn_public_t *c = (struct _st_quicly_conn_public_t *)conn; + return &c->tracer; +} + inline int quicly_stop_requested(quicly_stream_t *stream) { return stream->_send_aux.stop_sending.sender_state != QUICLY_SENDER_STATE_NONE; diff --git a/misc/probe2trace.pl b/misc/probe2trace.pl index f7c9ae5af..cee5e2baf 100755 --- a/misc/probe2trace.pl +++ b/misc/probe2trace.pl @@ -246,11 +246,8 @@ static inline void QUICLY_TRACER_@{[ uc $probe->[0] ]}($params) { - if (arg0->super.ctx->get_tracer != NULL) { - quicly_trace_cb tracer = arg0->super.ctx->get_tracer->cb(arg0->super.ctx->get_tracer, arg0); - if (tracer != NULL) - tracer(arg0, "{$fmt}\\n", @{[join ', ', @ap]}); - } + if (arg0->super.tracer.cb != NULL) + arg0->super.tracer.cb(arg0->super.tracer.ctx, "{$fmt}\\n", @{[join ', ', @ap]}); } EOT } else { From 11aed7925421d4420be4b4429846f764669d44d0 Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Thu, 17 Jun 2021 16:29:26 -0700 Subject: [PATCH 101/361] quicly_receive: do not try to cleanly shutdown connections on fatal errors On fatal errors, it's possible that the sentmap has been left in an unusable state (see https://github.com/h2o/quicly/pull/462) When these happen, let the application deal with the fatal error. --- lib/quicly.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/quicly.c b/lib/quicly.c index 651aa0527..7fad54cc8 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5866,6 +5866,8 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka conn->egress.loss.alarm_at = conn->stash.now; assert_consistency(conn, 0); break; + case PTLS_ERROR_NO_MEMORY: + case QUICLY_ERROR_STATE_EXHAUSTION: case QUICLY_ERROR_PACKET_IGNORED: break; default: /* close connection */ From 0f717e21e9ca0d31fbaf27ea7ffea2e0f8298c31 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 18 Jun 2021 21:14:20 +0900 Subject: [PATCH 102/361] add quictrace_cc probes to self-trace to observe RTT (amends #468) --- misc/probe2trace.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/probe2trace.pl b/misc/probe2trace.pl index cee5e2baf..ee44290d4 100755 --- a/misc/probe2trace.pl +++ b/misc/probe2trace.pl @@ -7,7 +7,7 @@ use Getopt::Long; my $arch = $^O; -my %tracer_probes = map { uc($_) => 1 } qw(packet_sent packet_received packet_acked packet_lost packet_decryption_failed pto cc_ack_received cc_congestion max_data_send max_data_receive max_stream_data_send max_stream_data_receive streams_blocked_send streams_blocked_receive stream_on_open stream_on_destroy); +my %tracer_probes = map { uc($_) => 1 } qw(packet_sent packet_received packet_acked packet_lost packet_decryption_failed pto cc_ack_received cc_congestion quictrace_cc_ack quictrace_cc_lost max_data_send max_data_receive max_stream_data_send max_stream_data_receive streams_blocked_send streams_blocked_receive stream_on_open stream_on_destroy); GetOptions("arch=s" => \$arch) or die "invalid command option\n"; From 51edf39ea8e393f819e447d5e83cb56169ebf91b Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 23 Jun 2021 21:21:14 +0900 Subject: [PATCH 103/361] implement pico cc --- CMakeLists.txt | 1 + include/quicly/cc.h | 12 +++- lib/cc-pico.c | 114 +++++++++++++++++++++++++++++++ quicly.xcodeproj/project.pbxproj | 8 +++ src/cli.c | 4 +- 5 files changed, 136 insertions(+), 3 deletions(-) create mode 100644 lib/cc-pico.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 4cc2524f7..a2ed00ec0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,7 @@ SET(QUICLY_LIBRARY_FILES lib/frame.c lib/cc-reno.c lib/cc-cubic.c + lib/cc-pico.c lib/defaults.c lib/local_cid.c lib/loss.c diff --git a/include/quicly/cc.h b/include/quicly/cc.h index 031ed51af..e18115f61 100644 --- a/include/quicly/cc.h +++ b/include/quicly/cc.h @@ -44,7 +44,11 @@ typedef enum { /** * CUBIC (RFC 8312) */ - CC_CUBIC + CC_CUBIC, + /** + * + */ + CC_PICO } quicly_cc_type_t; /** @@ -81,7 +85,7 @@ typedef struct st_quicly_cc_t { * Stash of acknowledged bytes, used during congestion avoidance. */ uint32_t stash; - } reno; + } reno, pico; /** * State information for CUBIC congestion control. */ @@ -164,6 +168,10 @@ extern struct st_quicly_init_cc_t quicly_cc_reno_init; * The factory method for the modified Reno congestion controller. */ extern struct st_quicly_init_cc_t quicly_cc_cubic_init; +/** + * The factory method for the Pico congestion controller. + */ +extern struct st_quicly_init_cc_t quicly_cc_pico_init; /** * Calculates the initial congestion window size given the maximum UDP payload size. diff --git a/lib/cc-pico.c b/lib/cc-pico.c new file mode 100644 index 000000000..5369eac46 --- /dev/null +++ b/lib/cc-pico.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2019-2021 Fastly, Janardhan Iyengar, Kazuho Oku + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include "quicly/cc.h" +#include "quicly.h" + +#define QUICLY_MIN_CWND 2 +#define QUICLY_PICO_BETA 0.5 +#define QUICLY_PICO_RECOVERY_PERIOD 1000 /* in milliseconds */ + +static uint32_t calc_bytes_per_mtu_increase(uint32_t cwnd, uint32_t ssthresh, uint32_t rtt, uint32_t mtu) +{ + /* Increase per byte acked is the sum of 1mtu/cwnd (additive part) and ... */ + double increase_per_byte = (double)mtu / cwnd; + /* ... multiplicative part being 1 during slow start, or (1/beta - 1) * RTT during congestion avoidance. */ + if (cwnd < ssthresh) { + increase_per_byte += 1; + } else { + increase_per_byte += (1 / QUICLY_PICO_BETA - 1) / QUICLY_PICO_RECOVERY_PERIOD * rtt; + } + + return (uint32_t)(mtu / increase_per_byte); +} + +/* TODO: Avoid increase if sender was application limited. */ +static void pico_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t largest_acked, uint32_t inflight, + int64_t now, uint32_t max_udp_payload_size) +{ + assert(inflight >= bytes); + + /* Do not increase congestion window while in recovery. */ + if (largest_acked < cc->recovery_end) + return; + + cc->state.pico.stash += bytes; + + /* Calculate the amount of bytes required to be acked for incrementing CWND by one MTU. */ + uint32_t bytes_per_mtu_increase = calc_bytes_per_mtu_increase(cc->cwnd, cc->ssthresh, loss->rtt.smoothed, max_udp_payload_size); + + /* Bail out if we do not yet have enough bytes being acked. */ + if (cc->state.pico.stash < bytes_per_mtu_increase) + return; + + /* Update CWND, reducing stash relative to the amount we've adjusted the CWND */ + uint32_t count = cc->state.pico.stash / bytes_per_mtu_increase; + cc->cwnd += count * max_udp_payload_size; + cc->state.pico.stash -= count * bytes_per_mtu_increase; + + if (cc->cwnd_maximum < cc->cwnd) + cc->cwnd_maximum = cc->cwnd; +} + +static void pico_on_lost(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t lost_pn, uint64_t next_pn, + int64_t now, uint32_t max_udp_payload_size) +{ + /* Nothing to do if loss is in recovery window. */ + if (lost_pn < cc->recovery_end) + return; + cc->recovery_end = next_pn; + + ++cc->num_loss_episodes; + if (cc->cwnd_exiting_slow_start == 0) + cc->cwnd_exiting_slow_start = cc->cwnd; + + /* Reduce congestion window. */ + cc->cwnd *= QUICLY_PICO_BETA; + if (cc->cwnd < QUICLY_MIN_CWND * max_udp_payload_size) + cc->cwnd = QUICLY_MIN_CWND * max_udp_payload_size; + cc->ssthresh = cc->cwnd; + + if (cc->cwnd_minimum > cc->cwnd) + cc->cwnd_minimum = cc->cwnd; +} + +static void pico_on_persistent_congestion(quicly_cc_t *cc, const quicly_loss_t *loss, int64_t now) +{ + /* TODO */ +} + +static void pico_on_sent(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, int64_t now) +{ + /* Unused */ +} + +static const struct st_quicly_cc_impl_t pico_impl = {CC_PICO, pico_on_acked, pico_on_lost, pico_on_persistent_congestion, + pico_on_sent}; + +static void pico_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwnd, int64_t now) +{ + memset(cc, 0, sizeof(quicly_cc_t)); + cc->impl = &pico_impl; + cc->cwnd = cc->cwnd_initial = cc->cwnd_maximum = initcwnd; + cc->ssthresh = cc->cwnd_minimum = UINT32_MAX; +} + +quicly_init_cc_t quicly_cc_pico_init = {pico_init}; diff --git a/quicly.xcodeproj/project.pbxproj b/quicly.xcodeproj/project.pbxproj index 91050d834..2f7ac86d1 100644 --- a/quicly.xcodeproj/project.pbxproj +++ b/quicly.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 082195082683498900E3EFCF /* cc-pico.c in Sources */ = {isa = PBXBuildFile; fileRef = 082195072683498900E3EFCF /* cc-pico.c */; }; + 082195092683498900E3EFCF /* cc-pico.c in Sources */ = {isa = PBXBuildFile; fileRef = 082195072683498900E3EFCF /* cc-pico.c */; }; + 0821950A2683498900E3EFCF /* cc-pico.c in Sources */ = {isa = PBXBuildFile; fileRef = 082195072683498900E3EFCF /* cc-pico.c */; }; E904233D24AED0410072C5B7 /* loss.c in Sources */ = {isa = PBXBuildFile; fileRef = E904233C24AED0410072C5B7 /* loss.c */; }; E904233E24AED0410072C5B7 /* loss.c in Sources */ = {isa = PBXBuildFile; fileRef = E904233C24AED0410072C5B7 /* loss.c */; }; E904233F24AED0410072C5B7 /* loss.c in Sources */ = {isa = PBXBuildFile; fileRef = E904233C24AED0410072C5B7 /* loss.c */; }; @@ -141,6 +144,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 082195072683498900E3EFCF /* cc-pico.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "cc-pico.c"; sourceTree = ""; }; E904233C24AED0410072C5B7 /* loss.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = loss.c; sourceTree = ""; }; E904234024AEFB980072C5B7 /* loss.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = loss.c; sourceTree = ""; }; E9056C071F56965300E2B96C /* linklist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = linklist.h; sourceTree = ""; }; @@ -324,6 +328,7 @@ isa = PBXGroup; children = ( E9DF012324E4BAC20002EEC7 /* cc-cubic.c */, + 082195072683498900E3EFCF /* cc-pico.c */, E98041C522383C62008B9745 /* cc-reno.c */, E9736527246FD3AC0039AA49 /* remote_cid.c */, E98042352244A5D7008B9745 /* defaults.c */, @@ -698,6 +703,7 @@ E98042362244A5D7008B9745 /* defaults.c in Sources */, E904233D24AED0410072C5B7 /* loss.c in Sources */, E9F6A42E1F41375B0083F0B2 /* sendstate.c in Sources */, + 082195082683498900E3EFCF /* cc-pico.c in Sources */, E99F8C261F4E9EBF00C26B3D /* frame.c in Sources */, E98448421EA490A500390927 /* quicly.c in Sources */, E9DF012424E4BAC20002EEC7 /* cc-cubic.c in Sources */, @@ -721,6 +727,7 @@ E984483B1EA48DD300390927 /* openssl.c in Sources */, E973652E246FD3B40039AA49 /* remote_cid.c in Sources */, E904233E24AED0410072C5B7 /* loss.c in Sources */, + 082195092683498900E3EFCF /* cc-pico.c in Sources */, E941428D23B0B839002D3CE0 /* frame.c in Sources */, E941429123B0B86D002D3CE0 /* recvstate.c in Sources */, E9B43E12246943D300824E51 /* fusion.c in Sources */, @@ -771,6 +778,7 @@ E99B75E91F5D259400CF503E /* stream-concurrency.c in Sources */, E920D22E1F4981E500799777 /* sentmap.c in Sources */, E9CC44261EC1963100DC7D3E /* picotest.c in Sources */, + 0821950A2683498900E3EFCF /* cc-pico.c in Sources */, E95E953D22904A4C00215ACD /* picotls-probes.d in Sources */, E9CC441C1EC195DF00DC7D3E /* picotls.c in Sources */, E904233F24AED0410072C5B7 /* loss.c in Sources */, diff --git a/src/cli.c b/src/cli.c index 3ff1f50dc..e6d0f811d 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1015,7 +1015,7 @@ static void usage(const char *cmd) " -k key-file specifies the credentials to be used for running the\n" " server. If omitted, the command runs as a client.\n" " -C the congestion control algorithm; either \"reno\"\n" - " (default) or \"cubic\"\n" + " (default), \"cubic\", or \"pico\"\n" " -d draft-number specifies the draft version number to be used (e.g.,\n" " 29)\n" " -e event-log-file file to log events\n" @@ -1115,6 +1115,8 @@ int main(int argc, char **argv) ctx.init_cc = &quicly_cc_reno_init; } else if (strcmp(optarg, "cubic") == 0) { ctx.init_cc = &quicly_cc_cubic_init; + } else if (strcmp(optarg, "pico") == 0) { + ctx.init_cc = &quicly_cc_pico_init; } else { fprintf(stderr, "unknown congestion controller: %s\n", optarg); exit(1); From 24dba9127f57bbcd163115d1890afa9be35064cc Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 24 Jun 2021 10:15:20 +0900 Subject: [PATCH 104/361] Update include/quicly/cc.h Co-authored-by: Jana Iyengar --- include/quicly/cc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/quicly/cc.h b/include/quicly/cc.h index e18115f61..3dae5709d 100644 --- a/include/quicly/cc.h +++ b/include/quicly/cc.h @@ -165,7 +165,7 @@ struct st_quicly_cc_impl_t { */ extern struct st_quicly_init_cc_t quicly_cc_reno_init; /** - * The factory method for the modified Reno congestion controller. + * The factory method for the Cubic congestion controller. */ extern struct st_quicly_init_cc_t quicly_cc_cubic_init; /** From 94317b0a10d717d0ca7ffd7e068402556c985768 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 24 Jun 2021 10:15:52 +0900 Subject: [PATCH 105/361] Update lib/cc-pico.c Co-authored-by: Jana Iyengar --- lib/cc-pico.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cc-pico.c b/lib/cc-pico.c index 5369eac46..bc5fa96fc 100644 --- a/lib/cc-pico.c +++ b/lib/cc-pico.c @@ -30,7 +30,7 @@ static uint32_t calc_bytes_per_mtu_increase(uint32_t cwnd, uint32_t ssthresh, ui { /* Increase per byte acked is the sum of 1mtu/cwnd (additive part) and ... */ double increase_per_byte = (double)mtu / cwnd; - /* ... multiplicative part being 1 during slow start, or (1/beta - 1) * RTT during congestion avoidance. */ + /* ... multiplicative part being 1 during slow start, and the RTT-compensated rate for recovery within QUICLY_PICO_RECOVERY_PERIOD during congestion avoidance. */ if (cwnd < ssthresh) { increase_per_byte += 1; } else { From 37bf413ad399d4509fb22dcf405e41ca033ea49c Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 24 Jun 2021 17:29:06 +0900 Subject: [PATCH 106/361] code reuse, changing pico's BETA to 0.7 --- include/quicly/cc.h | 13 +++++++++-- lib/cc-pico.c | 57 +++++++++------------------------------------ lib/cc-reno.c | 15 +++++------- 3 files changed, 28 insertions(+), 57 deletions(-) diff --git a/include/quicly/cc.h b/include/quicly/cc.h index 3dae5709d..b5a7b157b 100644 --- a/include/quicly/cc.h +++ b/include/quicly/cc.h @@ -36,6 +36,9 @@ extern "C" { #include "quicly/constants.h" #include "quicly/loss.h" +#define QUICLY_MIN_CWND 2 +#define QUICLY_RENO_BETA 0.7 + typedef enum { /** * Reno, with 0.7 beta reduction @@ -78,14 +81,15 @@ typedef struct st_quicly_cc_t { */ union { /** - * State information for Reno congestion control. + * State information for Reno congestion control. Pico also uses this (and therefore we can switch between Reno and Pico + * mid-connection). */ struct { /** * Stash of acknowledged bytes, used during congestion avoidance. */ uint32_t stash; - } reno, pico; + } reno; /** * State information for CUBIC congestion control. */ @@ -178,6 +182,11 @@ extern struct st_quicly_init_cc_t quicly_cc_pico_init; */ uint32_t quicly_cc_calc_initial_cwnd(uint32_t max_packets, uint16_t max_udp_payload_size); +void quicly_cc_reno_on_lost(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t lost_pn, uint64_t next_pn, + int64_t now, uint32_t max_udp_payload_size); +void quicly_cc_reno_on_persistent_congestion(quicly_cc_t *cc, const quicly_loss_t *loss, int64_t now); +void quicly_cc_reno_on_sent(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, int64_t now); + #ifdef __cplusplus } #endif diff --git a/lib/cc-pico.c b/lib/cc-pico.c index bc5fa96fc..5b54fc535 100644 --- a/lib/cc-pico.c +++ b/lib/cc-pico.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 Fastly, Janardhan Iyengar, Kazuho Oku + * Copyright (c) 2021 Fastly, Kazuho Oku * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -22,19 +22,18 @@ #include "quicly/cc.h" #include "quicly.h" -#define QUICLY_MIN_CWND 2 -#define QUICLY_PICO_BETA 0.5 #define QUICLY_PICO_RECOVERY_PERIOD 1000 /* in milliseconds */ static uint32_t calc_bytes_per_mtu_increase(uint32_t cwnd, uint32_t ssthresh, uint32_t rtt, uint32_t mtu) { /* Increase per byte acked is the sum of 1mtu/cwnd (additive part) and ... */ double increase_per_byte = (double)mtu / cwnd; - /* ... multiplicative part being 1 during slow start, and the RTT-compensated rate for recovery within QUICLY_PICO_RECOVERY_PERIOD during congestion avoidance. */ + /* ... multiplicative part being 1 during slow start, and the RTT-compensated rate for recovery within + * QUICLY_PICO_RECOVERY_PERIOD during congestion avoidance. */ if (cwnd < ssthresh) { increase_per_byte += 1; } else { - increase_per_byte += (1 / QUICLY_PICO_BETA - 1) / QUICLY_PICO_RECOVERY_PERIOD * rtt; + increase_per_byte += (1 / QUICLY_RENO_BETA - 1) / QUICLY_PICO_RECOVERY_PERIOD * rtt; } return (uint32_t)(mtu / increase_per_byte); @@ -50,65 +49,31 @@ static void pico_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t b if (largest_acked < cc->recovery_end) return; - cc->state.pico.stash += bytes; + cc->state.reno.stash += bytes; /* Calculate the amount of bytes required to be acked for incrementing CWND by one MTU. */ uint32_t bytes_per_mtu_increase = calc_bytes_per_mtu_increase(cc->cwnd, cc->ssthresh, loss->rtt.smoothed, max_udp_payload_size); /* Bail out if we do not yet have enough bytes being acked. */ - if (cc->state.pico.stash < bytes_per_mtu_increase) + if (cc->state.reno.stash < bytes_per_mtu_increase) return; /* Update CWND, reducing stash relative to the amount we've adjusted the CWND */ - uint32_t count = cc->state.pico.stash / bytes_per_mtu_increase; + uint32_t count = cc->state.reno.stash / bytes_per_mtu_increase; cc->cwnd += count * max_udp_payload_size; - cc->state.pico.stash -= count * bytes_per_mtu_increase; + cc->state.reno.stash -= count * bytes_per_mtu_increase; if (cc->cwnd_maximum < cc->cwnd) cc->cwnd_maximum = cc->cwnd; } -static void pico_on_lost(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t lost_pn, uint64_t next_pn, - int64_t now, uint32_t max_udp_payload_size) -{ - /* Nothing to do if loss is in recovery window. */ - if (lost_pn < cc->recovery_end) - return; - cc->recovery_end = next_pn; - - ++cc->num_loss_episodes; - if (cc->cwnd_exiting_slow_start == 0) - cc->cwnd_exiting_slow_start = cc->cwnd; - - /* Reduce congestion window. */ - cc->cwnd *= QUICLY_PICO_BETA; - if (cc->cwnd < QUICLY_MIN_CWND * max_udp_payload_size) - cc->cwnd = QUICLY_MIN_CWND * max_udp_payload_size; - cc->ssthresh = cc->cwnd; - - if (cc->cwnd_minimum > cc->cwnd) - cc->cwnd_minimum = cc->cwnd; -} - -static void pico_on_persistent_congestion(quicly_cc_t *cc, const quicly_loss_t *loss, int64_t now) -{ - /* TODO */ -} - -static void pico_on_sent(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, int64_t now) -{ - /* Unused */ -} - -static const struct st_quicly_cc_impl_t pico_impl = {CC_PICO, pico_on_acked, pico_on_lost, pico_on_persistent_congestion, - pico_on_sent}; +static const struct st_quicly_cc_impl_t pico_impl = {CC_PICO, pico_on_acked, quicly_cc_reno_on_lost, + quicly_cc_reno_on_persistent_congestion, quicly_cc_reno_on_sent}; static void pico_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwnd, int64_t now) { - memset(cc, 0, sizeof(quicly_cc_t)); + quicly_cc_reno_init.cb(&quicly_cc_reno_init, cc, initcwnd, now); cc->impl = &pico_impl; - cc->cwnd = cc->cwnd_initial = cc->cwnd_maximum = initcwnd; - cc->ssthresh = cc->cwnd_minimum = UINT32_MAX; } quicly_init_cc_t quicly_cc_pico_init = {pico_init}; diff --git a/lib/cc-reno.c b/lib/cc-reno.c index b1fe1e97d..dd9c6381c 100644 --- a/lib/cc-reno.c +++ b/lib/cc-reno.c @@ -22,9 +22,6 @@ #include "quicly/cc.h" #include "quicly.h" -#define QUICLY_MIN_CWND 2 -#define QUICLY_RENO_BETA 0.7 - /* TODO: Avoid increase if sender was application limited. */ static void reno_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t largest_acked, uint32_t inflight, int64_t now, uint32_t max_udp_payload_size) @@ -53,8 +50,8 @@ static void reno_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t b cc->cwnd_maximum = cc->cwnd; } -static void reno_on_lost(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t lost_pn, uint64_t next_pn, - int64_t now, uint32_t max_udp_payload_size) +void quicly_cc_reno_on_lost(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t lost_pn, uint64_t next_pn, + int64_t now, uint32_t max_udp_payload_size) { /* Nothing to do if loss is in recovery window. */ if (lost_pn < cc->recovery_end) @@ -75,18 +72,18 @@ static void reno_on_lost(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t by cc->cwnd_minimum = cc->cwnd; } -static void reno_on_persistent_congestion(quicly_cc_t *cc, const quicly_loss_t *loss, int64_t now) +void quicly_cc_reno_on_persistent_congestion(quicly_cc_t *cc, const quicly_loss_t *loss, int64_t now) { /* TODO */ } -static void reno_on_sent(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, int64_t now) +void quicly_cc_reno_on_sent(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, int64_t now) { /* Unused */ } -static const struct st_quicly_cc_impl_t reno_impl = {CC_RENO_MODIFIED, reno_on_acked, reno_on_lost, reno_on_persistent_congestion, - reno_on_sent}; +static const struct st_quicly_cc_impl_t reno_impl = {CC_RENO_MODIFIED, reno_on_acked, quicly_cc_reno_on_lost, + quicly_cc_reno_on_persistent_congestion, quicly_cc_reno_on_sent}; static void reno_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwnd, int64_t now) { From e9ac46534929824cee6389829d938787045a63d2 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 24 Jun 2021 20:07:18 +0900 Subject: [PATCH 107/361] rename, use Hz --- lib/cc-pico.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/cc-pico.c b/lib/cc-pico.c index 5b54fc535..2f6daa74e 100644 --- a/lib/cc-pico.c +++ b/lib/cc-pico.c @@ -22,18 +22,21 @@ #include "quicly/cc.h" #include "quicly.h" -#define QUICLY_PICO_RECOVERY_PERIOD 1000 /* in milliseconds */ +/** + * Speed at which the multiplicative increase grows from BETA to 1. Unit is Hz. + */ +#define QUICLY_PICO_MULT_HZ 1.0 static uint32_t calc_bytes_per_mtu_increase(uint32_t cwnd, uint32_t ssthresh, uint32_t rtt, uint32_t mtu) { /* Increase per byte acked is the sum of 1mtu/cwnd (additive part) and ... */ double increase_per_byte = (double)mtu / cwnd; - /* ... multiplicative part being 1 during slow start, and the RTT-compensated rate for recovery within - * QUICLY_PICO_RECOVERY_PERIOD during congestion avoidance. */ + /* ... multiplicative part being 1 during slow start, and the RTT-compensated rate for recovery within ~1/QUICLY_PICO_MULT_HZ + * seconds congestion avoidance. */ if (cwnd < ssthresh) { increase_per_byte += 1; } else { - increase_per_byte += (1 / QUICLY_RENO_BETA - 1) / QUICLY_PICO_RECOVERY_PERIOD * rtt; + increase_per_byte += (1 / QUICLY_RENO_BETA - 1) * QUICLY_PICO_MULT_HZ / 1000 * rtt; } return (uint32_t)(mtu / increase_per_byte); From 2002981732b9b12354e576b90746c37baca5d513 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 24 Jun 2021 21:50:18 +0900 Subject: [PATCH 108/361] [refactor] expose `impl` as `type`, adding `name` as a field --- include/quicly/cc.h | 39 ++++++++++----------------------------- lib/cc-cubic.c | 6 ++---- lib/cc-pico.c | 7 +++---- lib/cc-reno.c | 7 +++---- lib/quicly.c | 6 +++--- 5 files changed, 21 insertions(+), 44 deletions(-) diff --git a/include/quicly/cc.h b/include/quicly/cc.h index b5a7b157b..b3e915d9d 100644 --- a/include/quicly/cc.h +++ b/include/quicly/cc.h @@ -39,31 +39,16 @@ extern "C" { #define QUICLY_MIN_CWND 2 #define QUICLY_RENO_BETA 0.7 -typedef enum { - /** - * Reno, with 0.7 beta reduction - */ - CC_RENO_MODIFIED, - /** - * CUBIC (RFC 8312) - */ - CC_CUBIC, - /** - * - */ - CC_PICO -} quicly_cc_type_t; - /** * Holds pointers to concrete congestion control implementation functions. */ -struct st_quicly_cc_impl_t; +typedef const struct st_quicly_cc_type_t quicly_cc_type_t; typedef struct st_quicly_cc_t { /** - * Congestion controller implementation. + * Congestion controller type. */ - const struct st_quicly_cc_impl_t *impl; + quicly_cc_type_t *type; /** * Current congestion window. */ @@ -138,11 +123,11 @@ typedef struct st_quicly_cc_t { uint32_t num_loss_episodes; } quicly_cc_t; -struct st_quicly_cc_impl_t { +struct st_quicly_cc_type_t { /** - * Congestion controller type. + * name (e.g., "reno") */ - quicly_cc_type_t type; + const char *name; /** * Called when a packet is newly acknowledged. */ @@ -165,17 +150,13 @@ struct st_quicly_cc_impl_t { }; /** - * The factory method for the modified Reno congestion controller. - */ -extern struct st_quicly_init_cc_t quicly_cc_reno_init; -/** - * The factory method for the Cubic congestion controller. + * The type objects for each CC. These can be used for testing the type of each `quicly_cc_t`. */ -extern struct st_quicly_init_cc_t quicly_cc_cubic_init; +extern quicly_cc_type_t quicly_cc_type_reno, quicly_cc_type_cubic, quicly_cc_type_pico; /** - * The factory method for the Pico congestion controller. + * The factory methods for each CC. */ -extern struct st_quicly_init_cc_t quicly_cc_pico_init; +extern struct st_quicly_init_cc_t quicly_cc_reno_init, quicly_cc_cubic_init, quicly_cc_pico_init; /** * Calculates the initial congestion window size given the maximum UDP payload size. diff --git a/lib/cc-cubic.c b/lib/cc-cubic.c index 399ae6aca..f2bc55742 100644 --- a/lib/cc-cubic.c +++ b/lib/cc-cubic.c @@ -157,15 +157,13 @@ static void cubic_on_sent(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t b cc->state.cubic.last_sent_time = now; } -static const struct st_quicly_cc_impl_t cubic_impl = {CC_CUBIC, cubic_on_acked, cubic_on_lost, cubic_on_persistent_congestion, - cubic_on_sent}; - static void cubic_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwnd, int64_t now) { memset(cc, 0, sizeof(quicly_cc_t)); - cc->impl = &cubic_impl; + cc->type = &quicly_cc_type_cubic; cc->cwnd = cc->cwnd_initial = cc->cwnd_maximum = initcwnd; cc->ssthresh = cc->cwnd_minimum = UINT32_MAX; } +quicly_cc_type_t quicly_cc_type_cubic = {"cubic", cubic_on_acked, cubic_on_lost, cubic_on_persistent_congestion, cubic_on_sent}; quicly_init_cc_t quicly_cc_cubic_init = {cubic_init}; diff --git a/lib/cc-pico.c b/lib/cc-pico.c index 2f6daa74e..0fb7e4927 100644 --- a/lib/cc-pico.c +++ b/lib/cc-pico.c @@ -70,13 +70,12 @@ static void pico_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t b cc->cwnd_maximum = cc->cwnd; } -static const struct st_quicly_cc_impl_t pico_impl = {CC_PICO, pico_on_acked, quicly_cc_reno_on_lost, - quicly_cc_reno_on_persistent_congestion, quicly_cc_reno_on_sent}; - static void pico_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwnd, int64_t now) { quicly_cc_reno_init.cb(&quicly_cc_reno_init, cc, initcwnd, now); - cc->impl = &pico_impl; + cc->type = &quicly_cc_type_pico; } +quicly_cc_type_t quicly_cc_type_pico = {"pico", pico_on_acked, quicly_cc_reno_on_lost, quicly_cc_reno_on_persistent_congestion, + quicly_cc_reno_on_sent}; quicly_init_cc_t quicly_cc_pico_init = {pico_init}; diff --git a/lib/cc-reno.c b/lib/cc-reno.c index dd9c6381c..95b731b4e 100644 --- a/lib/cc-reno.c +++ b/lib/cc-reno.c @@ -82,17 +82,16 @@ void quicly_cc_reno_on_sent(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t /* Unused */ } -static const struct st_quicly_cc_impl_t reno_impl = {CC_RENO_MODIFIED, reno_on_acked, quicly_cc_reno_on_lost, - quicly_cc_reno_on_persistent_congestion, quicly_cc_reno_on_sent}; - static void reno_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwnd, int64_t now) { memset(cc, 0, sizeof(quicly_cc_t)); - cc->impl = &reno_impl; + cc->type = &quicly_cc_type_reno; cc->cwnd = cc->cwnd_initial = cc->cwnd_maximum = initcwnd; cc->ssthresh = cc->cwnd_minimum = UINT32_MAX; } +quicly_cc_type_t quicly_cc_type_reno = {"reno", reno_on_acked, quicly_cc_reno_on_lost, quicly_cc_reno_on_persistent_congestion, + quicly_cc_reno_on_sent}; quicly_init_cc_t quicly_cc_reno_init = {reno_init}; uint32_t quicly_cc_calc_initial_cwnd(uint32_t max_packets, uint16_t max_udp_payload_size) diff --git a/lib/quicly.c b/lib/quicly.c index 2b4aae54f..d881b72c2 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3043,7 +3043,7 @@ static int commit_send_packet(quicly_conn_t *conn, quicly_send_context_t *s, enu if (quicly_sentmap_is_open(&conn->egress.loss.sentmap)) quicly_sentmap_commit(&conn->egress.loss.sentmap, (uint16_t)packet_bytes_in_flight); - conn->egress.cc.impl->cc_on_sent(&conn->egress.cc, &conn->egress.loss, (uint32_t)packet_bytes_in_flight, conn->stash.now); + conn->egress.cc.type->cc_on_sent(&conn->egress.cc, &conn->egress.loss, (uint32_t)packet_bytes_in_flight, conn->stash.now); QUICLY_PROBE(PACKET_SENT, conn, conn->stash.now, conn->egress.packet_number, s->dst - s->target.first_byte_at, get_epoch(*s->target.first_byte_at), !s->target.ack_eliciting); @@ -3628,7 +3628,7 @@ static void on_loss_detected(quicly_loss_t *loss, const quicly_sent_packet_t *lo ++conn->super.stats.num_packets.lost; if (is_time_threshold) ++conn->super.stats.num_packets.lost_time_threshold; - conn->egress.cc.impl->cc_on_lost(&conn->egress.cc, &conn->egress.loss, lost_packet->cc_bytes_in_flight, + conn->egress.cc.type->cc_on_lost(&conn->egress.cc, &conn->egress.loss, lost_packet->cc_bytes_in_flight, lost_packet->packet_number, conn->egress.packet_number, conn->stash.now, conn->egress.max_udp_payload_size); QUICLY_PROBE(PACKET_LOST, conn, conn->stash.now, lost_packet->packet_number, lost_packet->ack_epoch); @@ -4830,7 +4830,7 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload /* OnPacketAcked and OnPacketAckedCC */ if (bytes_acked > 0) { - conn->egress.cc.impl->cc_on_acked(&conn->egress.cc, &conn->egress.loss, (uint32_t)bytes_acked, frame.largest_acknowledged, + conn->egress.cc.type->cc_on_acked(&conn->egress.cc, &conn->egress.loss, (uint32_t)bytes_acked, frame.largest_acknowledged, (uint32_t)(conn->egress.loss.sentmap.bytes_in_flight + bytes_acked), conn->stash.now, conn->egress.max_udp_payload_size); QUICLY_PROBE(QUICTRACE_CC_ACK, conn, conn->stash.now, &conn->egress.loss.rtt, conn->egress.cc.cwnd, From b4c33691c223d97d6389ba3ea082bd80fef1b051 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 24 Jun 2021 22:11:28 +0900 Subject: [PATCH 109/361] add API to switch between CCs --- include/quicly/cc.h | 4 ++++ lib/cc-cubic.c | 10 +++++++++- lib/cc-pico.c | 16 ++++++++++++++-- lib/cc-reno.c | 16 ++++++++++++++-- 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/include/quicly/cc.h b/include/quicly/cc.h index b3e915d9d..7373c79e8 100644 --- a/include/quicly/cc.h +++ b/include/quicly/cc.h @@ -147,6 +147,10 @@ struct st_quicly_cc_type_t { * Called after a packet is sent. */ void (*cc_on_sent)(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, int64_t now); + /** + * Switches the underlying algorithm of `cc` to that of `cc_switch`, returning a boolean if the operation was successful. + */ + int (*cc_switch)(quicly_cc_t *cc); }; /** diff --git a/lib/cc-cubic.c b/lib/cc-cubic.c index f2bc55742..c4ab905df 100644 --- a/lib/cc-cubic.c +++ b/lib/cc-cubic.c @@ -157,6 +157,13 @@ static void cubic_on_sent(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t b cc->state.cubic.last_sent_time = now; } +static int cubic_on_switch(quicly_cc_t *cc) +{ + if (cc->type == &quicly_cc_type_cubic) + return 1; + return 0; +} + static void cubic_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwnd, int64_t now) { memset(cc, 0, sizeof(quicly_cc_t)); @@ -165,5 +172,6 @@ static void cubic_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwn cc->ssthresh = cc->cwnd_minimum = UINT32_MAX; } -quicly_cc_type_t quicly_cc_type_cubic = {"cubic", cubic_on_acked, cubic_on_lost, cubic_on_persistent_congestion, cubic_on_sent}; +quicly_cc_type_t quicly_cc_type_cubic = {"cubic", cubic_on_acked, cubic_on_lost, cubic_on_persistent_congestion, + cubic_on_sent, cubic_on_switch}; quicly_init_cc_t quicly_cc_cubic_init = {cubic_init}; diff --git a/lib/cc-pico.c b/lib/cc-pico.c index 0fb7e4927..945684a4e 100644 --- a/lib/cc-pico.c +++ b/lib/cc-pico.c @@ -70,12 +70,24 @@ static void pico_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t b cc->cwnd_maximum = cc->cwnd; } +static int pico_on_switch(quicly_cc_t *cc) +{ + if (cc->type == &quicly_cc_type_pico) { + return 1; /* nothing to do */ + } else if (cc->type == &quicly_cc_type_reno) { + cc->type = &quicly_cc_type_pico; + return 1; + } else { + return 0; + } +} + static void pico_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwnd, int64_t now) { quicly_cc_reno_init.cb(&quicly_cc_reno_init, cc, initcwnd, now); cc->type = &quicly_cc_type_pico; } -quicly_cc_type_t quicly_cc_type_pico = {"pico", pico_on_acked, quicly_cc_reno_on_lost, quicly_cc_reno_on_persistent_congestion, - quicly_cc_reno_on_sent}; +quicly_cc_type_t quicly_cc_type_pico = { + "pico", pico_on_acked, quicly_cc_reno_on_lost, quicly_cc_reno_on_persistent_congestion, quicly_cc_reno_on_sent, pico_on_switch}; quicly_init_cc_t quicly_cc_pico_init = {pico_init}; diff --git a/lib/cc-reno.c b/lib/cc-reno.c index 95b731b4e..6046e2d9e 100644 --- a/lib/cc-reno.c +++ b/lib/cc-reno.c @@ -82,6 +82,18 @@ void quicly_cc_reno_on_sent(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t /* Unused */ } +static int reno_on_switch(quicly_cc_t *cc) +{ + if (cc->type == &quicly_cc_type_reno) { + return 1; /* nothing to do */ + } else if (cc->type == &quicly_cc_type_pico) { + cc->type = &quicly_cc_type_reno; + return 1; + } else { + return 0; + } +} + static void reno_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwnd, int64_t now) { memset(cc, 0, sizeof(quicly_cc_t)); @@ -90,8 +102,8 @@ static void reno_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwnd cc->ssthresh = cc->cwnd_minimum = UINT32_MAX; } -quicly_cc_type_t quicly_cc_type_reno = {"reno", reno_on_acked, quicly_cc_reno_on_lost, quicly_cc_reno_on_persistent_congestion, - quicly_cc_reno_on_sent}; +quicly_cc_type_t quicly_cc_type_reno = { + "reno", reno_on_acked, quicly_cc_reno_on_lost, quicly_cc_reno_on_persistent_congestion, quicly_cc_reno_on_sent, reno_on_switch}; quicly_init_cc_t quicly_cc_reno_init = {reno_init}; uint32_t quicly_cc_calc_initial_cwnd(uint32_t max_packets, uint16_t max_udp_payload_size) From 9cb3a030bf3af14f84f1dcf8ffd62a72163cb55d Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 24 Jun 2021 22:39:45 +0900 Subject: [PATCH 110/361] add special handling for cc.name now that it is a string --- misc/probe2trace.pl | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/misc/probe2trace.pl b/misc/probe2trace.pl index ee44290d4..7b9465ccf 100755 --- a/misc/probe2trace.pl +++ b/misc/probe2trace.pl @@ -130,7 +130,7 @@ # build an array of [field-names => type-specifiers] my @fields; push @fields, map {["rtt.$_" => '%u']} qw(minimum smoothed variance); - push @fields, map {["cc.$_" => '%u']} qw(impl->type cwnd ssthresh cwnd_initial cwnd_exiting_slow_start cwnd_minimum cwnd_maximum num_loss_episodes); + push @fields, map {["cc.$_" => '%u']} qw(cwnd ssthresh cwnd_initial cwnd_exiting_slow_start cwnd_minimum cwnd_maximum num_loss_episodes); push @fields, map {["num_packets.$_" => $arch eq 'embedded' ? '%" PRIu64 "' : '%llu']} qw(sent ack_received lost lost_time_threshold late_acked received decryption_failed); push @fields, map {["num_bytes.$_" => $arch eq 'embedded' ? '%" PRIu64 "' : '%llu']} qw(sent received); for my $container (qw(num_frames_sent num_frames_received)) { @@ -144,6 +144,15 @@ } else { push @ap, map{"arg${i}->" . $_->[0]} @fields; } + # special handling of cc.type + push @fmt, '"cc_type":"%s"'; + if ($arch eq 'linux') { + push @ap, "str((struct st_quicly_stats_t *)arg$i)->cc.type->name)"; + } elsif ($arch eq 'darwin') { + push @ap, "copyinstr(str(arg${i}->cc.type->name))"; + } else { + push @ap, "arg${i}->cc.type->name"; + } } else { $name = 'time' if $name eq 'at'; From 029e34a4c9d91b0ba445e3792f53f6de2a4e4008 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 24 Jun 2021 22:45:56 +0900 Subject: [PATCH 111/361] include reference to init in type so that we do not need to hard code the names at the user-side --- include/quicly/cc.h | 4 ++++ include/quicly/defaults.h | 1 + lib/cc-cubic.c | 4 ++-- lib/cc-pico.c | 11 ++++++++--- lib/cc-reno.c | 9 +++++++-- src/cli.c | 17 +++++++++-------- 6 files changed, 31 insertions(+), 15 deletions(-) diff --git a/include/quicly/cc.h b/include/quicly/cc.h index 7373c79e8..db8688e26 100644 --- a/include/quicly/cc.h +++ b/include/quicly/cc.h @@ -128,6 +128,10 @@ struct st_quicly_cc_type_t { * name (e.g., "reno") */ const char *name; + /** + * Corresponding default init_cc. + */ + struct st_quicly_init_cc_t *cc_init; /** * Called when a packet is newly acknowledged. */ diff --git a/include/quicly/defaults.h b/include/quicly/defaults.h index 820232025..917c5ac11 100644 --- a/include/quicly/defaults.h +++ b/include/quicly/defaults.h @@ -57,6 +57,7 @@ extern quicly_now_t quicly_default_now; */ extern quicly_crypto_engine_t quicly_default_crypto_engine; +#define quicly_default_cc quicly_cc_type_reno #define quicly_default_init_cc quicly_cc_reno_init #ifdef __cplusplus diff --git a/lib/cc-cubic.c b/lib/cc-cubic.c index c4ab905df..ef3bbeabc 100644 --- a/lib/cc-cubic.c +++ b/lib/cc-cubic.c @@ -172,6 +172,6 @@ static void cubic_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwn cc->ssthresh = cc->cwnd_minimum = UINT32_MAX; } -quicly_cc_type_t quicly_cc_type_cubic = {"cubic", cubic_on_acked, cubic_on_lost, cubic_on_persistent_congestion, - cubic_on_sent, cubic_on_switch}; +quicly_cc_type_t quicly_cc_type_cubic = { + "cubic", &quicly_cc_cubic_init, cubic_on_acked, cubic_on_lost, cubic_on_persistent_congestion, cubic_on_sent, cubic_on_switch}; quicly_init_cc_t quicly_cc_cubic_init = {cubic_init}; diff --git a/lib/cc-pico.c b/lib/cc-pico.c index 945684a4e..75b0f8beb 100644 --- a/lib/cc-pico.c +++ b/lib/cc-pico.c @@ -84,10 +84,15 @@ static int pico_on_switch(quicly_cc_t *cc) static void pico_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwnd, int64_t now) { - quicly_cc_reno_init.cb(&quicly_cc_reno_init, cc, initcwnd, now); + quicly_cc_type_reno.cc_init->cb(quicly_cc_type_reno.cc_init, cc, initcwnd, now); cc->type = &quicly_cc_type_pico; } -quicly_cc_type_t quicly_cc_type_pico = { - "pico", pico_on_acked, quicly_cc_reno_on_lost, quicly_cc_reno_on_persistent_congestion, quicly_cc_reno_on_sent, pico_on_switch}; +quicly_cc_type_t quicly_cc_type_pico = {"pico", + &quicly_cc_pico_init, + pico_on_acked, + quicly_cc_reno_on_lost, + quicly_cc_reno_on_persistent_congestion, + quicly_cc_reno_on_sent, + pico_on_switch}; quicly_init_cc_t quicly_cc_pico_init = {pico_init}; diff --git a/lib/cc-reno.c b/lib/cc-reno.c index 6046e2d9e..a75faedd1 100644 --- a/lib/cc-reno.c +++ b/lib/cc-reno.c @@ -102,8 +102,13 @@ static void reno_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwnd cc->ssthresh = cc->cwnd_minimum = UINT32_MAX; } -quicly_cc_type_t quicly_cc_type_reno = { - "reno", reno_on_acked, quicly_cc_reno_on_lost, quicly_cc_reno_on_persistent_congestion, quicly_cc_reno_on_sent, reno_on_switch}; +quicly_cc_type_t quicly_cc_type_reno = {"reno", + &quicly_cc_reno_init, + reno_on_acked, + quicly_cc_reno_on_lost, + quicly_cc_reno_on_persistent_congestion, + quicly_cc_reno_on_sent, + reno_on_switch}; quicly_init_cc_t quicly_cc_reno_init = {reno_init}; uint32_t quicly_cc_calc_initial_cwnd(uint32_t max_packets, uint16_t max_udp_payload_size) diff --git a/src/cli.c b/src/cli.c index e6d0f811d..5e3448d53 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1110,18 +1110,19 @@ int main(int argc, char **argv) case 'c': cert_file = optarg; break; - case 'C': - if (strcmp(optarg, "reno") == 0) { - ctx.init_cc = &quicly_cc_reno_init; - } else if (strcmp(optarg, "cubic") == 0) { - ctx.init_cc = &quicly_cc_cubic_init; - } else if (strcmp(optarg, "pico") == 0) { - ctx.init_cc = &quicly_cc_pico_init; + case 'C': { + static const quicly_cc_type_t *supported[] = {&quicly_cc_type_reno, &quicly_cc_type_cubic, &quicly_cc_type_pico, NULL}; + quicly_cc_type_t **found; + for (found = supported; *found != NULL; found++) + if (strcmp((*found)->name, optarg) == 0) + break; + if (*found != NULL) { + ctx.init_cc = (*found)->cc_init; } else { fprintf(stderr, "unknown congestion controller: %s\n", optarg); exit(1); } - break; + } break; case 'G': #ifdef __linux__ send_packets = send_packets_gso; From 9481a38bc7325524cce92d9d202b2f17ce8dfd0f Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 25 Jun 2021 06:10:15 +0900 Subject: [PATCH 112/361] retain list of CC types so that apps can iterate and find --- include/quicly/cc.h | 5 +++++ lib/cc-reno.c | 2 ++ src/cli.c | 11 +++++------ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/include/quicly/cc.h b/include/quicly/cc.h index db8688e26..bef3f4c85 100644 --- a/include/quicly/cc.h +++ b/include/quicly/cc.h @@ -166,6 +166,11 @@ extern quicly_cc_type_t quicly_cc_type_reno, quicly_cc_type_cubic, quicly_cc_typ */ extern struct st_quicly_init_cc_t quicly_cc_reno_init, quicly_cc_cubic_init, quicly_cc_pico_init; +/** + * A null-terminated list of all CC types. + */ +extern quicly_cc_type_t *quicly_cc_all_types[]; + /** * Calculates the initial congestion window size given the maximum UDP payload size. */ diff --git a/lib/cc-reno.c b/lib/cc-reno.c index a75faedd1..f36c320db 100644 --- a/lib/cc-reno.c +++ b/lib/cc-reno.c @@ -111,6 +111,8 @@ quicly_cc_type_t quicly_cc_type_reno = {"reno", reno_on_switch}; quicly_init_cc_t quicly_cc_reno_init = {reno_init}; +quicly_cc_type_t *quicly_cc_all_types[] = {&quicly_cc_type_reno, &quicly_cc_type_cubic, &quicly_cc_type_pico, NULL}; + uint32_t quicly_cc_calc_initial_cwnd(uint32_t max_packets, uint16_t max_udp_payload_size) { static const uint32_t mtu_max = 1472; diff --git a/src/cli.c b/src/cli.c index 5e3448d53..1c910093a 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1111,13 +1111,12 @@ int main(int argc, char **argv) cert_file = optarg; break; case 'C': { - static const quicly_cc_type_t *supported[] = {&quicly_cc_type_reno, &quicly_cc_type_cubic, &quicly_cc_type_pico, NULL}; - quicly_cc_type_t **found; - for (found = supported; *found != NULL; found++) - if (strcmp((*found)->name, optarg) == 0) + quicly_cc_type_t **cc; + for (cc = quicly_cc_all_types; *cc != NULL; ++cc) + if (strcmp((*cc)->name, optarg) == 0) break; - if (*found != NULL) { - ctx.init_cc = (*found)->cc_init; + if (*cc != NULL) { + ctx.init_cc = (*cc)->cc_init; } else { fprintf(stderr, "unknown congestion controller: %s\n", optarg); exit(1); From 2f5792be723f72d64adf3f0e907f5a1eb6d6dec2 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 29 Jun 2021 17:25:53 +0900 Subject: [PATCH 113/361] Support switching CCs to/from Cubic. Works perfectly during slow start, restarted if already in congestion avoidance. --- lib/cc-cubic.c | 24 ++++++++++++++++++++---- lib/cc-pico.c | 11 ++++------- lib/cc-reno.c | 25 +++++++++++++++++++------ 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/lib/cc-cubic.c b/lib/cc-cubic.c index ef3bbeabc..2b981a27d 100644 --- a/lib/cc-cubic.c +++ b/lib/cc-cubic.c @@ -157,19 +157,35 @@ static void cubic_on_sent(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t b cc->state.cubic.last_sent_time = now; } +static void cubic_reset(quicly_cc_t *cc, uint32_t initcwnd) +{ + memset(cc, 0, sizeof(quicly_cc_t)); + cc->type = &quicly_cc_type_cubic; + cc->cwnd = cc->cwnd_initial = cc->cwnd_maximum = initcwnd; + cc->ssthresh = cc->cwnd_minimum = UINT32_MAX; +} + static int cubic_on_switch(quicly_cc_t *cc) { if (cc->type == &quicly_cc_type_cubic) return 1; + + if (cc->type == &quicly_cc_type_reno || cc->type == &quicly_cc_type_pico) { + /* When in slow start, state can be reused as-is; otherwise, restart. */ + if (cc->cwnd_exiting_slow_start == 0) { + cc->type = &quicly_cc_type_cubic; + } else { + cubic_reset(cc, cc->cwnd_initial); + } + return 1; + } + return 0; } static void cubic_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwnd, int64_t now) { - memset(cc, 0, sizeof(quicly_cc_t)); - cc->type = &quicly_cc_type_cubic; - cc->cwnd = cc->cwnd_initial = cc->cwnd_maximum = initcwnd; - cc->ssthresh = cc->cwnd_minimum = UINT32_MAX; + cubic_reset(cc, initcwnd); } quicly_cc_type_t quicly_cc_type_cubic = { diff --git a/lib/cc-pico.c b/lib/cc-pico.c index 75b0f8beb..ce37cb870 100644 --- a/lib/cc-pico.c +++ b/lib/cc-pico.c @@ -72,14 +72,11 @@ static void pico_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t b static int pico_on_switch(quicly_cc_t *cc) { - if (cc->type == &quicly_cc_type_pico) { - return 1; /* nothing to do */ - } else if (cc->type == &quicly_cc_type_reno) { - cc->type = &quicly_cc_type_pico; - return 1; - } else { + /* switch to reno then rewrite the type */ + if (!quicly_cc_type_reno.cc_switch(cc)) return 0; - } + cc->type = &quicly_cc_type_pico; + return 1; } static void pico_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwnd, int64_t now) diff --git a/lib/cc-reno.c b/lib/cc-reno.c index f36c320db..e4930ad81 100644 --- a/lib/cc-reno.c +++ b/lib/cc-reno.c @@ -82,6 +82,14 @@ void quicly_cc_reno_on_sent(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t /* Unused */ } +static void reno_reset(quicly_cc_t *cc, uint32_t initcwnd) +{ + memset(cc, 0, sizeof(quicly_cc_t)); + cc->type = &quicly_cc_type_reno; + cc->cwnd = cc->cwnd_initial = cc->cwnd_maximum = initcwnd; + cc->ssthresh = cc->cwnd_minimum = UINT32_MAX; +} + static int reno_on_switch(quicly_cc_t *cc) { if (cc->type == &quicly_cc_type_reno) { @@ -89,17 +97,22 @@ static int reno_on_switch(quicly_cc_t *cc) } else if (cc->type == &quicly_cc_type_pico) { cc->type = &quicly_cc_type_reno; return 1; - } else { - return 0; + } else if (cc->type == &quicly_cc_type_cubic) { + /* When in slow start, state can be reused as-is; otherwise, restart. */ + if (cc->cwnd_exiting_slow_start == 0) { + cc->type = &quicly_cc_type_reno; + } else { + reno_reset(cc, cc->cwnd_initial); + } + return 1; } + + return 0; } static void reno_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwnd, int64_t now) { - memset(cc, 0, sizeof(quicly_cc_t)); - cc->type = &quicly_cc_type_reno; - cc->cwnd = cc->cwnd_initial = cc->cwnd_maximum = initcwnd; - cc->ssthresh = cc->cwnd_minimum = UINT32_MAX; + reno_reset(cc, initcwnd); } quicly_cc_type_t quicly_cc_type_reno = {"reno", From b9f96e9e3a39ca1573188249b021ae118734144e Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 1 Jul 2021 17:28:52 +0900 Subject: [PATCH 114/361] [refactor] determine the size of the datagram based on state rather than the type of the packet --- lib/quicly.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index d881b72c2..a953db6d2 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -2933,7 +2933,14 @@ struct st_quicly_send_context_t { * contains multiple QUIC packet. */ uint8_t *first_byte_at; + /** + * if the target QUIC packet contains an ack-eliciting frame + */ uint8_t ack_eliciting : 1; + /** + * if the target datagram sholud be padded to full size + */ + uint8_t full_size : 1; } target; /** * output buffer into which list of datagrams is written @@ -2979,13 +2986,7 @@ struct st_quicly_send_context_t { uint8_t *dst_payload_from; }; -enum en_quicly_send_packet_mode_t { - QUICLY_COMMIT_SEND_PACKET_MODE_FULL_SIZE, - QUICLY_COMMIT_SEND_PACKET_MODE_SMALL, - QUICLY_COMMIT_SEND_PACKET_MODE_COALESCED, -}; - -static int commit_send_packet(quicly_conn_t *conn, quicly_send_context_t *s, enum en_quicly_send_packet_mode_t mode) +static int commit_send_packet(quicly_conn_t *conn, quicly_send_context_t *s, int coalesced) { size_t datagram_size, packet_bytes_in_flight; @@ -2997,7 +2998,7 @@ static int commit_send_packet(quicly_conn_t *conn, quicly_send_context_t *s, enu while (s->dst - s->dst_payload_from < QUICLY_MAX_PN_SIZE - QUICLY_SEND_PN_SIZE) *s->dst++ = QUICLY_FRAME_TYPE_PADDING; - if (mode == QUICLY_COMMIT_SEND_PACKET_MODE_FULL_SIZE) { + if (!coalesced && s->target.full_size) { assert(s->num_datagrams == 0 || s->datagrams[s->num_datagrams - 1].iov_len == conn->egress.max_udp_payload_size); const size_t max_size = conn->egress.max_udp_payload_size - QUICLY_AEAD_TAG_SIZE; assert(s->dst - s->payload_buf.datagram <= max_size); @@ -3031,7 +3032,7 @@ static int commit_send_packet(quicly_conn_t *conn, quicly_send_context_t *s, enu s->target.cipher->aead, ptls_iovec_init(s->payload_buf.datagram, datagram_size), s->target.first_byte_at - s->payload_buf.datagram, s->dst_payload_from - s->payload_buf.datagram, conn->egress.packet_number, - mode == QUICLY_COMMIT_SEND_PACKET_MODE_COALESCED); + coalesced); /* update CC, commit sentmap */ if (s->target.ack_eliciting) { @@ -3050,7 +3051,7 @@ static int commit_send_packet(quicly_conn_t *conn, quicly_send_context_t *s, enu ++conn->egress.packet_number; ++conn->super.stats.num_packets.sent; - if (mode != QUICLY_COMMIT_SEND_PACKET_MODE_COALESCED) { + if (!coalesced) { conn->super.stats.num_bytes.sent += datagram_size; s->datagrams[s->num_datagrams++] = (struct iovec){.iov_base = s->payload_buf.datagram, .iov_len = datagram_size}; s->payload_buf.datagram += datagram_size; @@ -3120,8 +3121,7 @@ static int _do_allocate_frame(quicly_conn_t *conn, quicly_send_context_t *s, siz coalescible = 0; } /* close out packet under construction */ - if ((ret = commit_send_packet( - conn, s, coalescible ? QUICLY_COMMIT_SEND_PACKET_MODE_COALESCED : QUICLY_COMMIT_SEND_PACKET_MODE_FULL_SIZE)) != 0) + if ((ret = commit_send_packet(conn, s, coalescible)) != 0) return ret; } else { coalescible = 0; @@ -3140,6 +3140,7 @@ static int _do_allocate_frame(quicly_conn_t *conn, quicly_send_context_t *s, siz if (s->payload_buf.end - s->payload_buf.datagram < conn->egress.max_udp_payload_size) return QUICLY_ERROR_SENDBUF_FULL; s->target.cipher = s->current.cipher; + s->target.full_size = 0; s->dst = s->payload_buf.datagram; s->dst_end = s->dst + conn->egress.max_udp_payload_size; } @@ -3260,7 +3261,8 @@ static int send_ack(quicly_conn_t *conn, struct st_quicly_pn_space_t *space, qui assert(s->target.first_byte_at != s->payload_buf.datagram); *s->dst++ = QUICLY_FRAME_TYPE_PADDING; } - if ((ret = commit_send_packet(conn, s, QUICLY_COMMIT_SEND_PACKET_MODE_FULL_SIZE)) != 0) + s->target.full_size = 1; + if ((ret = commit_send_packet(conn, s, 0)) != 0) return ret; goto Emit; } @@ -4381,11 +4383,10 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) ret = 0; if (ret == 0 && s->target.first_byte_at != NULL) { /* last packet can be small-sized, unless it is the first flight sent from the client */ - enum en_quicly_send_packet_mode_t commit_mode = QUICLY_COMMIT_SEND_PACKET_MODE_SMALL; if ((s->payload_buf.datagram[0] & QUICLY_PACKET_TYPE_BITMASK) == QUICLY_PACKET_TYPE_INITIAL && (quicly_is_client(conn) || !ack_only)) - commit_mode = QUICLY_COMMIT_SEND_PACKET_MODE_FULL_SIZE; - commit_send_packet(conn, s, commit_mode); + s->target.full_size = 1; + commit_send_packet(conn, s, 0); } if (ret == 0) { if (conn->application == NULL || conn->application->super.unacked_count == 0) @@ -4449,7 +4450,7 @@ int quicly_send(quicly_conn_t *conn, quicly_address_t *dest, quicly_address_t *s if ((ret = send_connection_close(conn, epoch, &s)) != 0) goto Exit; } - if ((ret = commit_send_packet(conn, &s, QUICLY_COMMIT_SEND_PACKET_MODE_SMALL)) != 0) + if ((ret = commit_send_packet(conn, &s, 0)) != 0) goto Exit; } /* wait at least 1ms */ From ae859fdd8dc9fbd3e4d09ea0a9dbdd06258a567d Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 1 Jul 2021 17:30:49 +0900 Subject: [PATCH 115/361] request datagrams carrying PATH_CHALLENGE / PATH_RESPONSE to be full-sized --- lib/quicly.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/quicly.c b/lib/quicly.c index a953db6d2..5c63b6a23 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -4310,6 +4310,7 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) free(c); } while (conn->egress.path_challenge.head != NULL); conn->egress.path_challenge.tail_ref = &conn->egress.path_challenge.head; + s->target.full_size = 1; /* datagrams carrying PATH_CHALLENGE / PATH_RESPONSE have to be full-sized */ } /* send max_streams frames */ if ((ret = send_max_streams(conn, 1, s)) != 0) From b3ea52bf6cd10d6960c3d68bebf5af81f17b17d6 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 1 Jul 2021 21:12:00 +0900 Subject: [PATCH 116/361] add new error codes --- include/quicly/constants.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/quicly/constants.h b/include/quicly/constants.h index 03a35c41b..d26604262 100644 --- a/include/quicly/constants.h +++ b/include/quicly/constants.h @@ -95,6 +95,8 @@ extern "C" { #define QUICLY_TRANSPORT_ERROR_INVALID_TOKEN QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0xb) #define QUICLY_TRANSPORT_ERROR_APPLICATION QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0xc) #define QUICLY_TRANSPORT_ERROR_CRYPTO_BUFFER_EXCEEDED QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0xd) +#define QUICLY_TRANSPORT_ERROR_KEY_UPDATE QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0xe) +#define QUICLY_TRANSPORT_ERROR_AEAD_LIMIT_REACHED QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0xf) #define QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0x100) /* internal error codes, used purely for signaling status to the application */ From 057f949ac2d587c51b7303ffa034380d35677246 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 1 Jul 2021 21:21:17 +0900 Subject: [PATCH 117/361] version 1 --- include/quicly.h | 9 +++++++-- lib/defaults.c | 4 ++-- lib/quicly.c | 49 +++++++++++++++++++++++++++++------------------- t/test.c | 4 ++-- 4 files changed, 41 insertions(+), 25 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index adbc992bf..21c8691b7 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -64,10 +64,14 @@ extern "C" { #define QUICLY_PACKET_IS_LONG_HEADER(first_byte) (((first_byte)&QUICLY_LONG_HEADER_BIT) != 0) +/** + * Version 1. + */ +#define QUICLY_PROTOCOL_VERSION_1 0x1 /** * The current version being supported. At the moment, it is draft-29. */ -#define QUICLY_PROTOCOL_VERSION_CURRENT 0xff00001d +#define QUICLY_PROTOCOL_VERSION_DRAFT29 0xff00001d /** * Draft-27 is also supported. */ @@ -1173,7 +1177,8 @@ extern const quicly_stream_callbacks_t quicly_stream_noop_callbacks; inline int quicly_is_supported_version(uint32_t version) { switch (version) { - case QUICLY_PROTOCOL_VERSION_CURRENT: + case QUICLY_PROTOCOL_VERSION_1: + case QUICLY_PROTOCOL_VERSION_DRAFT29: case QUICLY_PROTOCOL_VERSION_DRAFT27: return 1; default: diff --git a/lib/defaults.c b/lib/defaults.c index 6377f090a..92c12e053 100644 --- a/lib/defaults.c +++ b/lib/defaults.c @@ -42,7 +42,7 @@ const quicly_context_t quicly_spec_context = {NULL, DEFAULT_MAX_PACKETS_PER_KEY, DEFAULT_MAX_CRYPTO_BYTES, DEFAULT_INITCWND_PACKETS, - QUICLY_PROTOCOL_VERSION_CURRENT, + QUICLY_PROTOCOL_VERSION_1, DEFAULT_PRE_VALIDATION_AMPLIFICATION_LIMIT, 0, /* enlarge_client_hello */ NULL, @@ -69,7 +69,7 @@ const quicly_context_t quicly_performant_context = {NULL, DEFAULT_MAX_PACKETS_PER_KEY, DEFAULT_MAX_CRYPTO_BYTES, DEFAULT_INITCWND_PACKETS, - QUICLY_PROTOCOL_VERSION_CURRENT, + QUICLY_PROTOCOL_VERSION_1, DEFAULT_PRE_VALIDATION_AMPLIFICATION_LIMIT, 0, /* enlarge_client_hello */ NULL, diff --git a/lib/quicly.c b/lib/quicly.c index 5c63b6a23..80d48d05d 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -451,22 +451,27 @@ static const quicly_transport_parameters_t default_transport_params = {.max_udp_ static const struct st_ptls_salt_t *get_salt(uint32_t protocol_version) { - static const struct st_ptls_salt_t current = {.initial = {0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, - 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99}, - .retry = {.key = {0xcc, 0xce, 0x18, 0x7e, 0xd0, 0x9a, 0x09, 0xd0, 0x57, 0x28, - 0x15, 0x5a, 0x6c, 0xb9, 0x6b, 0xe1}, - .iv = {0xe5, 0x49, 0x30, 0xf9, 0x7f, 0x21, 0x36, 0xf0, 0x53, 0x0a, 0x8c, - 0x1c}}}, - draft27 = {.initial = {0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb, 0x5a, 0x11, 0xa7, - 0xd2, 0x43, 0x2b, 0xb4, 0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02}, - .retry = {.key = {0x4d, 0x32, 0xec, 0xdb, 0x2a, 0x21, 0x33, 0xc8, 0x41, 0xe4, - 0x04, 0x3d, 0xf2, 0x7d, 0x44, 0x30}, - .iv = {0x4d, 0x16, 0x11, 0xd0, 0x55, 0x13, 0xa5, 0x52, 0xc5, 0x87, 0xd5, - 0x75}}}; + static const struct st_ptls_salt_t + v1 = {.initial = {0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, + 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a}, + .retry = {.key = {0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a, 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e}, + .iv = {0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb}}}, + draft29 = {.initial = {0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, + 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99}, + .retry = {.key = {0xcc, 0xce, 0x18, 0x7e, 0xd0, 0x9a, 0x09, 0xd0, 0x57, 0x28, 0x15, 0x5a, 0x6c, 0xb9, 0x6b, + 0xe1}, + .iv = {0xe5, 0x49, 0x30, 0xf9, 0x7f, 0x21, 0x36, 0xf0, 0x53, 0x0a, 0x8c, 0x1c}}}, + draft27 = { + .initial = {0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb, 0x5a, 0x11, 0xa7, + 0xd2, 0x43, 0x2b, 0xb4, 0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02}, + .retry = {.key = {0x4d, 0x32, 0xec, 0xdb, 0x2a, 0x21, 0x33, 0xc8, 0x41, 0xe4, 0x04, 0x3d, 0xf2, 0x7d, 0x44, 0x30}, + .iv = {0x4d, 0x16, 0x11, 0xd0, 0x55, 0x13, 0xa5, 0x52, 0xc5, 0x87, 0xd5, 0x75}}}; switch (protocol_version) { - case QUICLY_PROTOCOL_VERSION_CURRENT: - return ¤t; + case QUICLY_PROTOCOL_VERSION_1: + return &v1; + case QUICLY_PROTOCOL_VERSION_DRAFT29: + return &draft29; case QUICLY_PROTOCOL_VERSION_DRAFT27: return &draft27; break; @@ -657,7 +662,8 @@ size_t quicly_decode_packet(quicly_context_t *ctx, quicly_decoded_packet_t *pack break; } switch (packet->version) { - case QUICLY_PROTOCOL_VERSION_CURRENT: + case QUICLY_PROTOCOL_VERSION_1: + case QUICLY_PROTOCOL_VERSION_DRAFT29: case QUICLY_PROTOCOL_VERSION_DRAFT27: /* these are the recognized versions, and they share the same packet header format */ if ((packet->octets.base[0] & QUICLY_PACKET_TYPE_BITMASK) == QUICLY_PACKET_TYPE_RETRY) { @@ -5064,12 +5070,16 @@ static int handle_version_negotiation_packet(quicly_conn_t *conn, quicly_decoded if (src == end || (end - src) % 4 != 0) return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; - /* select in the precedence of _CURRENT -> _DRAFT27 -> fail */ + /* select in the precedence of V1 -> draft29 -> draft27 -> fail */ while (src != end) { uint32_t supported_version = quicly_decode32(&src); switch (supported_version) { - case QUICLY_PROTOCOL_VERSION_CURRENT: - selected_version = QUICLY_PROTOCOL_VERSION_CURRENT; + case QUICLY_PROTOCOL_VERSION_1: + selected_version = QUICLY_PROTOCOL_VERSION_1; + break; + case QUICLY_PROTOCOL_VERSION_DRAFT29: + if (selected_version == 0 || selected_version == QUICLY_PROTOCOL_VERSION_DRAFT27) + selected_version = QUICLY_PROTOCOL_VERSION_DRAFT29; break; case QUICLY_PROTOCOL_VERSION_DRAFT27: if (selected_version == 0) @@ -6337,4 +6347,5 @@ void quicly__debug_printf(quicly_conn_t *conn, const char *function, int line, c #endif } -const uint32_t quicly_supported_versions[] = {QUICLY_PROTOCOL_VERSION_CURRENT, QUICLY_PROTOCOL_VERSION_DRAFT27, 0}; +const uint32_t quicly_supported_versions[] = {QUICLY_PROTOCOL_VERSION_1, QUICLY_PROTOCOL_VERSION_DRAFT29, + QUICLY_PROTOCOL_VERSION_DRAFT27, 0}; diff --git a/t/test.c b/t/test.c index 1d4fdaa55..a89c3bb64 100644 --- a/t/test.c +++ b/t/test.c @@ -241,7 +241,7 @@ static void test_vector(void) ok(off == sizeof(datagram)); /* decrypt */ - const struct st_ptls_salt_t *salt = get_salt(QUICLY_PROTOCOL_VERSION_CURRENT); + const struct st_ptls_salt_t *salt = get_salt(QUICLY_PROTOCOL_VERSION_DRAFT29); ret = setup_initial_encryption(&ptls_openssl_aes128gcmsha256, &ingress, &egress, packet.cid.dest.encrypted, 0, ptls_iovec_init(salt->initial, sizeof(salt->initial)), NULL); ok(ret == 0); @@ -269,7 +269,7 @@ static void test_retry_aead(void) ok(off == sizeof(packet_bytes)); /* decrypt */ - ptls_aead_context_t *retry_aead = create_retry_aead(&quic_ctx, QUICLY_PROTOCOL_VERSION_CURRENT, 0); + ptls_aead_context_t *retry_aead = create_retry_aead(&quic_ctx, QUICLY_PROTOCOL_VERSION_DRAFT29, 0); ok(validate_retry_tag(&decoded, &odcid, retry_aead)); ptls_aead_free(retry_aead); } From ab4417595cf64943ab25c4854de226f64a08c6c5 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sat, 3 Jul 2021 10:33:53 +0900 Subject: [PATCH 118/361] use the final TLS extension ID --- lib/quicly.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 80d48d05d..8ff743ef1 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -42,7 +42,8 @@ #endif #include "quicly/retire_cid.h" -#define QUICLY_TLS_EXTENSION_TYPE_TRANSPORT_PARAMETERS 0xffa5 +#define QUICLY_TLS_EXTENSION_TYPE_TRANSPORT_PARAMETERS_FINAL 0x39 +#define QUICLY_TLS_EXTENSION_TYPE_TRANSPORT_PARAMETERS_DRAFT 0xffa5 #define QUICLY_TRANSPORT_PARAMETER_ID_ORIGINAL_CONNECTION_ID 0 #define QUICLY_TRANSPORT_PARAMETER_ID_MAX_IDLE_TIMEOUT 1 #define QUICLY_TRANSPORT_PARAMETER_ID_STATELESS_RESET_TOKEN 2 @@ -2013,9 +2014,21 @@ int quicly_decode_transport_parameter_list(quicly_transport_parameters_t *params #undef DECODE_CID_TP } +static uint16_t get_transport_parameters_extension_id(uint32_t quic_version) +{ + switch (quic_version) { + case QUICLY_PROTOCOL_VERSION_DRAFT27: + case QUICLY_PROTOCOL_VERSION_DRAFT29: + return QUICLY_TLS_EXTENSION_TYPE_TRANSPORT_PARAMETERS_DRAFT; + default: + return QUICLY_TLS_EXTENSION_TYPE_TRANSPORT_PARAMETERS_FINAL; + } +} + static int collect_transport_parameters(ptls_t *tls, struct st_ptls_handshake_properties_t *properties, uint16_t type) { - return type == QUICLY_TLS_EXTENSION_TYPE_TRANSPORT_PARAMETERS; + quicly_conn_t *conn = (void *)((char *)properties - offsetof(quicly_conn_t, crypto.handshake_properties)); + return type == get_transport_parameters_extension_id(conn->super.version); } static quicly_conn_t *create_connection(quicly_context_t *ctx, uint32_t protocol_version, const char *server_name, @@ -2122,7 +2135,7 @@ static int client_collected_extensions(ptls_t *tls, ptls_handshake_properties_t ret = PTLS_ALERT_MISSING_EXTENSION; goto Exit; } - assert(slots[0].type == QUICLY_TLS_EXTENSION_TYPE_TRANSPORT_PARAMETERS); + assert(slots[0].type == get_transport_parameters_extension_id(conn->super.version)); assert(slots[1].type == UINT16_MAX); const uint8_t *src = slots[0].data.base, *end = src + slots[0].data.len; @@ -2245,7 +2258,7 @@ int quicly_connect(quicly_conn_t **_conn, quicly_context_t *ctx, const char *ser NULL, NULL, conn->super.ctx->expand_client_hello ? conn->super.ctx->initial_egress_max_udp_payload_size : 0)) != 0) goto Exit; conn->crypto.transport_params.ext[0] = - (ptls_raw_extension_t){QUICLY_TLS_EXTENSION_TYPE_TRANSPORT_PARAMETERS, + (ptls_raw_extension_t){get_transport_parameters_extension_id(conn->super.version), {conn->crypto.transport_params.buf.base, conn->crypto.transport_params.buf.off}}; conn->crypto.transport_params.ext[1] = (ptls_raw_extension_t){UINT16_MAX}; conn->crypto.handshake_properties.additional_extensions = conn->crypto.transport_params.ext; @@ -2301,7 +2314,7 @@ static int server_collected_extensions(ptls_t *tls, ptls_handshake_properties_t ret = PTLS_ALERT_MISSING_EXTENSION; goto Exit; } - assert(slots[0].type == QUICLY_TLS_EXTENSION_TYPE_TRANSPORT_PARAMETERS); + assert(slots[0].type == get_transport_parameters_extension_id(conn->super.version)); assert(slots[1].type == UINT16_MAX); { /* decode transport_parameters extension */ @@ -2346,7 +2359,7 @@ static int server_collected_extensions(ptls_t *tls, ptls_handshake_properties_t goto Exit; properties->additional_extensions = conn->crypto.transport_params.ext; conn->crypto.transport_params.ext[0] = - (ptls_raw_extension_t){QUICLY_TLS_EXTENSION_TYPE_TRANSPORT_PARAMETERS, + (ptls_raw_extension_t){get_transport_parameters_extension_id(conn->super.version), {conn->crypto.transport_params.buf.base, conn->crypto.transport_params.buf.off}}; conn->crypto.transport_params.ext[1] = (ptls_raw_extension_t){UINT16_MAX}; conn->crypto.handshake_properties.additional_extensions = conn->crypto.transport_params.ext; @@ -5047,9 +5060,10 @@ static int negotiate_using_version(quicly_conn_t *conn, uint32_t version) { int ret; - /* set selected version */ + /* set selected version, update transport parameters extension ID */ conn->super.version = version; QUICLY_PROBE(VERSION_SWITCH, conn, conn->stash.now, version); + conn->crypto.transport_params.ext[0].type = get_transport_parameters_extension_id(version); /* replace initial keys */ if ((ret = reinstall_initial_encryption(conn, PTLS_ERROR_LIBRARY)) != 0) From 7ab8165a880309d0e8264f506c259f1c6790dec4 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sat, 3 Jul 2021 15:43:24 +0900 Subject: [PATCH 119/361] public API for changing CC --- include/quicly.h | 4 ++++ lib/quicly.c | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/include/quicly.h b/include/quicly.h index adbc992bf..79653cede 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -1096,6 +1096,10 @@ static int quicly_stream_is_self_initiated(quicly_stream_t *stream); * * While the API is designed to look like synchronous, application still has to call `quicly_send` for the time being. */ void quicly_send_datagram_frames(quicly_conn_t *conn, ptls_iovec_t *datagrams, size_t num_datagrams); +/** + * Sets CC to the specified type. Returns a boolean indicating if the operation was successful. + */ +int quicly_set_cc(quicly_conn_t *conn, quicly_cc_type_t *cc); /** * */ diff --git a/lib/quicly.c b/lib/quicly.c index 5c63b6a23..3470fedf6 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -4413,6 +4413,11 @@ void quicly_send_datagram_frames(quicly_conn_t *conn, ptls_iovec_t *datagrams, s } } +int quicly_set_cc(quicly_conn_t *conn, quicly_cc_type_t *cc) +{ + return cc->cc_switch(&conn->egress.cc); +} + int quicly_send(quicly_conn_t *conn, quicly_address_t *dest, quicly_address_t *src, struct iovec *datagrams, size_t *num_datagrams, void *buf, size_t bufsize) { From 15901f07ada01f244b08b56bcb7cd1f44e99fe1b Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 5 Jul 2021 11:38:04 +0900 Subject: [PATCH 120/361] add docker-based CI runner --- misc/docker-ci.mk | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 misc/docker-ci.mk diff --git a/misc/docker-ci.mk b/misc/docker-ci.mk new file mode 100644 index 000000000..bfa116af1 --- /dev/null +++ b/misc/docker-ci.mk @@ -0,0 +1,23 @@ +CONTAINER_NAME=h2oserver/h2o-ci:ubuntu2004 +SRC_DIR=/quicly +CI_MK=$(SRC_DIR)/misc/docker-ci.mk +CMAKE_ARGS= +DOCKER_RUN_OPTS=--privileged \ + -v `pwd`:$(SRC_DIR) \ + -it + +ALL: + docker run $(DOCKER_RUN_OPTS) $(CONTAINER_NAME) make -f $(CI_MK) _check + +_check: + uname -a + mkdir -p build + sudo mount -t tmpfs tmpfs build -o size=3G + sudo chown -R ci:ci build + sudo chmod 0755 build + $(MAKE) -f $(CI_MK) -C build _do-check CMAKE_ARGS=$(CMAKE_ARGS) + +_do-check: + cmake $(CMAKE_ARGS) -H$(SRC_DIR) -B. + make all + make check From 135e4eca88d213cee0ad70604c5951195776b95c Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 5 Jul 2021 12:10:19 +0900 Subject: [PATCH 121/361] run using GitHub Actions --- .github/workflows/ci.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..66054df1b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,30 @@ +name: CI + +on: [push, pull_request] + +jobs: + build: + name: "${{ matrix.name }}" + runs-on: [ubuntu-20.04] + + # We want to run on external PRs, but not on our own internal PRs as they'll be run + # by the push to the branch. + if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository + + strategy: + fail-fast: false + matrix: + include: + - name: default + command: make -f misc/docker-ci.mk + + timeout-minutes: 10 + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Run with Docker + shell: 'script -q -e -c "bash -xe {0}"' + run: | + chmod -R ugo+w . + ${{ matrix.command }} From ccb77e6d083f30cd6034074e76d15f12110fd8ee Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 5 Jul 2021 16:03:36 +0900 Subject: [PATCH 122/361] send CID authentication extensions when v1 is used --- lib/quicly.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index b884c31ec..5040be0b0 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -588,7 +588,13 @@ static int is_retry(quicly_conn_t *conn) static int needs_cid_auth(quicly_conn_t *conn) { - return conn->super.version > QUICLY_PROTOCOL_VERSION_DRAFT27; + switch (conn->super.version) { + case QUICLY_PROTOCOL_VERSION_1: + case QUICLY_PROTOCOL_VERSION_DRAFT29: + return 1; + default: + return 0; + } } static int recognize_delayed_ack(quicly_conn_t *conn) From d348452534b9109d636da460a35e82c195befd83 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 5 Jul 2021 16:03:50 +0900 Subject: [PATCH 123/361] add public API to obtain version being used --- include/quicly.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/quicly.h b/include/quicly.h index 20c775f68..7e84d5a27 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -867,6 +867,10 @@ int quicly_get_stats(quicly_conn_t *conn, quicly_stats_t *stats); * */ void quicly_get_max_data(quicly_conn_t *conn, uint64_t *send_permitted, uint64_t *sent, uint64_t *consumed); +/** + * + */ +static uint32_t quicly_get_protocol_version(quicly_conn_t *conn); /** * */ @@ -1262,6 +1266,12 @@ inline struct sockaddr *quicly_get_peername(quicly_conn_t *conn) return &c->remote.address.sa; } +inline uint32_t quicly_get_protocol_version(quicly_conn_t *conn) +{ + struct _st_quicly_conn_public_t *c = (struct _st_quicly_conn_public_t *)conn; + return c->version; +} + inline void **quicly_get_data(quicly_conn_t *conn) { struct _st_quicly_conn_public_t *c = (struct _st_quicly_conn_public_t *)conn; From 137fd1a032bdbf0be6b954be8444121c45a30f52 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 5 Jul 2021 16:06:43 +0900 Subject: [PATCH 124/361] update tests --- t/e2e.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/e2e.t b/t/e2e.t index d9ec76247..05a35f3bf 100755 --- a/t/e2e.t +++ b/t/e2e.t @@ -85,8 +85,8 @@ subtest "version-negotiation" => sub { is $resp, "hello world\n"; my $events = slurp_file("$tempdir/events"); if ($events =~ /"type":"connect",.*"version":(\d+)(?:.|\n)*"type":"version-switch",.*"new-version":(\d+)/m) { - is $2, 0xff00001d; - isnt $1, 0xff00001d; + is $2, 1; + isnt $1, 1; } else { fail "no quic-version-switch event"; diag $events; From e51d3bdfbc3a68c0be4503ccc821933fbe730297 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 7 Jul 2021 11:33:24 +0900 Subject: [PATCH 125/361] pad datagrams to full-size so that they can be sent using GSO --- lib/quicly.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 5040be0b0..634a41684 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3145,7 +3145,10 @@ static int _do_allocate_frame(quicly_conn_t *conn, quicly_send_context_t *s, siz if (overhead + packet_min_space > s->dst_end - s->dst) coalescible = 0; } - /* close out packet under construction */ + /* Close the packet under construction. Datagrams being returned by `quicly_send` are padded to full-size (except for the + * last one datagram) so that they can be sent at once using GSO. */ + if (!coalescible) + s->target.full_size = 1; if ((ret = commit_send_packet(conn, s, coalescible)) != 0) return ret; } else { From dc90bdde405d3dd55db43320791790633cc65f7f Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 8 Jul 2021 15:33:44 +0900 Subject: [PATCH 126/361] TLS extension ID is different bet. draft versions, but we do not have a way of rebuilding ClientHello when we receive a Version Negotiation packet. The next best thing we can do is send the extension using both IDs --- lib/quicly.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 5040be0b0..2b35c5f6f 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -357,7 +357,7 @@ struct st_quicly_conn_t { ptls_t *tls; ptls_handshake_properties_t handshake_properties; struct { - ptls_raw_extension_t ext[2]; + ptls_raw_extension_t ext[3]; ptls_buffer_t buf; } transport_params; } crypto; @@ -2264,9 +2264,12 @@ int quicly_connect(quicly_conn_t **_conn, quicly_context_t *ctx, const char *ser NULL, NULL, conn->super.ctx->expand_client_hello ? conn->super.ctx->initial_egress_max_udp_payload_size : 0)) != 0) goto Exit; conn->crypto.transport_params.ext[0] = - (ptls_raw_extension_t){get_transport_parameters_extension_id(conn->super.version), + (ptls_raw_extension_t){QUICLY_TLS_EXTENSION_TYPE_TRANSPORT_PARAMETERS_FINAL, {conn->crypto.transport_params.buf.base, conn->crypto.transport_params.buf.off}}; - conn->crypto.transport_params.ext[1] = (ptls_raw_extension_t){UINT16_MAX}; + conn->crypto.transport_params.ext[1] = + (ptls_raw_extension_t){QUICLY_TLS_EXTENSION_TYPE_TRANSPORT_PARAMETERS_DRAFT, + {conn->crypto.transport_params.buf.base, conn->crypto.transport_params.buf.off}}; + conn->crypto.transport_params.ext[2] = (ptls_raw_extension_t){UINT16_MAX}; conn->crypto.handshake_properties.additional_extensions = conn->crypto.transport_params.ext; conn->crypto.handshake_properties.collected_extensions = client_collected_extensions; @@ -5074,7 +5077,6 @@ static int negotiate_using_version(quicly_conn_t *conn, uint32_t version) /* set selected version, update transport parameters extension ID */ conn->super.version = version; QUICLY_PROBE(VERSION_SWITCH, conn, conn->stash.now, version); - conn->crypto.transport_params.ext[0].type = get_transport_parameters_extension_id(version); /* replace initial keys */ if ((ret = reinstall_initial_encryption(conn, PTLS_ERROR_LIBRARY)) != 0) From 2cc6b4fd793d69f1a2e28f454bf42ef151606a22 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 9 Jul 2021 11:40:54 +0900 Subject: [PATCH 127/361] add tracepoints for RESET_STREAM / STOP_SENDING --- lib/quicly.c | 6 ++++++ quicly-probes.d | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/lib/quicly.c b/lib/quicly.c index 09bf62b58..778bb7ae2 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3352,6 +3352,8 @@ static int send_control_frames_of_stream(quicly_stream_t *stream, quicly_send_co return ret; s->dst = quicly_encode_stop_sending_frame(s->dst, stream->stream_id, stream->_send_aux.stop_sending.error_code); ++stream->conn->super.stats.num_frames_sent.stop_sending; + QUICLY_PROBE(STOP_SENDING_SEND, stream->conn, stream->conn->stash.now, stream->stream_id, + stream->_send_aux.stop_sending.error_code); } /* send MAX_STREAM_DATA if necessary */ @@ -3380,6 +3382,8 @@ static int send_control_frames_of_stream(quicly_stream_t *stream, quicly_send_co s->dst = quicly_encode_reset_stream_frame(s->dst, stream->stream_id, stream->_send_aux.reset_stream.error_code, stream->sendstate.size_inflight); ++stream->conn->super.stats.num_frames_sent.reset_stream; + QUICLY_PROBE(RESET_STREAM_SEND, stream->conn, stream->conn->stash.now, stream->stream_id, + stream->_send_aux.reset_stream.error_code, stream->sendstate.size_inflight); } /* send STREAM_DATA_BLOCKED if necessary */ @@ -4747,6 +4751,7 @@ static int handle_reset_stream_frame(quicly_conn_t *conn, struct st_quicly_handl if ((ret = quicly_decode_reset_stream_frame(&state->src, state->end, &frame)) != 0) return ret; + QUICLY_PROBE(RESET_STREAM_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.app_error_code, frame.final_size); if ((ret = quicly_get_or_open_stream(conn, frame.stream_id, &stream)) != 0 || stream == NULL) return ret; @@ -5038,6 +5043,7 @@ static int handle_stop_sending_frame(quicly_conn_t *conn, struct st_quicly_handl if ((ret = quicly_decode_stop_sending_frame(&state->src, state->end, &frame)) != 0) return ret; + QUICLY_PROBE(STOP_SENDING_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.app_error_code); if ((ret = quicly_get_or_open_stream(conn, frame.stream_id, &stream)) != 0 || stream == NULL) return ret; diff --git a/quicly-probes.d b/quicly-probes.d index 18fb9d408..8a163f19a 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -87,6 +87,12 @@ provider quicly { probe stream_acked(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t off, size_t len); probe stream_lost(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t off, size_t len); + probe reset_stream_send(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint16_t error_code, uint64_t final_size); + probe reset_stream_receive(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint16_t error_code, uint64_t final_size); + + probe stop_sending_send(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint16_t error_code); + probe stop_sending_receive(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint16_t error_code); + probe max_data_send(struct st_quicly_conn_t *conn, int64_t at, uint64_t maximum); probe max_data_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t maximum); From 5e649bbaf38c8abf5d2230b835278b92441acc91 Mon Sep 17 00:00:00 2001 From: "Nabil S. Alramli" Date: Mon, 26 Jul 2021 15:01:11 -0400 Subject: [PATCH 128/361] Implement quicly_stats_t.num_bytes.lost, quicly_stats_t.num_bytes.lost_pending, quicly_stats_t.num_bytes.resent --- include/quicly.h | 12 ++++++++++++ lib/quicly.c | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/include/quicly.h b/include/quicly.h index 7e84d5a27..1590ede3d 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -435,6 +435,18 @@ struct st_quicly_conn_streamgroup_state_t { * Total bytes sent, at UDP datagram-level. \ */ \ uint64_t sent; \ + /** \ + * Total bytes sent but lost, at UDP datagram-level. \ + */ \ + uint64_t lost; \ + /** \ + * Bytes lost but pending to be resent, at UDP datagram-level. \ + */ \ + uint64_t lost_pending; \ + /** \ + * Total bytes resent, at UDP datagram-level. \ + */ \ + uint64_t resent; \ } num_bytes; \ /** \ * Total number of each frame being sent / received. \ diff --git a/lib/quicly.c b/lib/quicly.c index 778bb7ae2..5372c632b 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -104,6 +104,8 @@ KHASH_MAP_INIT_INT64(quicly_stream_t, quicly_stream_t *) quicly_escape_unsafe_string(alloca(_l * 4 + 1), (s), _l); \ }) +# define QUICLY_MIN(x, y) ((x) < (y) ? (x) : (y)) + struct st_quicly_cipher_context_t { ptls_aead_context_t *aead; ptls_cipher_context_t *header_protection; @@ -3080,11 +3082,16 @@ static int commit_send_packet(quicly_conn_t *conn, quicly_send_context_t *s, int ++conn->super.stats.num_packets.sent; if (!coalesced) { + uint64_t resend_size = QUICLY_MIN(conn->super.stats.num_bytes.lost_pending, datagram_size); conn->super.stats.num_bytes.sent += datagram_size; s->datagrams[s->num_datagrams++] = (struct iovec){.iov_base = s->payload_buf.datagram, .iov_len = datagram_size}; s->payload_buf.datagram += datagram_size; s->target.cipher = NULL; s->target.first_byte_at = NULL; + if (resend_size > UINT64_C(0)) { + conn->super.stats.num_bytes.resent += resend_size; + conn->super.stats.num_bytes.lost_pending -= resend_size; + } } /* insert PN gap if necessary, registering the PN to the ack queue so that we'd close the connection in the event of receiving @@ -3665,6 +3672,8 @@ static void on_loss_detected(quicly_loss_t *loss, const quicly_sent_packet_t *lo ++conn->super.stats.num_packets.lost; if (is_time_threshold) ++conn->super.stats.num_packets.lost_time_threshold; + conn->super.stats.num_bytes.lost += lost_packet->cc_bytes_in_flight; + conn->super.stats.num_bytes.lost_pending += lost_packet->cc_bytes_in_flight; conn->egress.cc.type->cc_on_lost(&conn->egress.cc, &conn->egress.loss, lost_packet->cc_bytes_in_flight, lost_packet->packet_number, conn->egress.packet_number, conn->stash.now, conn->egress.max_udp_payload_size); From cf92950b9bb14346718c7cea014423a6d74c1d74 Mon Sep 17 00:00:00 2001 From: "Nabil S. Alramli" Date: Mon, 2 Aug 2021 15:30:33 -0400 Subject: [PATCH 129/361] Implement quicly_stats_t.num_bytes.stream_data_sent and quicly_stats_t.num_bytes.stream_data_resent and remove incorrect quicly_stats_t.num_bytes.resent --- include/quicly.h | 8 ++++---- lib/quicly.c | 9 +++------ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index 1590ede3d..5dc976bca 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -440,13 +440,13 @@ struct st_quicly_conn_streamgroup_state_t { */ \ uint64_t lost; \ /** \ - * Bytes lost but pending to be resent, at UDP datagram-level. \ + * Total STREAM_DATA bytes sent \ */ \ - uint64_t lost_pending; \ + uint64_t stream_data_sent; \ /** \ - * Total bytes resent, at UDP datagram-level. \ + * Total STREAM_DATA bytes resent \ */ \ - uint64_t resent; \ + uint64_t stream_data_resent; \ } num_bytes; \ /** \ * Total number of each frame being sent / received. \ diff --git a/lib/quicly.c b/lib/quicly.c index 5372c632b..b1c940e79 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3082,16 +3082,11 @@ static int commit_send_packet(quicly_conn_t *conn, quicly_send_context_t *s, int ++conn->super.stats.num_packets.sent; if (!coalesced) { - uint64_t resend_size = QUICLY_MIN(conn->super.stats.num_bytes.lost_pending, datagram_size); conn->super.stats.num_bytes.sent += datagram_size; s->datagrams[s->num_datagrams++] = (struct iovec){.iov_base = s->payload_buf.datagram, .iov_len = datagram_size}; s->payload_buf.datagram += datagram_size; s->target.cipher = NULL; s->target.first_byte_at = NULL; - if (resend_size > UINT64_C(0)) { - conn->super.stats.num_bytes.resent += resend_size; - conn->super.stats.num_bytes.lost_pending -= resend_size; - } } /* insert PN gap if necessary, registering the PN to the ack queue so that we'd close the connection in the event of receiving @@ -3586,6 +3581,9 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) } else { ++stream->conn->super.stats.num_frames_sent.stream; } + stream->conn->super.stats.num_bytes.stream_data_sent += end_off - off; + if (off < stream->sendstate.size_inflight) + stream->conn->super.stats.num_bytes.stream_data_resent += QUICLY_MIN(stream->sendstate.size_inflight, end_off) - off; QUICLY_PROBE(STREAM_SEND, stream->conn, stream->conn->stash.now, stream, off, end_off - off, is_fin); QUICLY_PROBE(QUICTRACE_SEND_STREAM, stream->conn, stream->conn->stash.now, stream, off, end_off - off, is_fin); /* update sendstate (and also MAX_DATA counter) */ @@ -3673,7 +3671,6 @@ static void on_loss_detected(quicly_loss_t *loss, const quicly_sent_packet_t *lo if (is_time_threshold) ++conn->super.stats.num_packets.lost_time_threshold; conn->super.stats.num_bytes.lost += lost_packet->cc_bytes_in_flight; - conn->super.stats.num_bytes.lost_pending += lost_packet->cc_bytes_in_flight; conn->egress.cc.type->cc_on_lost(&conn->egress.cc, &conn->egress.loss, lost_packet->cc_bytes_in_flight, lost_packet->packet_number, conn->egress.packet_number, conn->stash.now, conn->egress.max_udp_payload_size); From be764c7a4d4f9e65b5732e935aee7970bf19c8af Mon Sep 17 00:00:00 2001 From: "Nabil S. Alramli" Date: Mon, 2 Aug 2021 18:12:50 -0400 Subject: [PATCH 130/361] https://github.com/h2o/quicly/pull/482#pullrequestreview-720619603 --- include/quicly.h | 4 ++-- lib/quicly.c | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index 5dc976bca..38d84593d 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -440,11 +440,11 @@ struct st_quicly_conn_streamgroup_state_t { */ \ uint64_t lost; \ /** \ - * Total STREAM_DATA bytes sent \ + * Total amount of stream-level payload being sent \ */ \ uint64_t stream_data_sent; \ /** \ - * Total STREAM_DATA bytes resent \ + * Total amount of stream-level payload being resent \ */ \ uint64_t stream_data_resent; \ } num_bytes; \ diff --git a/lib/quicly.c b/lib/quicly.c index b1c940e79..d87f9b154 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -104,8 +104,6 @@ KHASH_MAP_INIT_INT64(quicly_stream_t, quicly_stream_t *) quicly_escape_unsafe_string(alloca(_l * 4 + 1), (s), _l); \ }) -# define QUICLY_MIN(x, y) ((x) < (y) ? (x) : (y)) - struct st_quicly_cipher_context_t { ptls_aead_context_t *aead; ptls_cipher_context_t *header_protection; @@ -3583,7 +3581,8 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) } stream->conn->super.stats.num_bytes.stream_data_sent += end_off - off; if (off < stream->sendstate.size_inflight) - stream->conn->super.stats.num_bytes.stream_data_resent += QUICLY_MIN(stream->sendstate.size_inflight, end_off) - off; + stream->conn->super.stats.num_bytes.stream_data_resent += + (stream->sendstate.size_inflight < end_off ? stream->sendstate.size_inflight : end_off) - off; QUICLY_PROBE(STREAM_SEND, stream->conn, stream->conn->stash.now, stream, off, end_off - off, is_fin); QUICLY_PROBE(QUICTRACE_SEND_STREAM, stream->conn, stream->conn->stash.now, stream, off, end_off - off, is_fin); /* update sendstate (and also MAX_DATA counter) */ From 797252f2ecf0d881f552be948f345229fd3e8acc Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 24 Aug 2021 21:57:08 +0900 Subject: [PATCH 131/361] simulator works --- CMakeLists.txt | 4 + quicly.xcodeproj/project.pbxproj | 150 +++++++++ t/simulator.c | 522 +++++++++++++++++++++++++++++++ 3 files changed, 676 insertions(+) create mode 100644 t/simulator.c diff --git a/CMakeLists.txt b/CMakeLists.txt index a2ed00ec0..d12cf6db8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,6 +121,10 @@ TARGET_LINK_LIBRARIES(cli ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS} m) ADD_EXECUTABLE(test.t ${PICOTLS_OPENSSL_FILES} ${UNITTEST_SOURCE_FILES}) TARGET_LINK_LIBRARIES(test.t quicly ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS}) +ADD_EXECUTABLE(simulator ${PICOTLS_OPENSSL_FILES} ${QUICLY_LIBRARY_FILES} t/simulator.c embedded-probes.h) +SET_TARGET_PROPERTIES(simulator PROPERTIES COMPILE_FLAGS "-DQUICLY_USE_EMBEDDED_PROBES=1") +TARGET_LINK_LIBRARIES(simulator ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS} m) + ADD_EXECUTABLE(examples-echo ${PICOTLS_OPENSSL_FILES} examples/echo.c) TARGET_LINK_LIBRARIES(examples-echo quicly ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS}) diff --git a/quicly.xcodeproj/project.pbxproj b/quicly.xcodeproj/project.pbxproj index 2f7ac86d1..182256904 100644 --- a/quicly.xcodeproj/project.pbxproj +++ b/quicly.xcodeproj/project.pbxproj @@ -10,6 +10,27 @@ 082195082683498900E3EFCF /* cc-pico.c in Sources */ = {isa = PBXBuildFile; fileRef = 082195072683498900E3EFCF /* cc-pico.c */; }; 082195092683498900E3EFCF /* cc-pico.c in Sources */ = {isa = PBXBuildFile; fileRef = 082195072683498900E3EFCF /* cc-pico.c */; }; 0821950A2683498900E3EFCF /* cc-pico.c in Sources */ = {isa = PBXBuildFile; fileRef = 082195072683498900E3EFCF /* cc-pico.c */; }; + 0829876726D372B70053638F /* cc-cubic.c in Sources */ = {isa = PBXBuildFile; fileRef = E9DF012324E4BAC20002EEC7 /* cc-cubic.c */; }; + 0829876826D372B70053638F /* retire_cid.c in Sources */ = {isa = PBXBuildFile; fileRef = E9736528246FD3AC0039AA49 /* retire_cid.c */; }; + 0829876926D372B70053638F /* picotls-probes.d in Sources */ = {isa = PBXBuildFile; fileRef = E95E953A2290498E00215ACD /* picotls-probes.d */; }; + 0829876A26D372B70053638F /* ranges.c in Sources */ = {isa = PBXBuildFile; fileRef = E9F6A41F1F3C0B6D0083F0B2 /* ranges.c */; }; + 0829876B26D372B70053638F /* cc-reno.c in Sources */ = {isa = PBXBuildFile; fileRef = E98041C522383C62008B9745 /* cc-reno.c */; }; + 0829876C26D372B70053638F /* local_cid.c in Sources */ = {isa = PBXBuildFile; fileRef = E9736529246FD3AC0039AA49 /* local_cid.c */; }; + 0829876D26D372B70053638F /* openssl.c in Sources */ = {isa = PBXBuildFile; fileRef = E98448271EA48D0000390927 /* openssl.c */; }; + 0829876E26D372B70053638F /* remote_cid.c in Sources */ = {isa = PBXBuildFile; fileRef = E9736527246FD3AC0039AA49 /* remote_cid.c */; }; + 0829876F26D372B70053638F /* loss.c in Sources */ = {isa = PBXBuildFile; fileRef = E904233C24AED0410072C5B7 /* loss.c */; }; + 0829877026D372B70053638F /* cc-pico.c in Sources */ = {isa = PBXBuildFile; fileRef = 082195072683498900E3EFCF /* cc-pico.c */; }; + 0829877126D372B70053638F /* frame.c in Sources */ = {isa = PBXBuildFile; fileRef = E99F8C251F4E9EBF00C26B3D /* frame.c */; }; + 0829877226D372B70053638F /* recvstate.c in Sources */ = {isa = PBXBuildFile; fileRef = E920D21D1F43E05000799777 /* recvstate.c */; }; + 0829877326D372B70053638F /* fusion.c in Sources */ = {isa = PBXBuildFile; fileRef = E9B43E11246943D300824E51 /* fusion.c */; }; + 0829877426D372B70053638F /* defaults.c in Sources */ = {isa = PBXBuildFile; fileRef = E98042352244A5D7008B9745 /* defaults.c */; }; + 0829877526D372B70053638F /* streambuf.c in Sources */ = {isa = PBXBuildFile; fileRef = E9D3CCCE21D22F4300516202 /* streambuf.c */; }; + 0829877626D372B70053638F /* pembase64.c in Sources */ = {isa = PBXBuildFile; fileRef = E93E54681F663849001C50FE /* pembase64.c */; }; + 0829877826D372B70053638F /* sendstate.c in Sources */ = {isa = PBXBuildFile; fileRef = E9F6A42D1F41375B0083F0B2 /* sendstate.c */; }; + 0829877926D372B70053638F /* quicly.c in Sources */ = {isa = PBXBuildFile; fileRef = E98448411EA490A500390927 /* quicly.c */; }; + 0829877A26D372B70053638F /* sentmap.c in Sources */ = {isa = PBXBuildFile; fileRef = E920D22A1F49533800799777 /* sentmap.c */; }; + 0829877B26D372B70053638F /* picotls.c in Sources */ = {isa = PBXBuildFile; fileRef = E98448281EA48D0000390927 /* picotls.c */; }; + 0829878326D37E370053638F /* simulator.c in Sources */ = {isa = PBXBuildFile; fileRef = 0829878226D37E370053638F /* simulator.c */; }; E904233D24AED0410072C5B7 /* loss.c in Sources */ = {isa = PBXBuildFile; fileRef = E904233C24AED0410072C5B7 /* loss.c */; }; E904233E24AED0410072C5B7 /* loss.c in Sources */ = {isa = PBXBuildFile; fileRef = E904233C24AED0410072C5B7 /* loss.c */; }; E904233F24AED0410072C5B7 /* loss.c in Sources */ = {isa = PBXBuildFile; fileRef = E904233C24AED0410072C5B7 /* loss.c */; }; @@ -105,6 +126,15 @@ /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ + 0829877D26D372B70053638F /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; E9804223223952FD008B9745 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -145,6 +175,8 @@ /* Begin PBXFileReference section */ 082195072683498900E3EFCF /* cc-pico.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "cc-pico.c"; sourceTree = ""; }; + 0829878126D372B70053638F /* simulator */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = simulator; sourceTree = BUILT_PRODUCTS_DIR; }; + 0829878226D37E370053638F /* simulator.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = simulator.c; sourceTree = ""; }; E904233C24AED0410072C5B7 /* loss.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = loss.c; sourceTree = ""; }; E904234024AEFB980072C5B7 /* loss.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = loss.c; sourceTree = ""; }; E9056C071F56965300E2B96C /* linklist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = linklist.h; sourceTree = ""; }; @@ -222,6 +254,13 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 0829877C26D372B70053638F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; E9804221223952FD008B9745 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -311,6 +350,7 @@ E9CC44231EC195DF00DC7D3E /* test */, E98F4CBB20E5CF1B00362F15 /* udpfw */, E9804227223952FD008B9745 /* echo */, + 0829878126D372B70053638F /* simulator */, ); name = Products; sourceTree = ""; @@ -429,6 +469,7 @@ E9F6A4281F3C3B3F0083F0B2 /* test.h */, E9CC44241EC1962700DC7D3E /* test.c */, E98F4CBC20E5CF3A00362F15 /* udpfw.c */, + 0829878226D37E370053638F /* simulator.c */, ); path = t; sourceTree = ""; @@ -510,6 +551,24 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + 0829876426D372B70053638F /* simulator */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0829877E26D372B70053638F /* Build configuration list for PBXNativeTarget "simulator" */; + buildPhases = ( + 0829876526D372B70053638F /* ShellScript */, + 0829876626D372B70053638F /* Sources */, + 0829877C26D372B70053638F /* Frameworks */, + 0829877D26D372B70053638F /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = simulator; + productName = cli; + productReference = 0829878126D372B70053638F /* simulator */; + productType = "com.apple.product-type.tool"; + }; E980421C223952FD008B9745 /* echo */ = { isa = PBXNativeTarget; buildConfigurationList = E9804224223952FD008B9745 /* Build configuration list for PBXNativeTarget "echo" */; @@ -633,11 +692,31 @@ E9CC44191EC195DF00DC7D3E /* test */, E98F4C9D20E5CF1B00362F15 /* udpfw */, E980421C223952FD008B9745 /* echo */, + 0829876426D372B70053638F /* simulator */, ); }; /* End PBXProject section */ /* Begin PBXShellScriptBuildPhase section */ + 0829876526D372B70053638F /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "$(SRCROOT)/quicly-probes.d", + ); + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILES_DIR)/embedded-probes.h", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\nexec $SRCROOT/misc/probe2trace.pl -a embedded < $SRCROOT/quicly-probes.d > $DERIVED_FILES_DIR/embedded-probes.h\n"; + }; 08CEA9DF267B461700B4BB6B /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -679,6 +758,34 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 0829876626D372B70053638F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0829876726D372B70053638F /* cc-cubic.c in Sources */, + 0829876826D372B70053638F /* retire_cid.c in Sources */, + 0829876926D372B70053638F /* picotls-probes.d in Sources */, + 0829876A26D372B70053638F /* ranges.c in Sources */, + 0829876B26D372B70053638F /* cc-reno.c in Sources */, + 0829876C26D372B70053638F /* local_cid.c in Sources */, + 0829876D26D372B70053638F /* openssl.c in Sources */, + 0829876E26D372B70053638F /* remote_cid.c in Sources */, + 0829876F26D372B70053638F /* loss.c in Sources */, + 0829877026D372B70053638F /* cc-pico.c in Sources */, + 0829878326D37E370053638F /* simulator.c in Sources */, + 0829877126D372B70053638F /* frame.c in Sources */, + 0829877226D372B70053638F /* recvstate.c in Sources */, + 0829877326D372B70053638F /* fusion.c in Sources */, + 0829877426D372B70053638F /* defaults.c in Sources */, + 0829877526D372B70053638F /* streambuf.c in Sources */, + 0829877626D372B70053638F /* pembase64.c in Sources */, + 0829877826D372B70053638F /* sendstate.c in Sources */, + 0829877926D372B70053638F /* quicly.c in Sources */, + 0829877A26D372B70053638F /* sentmap.c in Sources */, + 0829877B26D372B70053638F /* picotls.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; E980421D223952FD008B9745 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -792,6 +899,40 @@ /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ + 0829877F26D372B70053638F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "QUICLY_USE_EMBEDDED_PROBES=1", + "QUICLY_HAVE_FUSION=1", + ); + OTHER_CFLAGS = "-march=native"; + OTHER_LDFLAGS = ( + "-L/usr/local/opt/openssl@1.1/lib", + "-lcrypto", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 0829878026D372B70053638F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "QUICLY_USE_EMBEDDED_PROBES=1", + "QUICLY_HAVE_FUSION=1", + ); + OTHER_CFLAGS = "-march=native"; + OTHER_LDFLAGS = ( + "-L/usr/local/opt/openssl@1.1/lib", + "-lcrypto", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; E9804225223952FD008B9745 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1028,6 +1169,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 0829877E26D372B70053638F /* Build configuration list for PBXNativeTarget "simulator" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0829877F26D372B70053638F /* Debug */, + 0829878026D372B70053638F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; E9804224223952FD008B9745 /* Build configuration list for PBXNativeTarget "echo" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/t/simulator.c b/t/simulator.c new file mode 100644 index 000000000..194cca964 --- /dev/null +++ b/t/simulator.c @@ -0,0 +1,522 @@ +/* + * Copyright (c) 2021 Fastly, Kazuho Oku + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "picotls.h" +#include "picotls/openssl.h" +#include "quicly.h" +#include "quicly/cc.h" +#include "quicly/defaults.h" + +static double now = 1000; + +static quicly_address_t new_address(void) +{ + static uint32_t next_ipaddr = 0xac100001; + quicly_address_t addr = {}; + addr.sin.sin_family = AF_INET; + addr.sin.sin_addr.s_addr = htonl(next_ipaddr); + addr.sin.sin_port = htons(54321); + ++next_ipaddr; + return addr; +} + +/** + * Packet + */ +struct net_packet { + /** + * used by hops to maintain the linked-list of packets being queued + */ + struct net_packet *next; + /** + * 4-tuple + */ + quicly_address_t dest, src; + /** + * used by queues to retain when the packet entered that queue + */ + double enter_at; + /** + * size of the packet + */ + size_t size; + /** + * the packet + */ + uint8_t bytes[1]; +}; + +static struct net_packet *net_packet_create(quicly_address_t *dest, quicly_address_t *src, ptls_iovec_t vec) +{ + struct net_packet *p = malloc(offsetof(struct net_packet, bytes) + vec.len); + + p->next = NULL; + p->dest = *dest; + p->src = *src; + p->enter_at = now; + p->size = vec.len; + memcpy(p->bytes, vec.base, vec.len); + + return p; +} + +static void net_packet_destroy(struct net_packet *packet) +{ + free(packet); +} + +struct net_hop { + void (*forward_)(struct net_hop *hop, struct net_packet *packet); + int (*is_receiver_of)(struct net_hop *hop, quicly_address_t *dest); + double (*next_run_at)(struct net_hop *hop); + void (*run)(struct net_hop *hop); +}; + +struct net_queue { + struct net_hop hop; + struct net_hop *next_hops[10]; + struct { + struct net_packet *first, **append_at; + } queue; + double next_emit_at; + double prop_delay; + double bytes_per_sec; + size_t size; + size_t capacity; +}; + +static void net_queue_forward(struct net_hop *_hop, struct net_packet *packet) +{ + struct net_queue *queue = (struct net_queue *)_hop; + + /* drop the packet if the queue is full */ + if (queue->size + packet->size > queue->capacity) { + printf("drop %f %zu\n", now, queue->size); + net_packet_destroy(packet); + return; + } + + printf("enqueue %f %zu\n", now, queue->size); + packet->enter_at = now; + *queue->queue.append_at = packet; + queue->queue.append_at = &packet->next; + queue->size += packet->size; +} + +static int net_queue_is_receiver_of(struct net_hop *_hop, quicly_address_t *dest) +{ + assert(!"not implemented"); +} + +static double net_queue_next_run_at(struct net_hop *_hop) +{ + struct net_queue *queue = (struct net_queue *)_hop; + + if (queue->queue.first == NULL) + return INFINITY; + + double emit_at = queue->queue.first->enter_at + queue->prop_delay; + if (emit_at < queue->next_emit_at) + emit_at = queue->next_emit_at; + + return emit_at; +} + +static void net_queue_run(struct net_hop *_hop) +{ + struct net_queue *queue = (struct net_queue *)_hop; + + if (net_queue_next_run_at(&queue->hop) > now) + return; + + /* detach packet */ + struct net_packet *packet = queue->queue.first; + if ((queue->queue.first = packet->next) == NULL) + queue->queue.append_at = &queue->queue.first; + queue->size -= packet->size; + + /* update next emission timer */ + queue->next_emit_at = now + (double)packet->size / queue->bytes_per_sec; + + /* find the next hop and forward */ + struct net_hop **next_hop = queue->next_hops; + for (; *next_hop != NULL; ++next_hop) + if ((*next_hop)->is_receiver_of(*next_hop, &packet->dest)) + break; + assert(*next_hop != NULL); + (*next_hop)->forward_(*next_hop, packet); + + printf("shift %f %zu\n", now, queue->size); +} + +static void net_queue_init(struct net_queue *queue, double prop_delay, double bytes_per_sec, double capacity_in_sec) +{ + queue->hop = (struct net_hop){net_queue_forward, net_queue_is_receiver_of, net_queue_next_run_at, net_queue_run}; + memset(queue->next_hops, 0, sizeof(*queue->next_hops)); + queue->queue.first = NULL; + queue->queue.append_at = &queue->queue.first; + queue->next_emit_at = 0; + queue->prop_delay = prop_delay; + queue->bytes_per_sec = bytes_per_sec; + queue->size = 0; + queue->capacity = (size_t)(bytes_per_sec * capacity_in_sec); +} + +struct net_endpoint { + struct net_hop hop; + quicly_address_t addr; + struct net_hop *egress; + quicly_conn_t *quic; + quicly_context_t *accept_ctx; +}; + +static quicly_cid_plaintext_t next_quic_cid; + +static void net_endpoint_forward(struct net_hop *_hop, struct net_packet *packet) +{ + struct net_endpoint *endpoint = (struct net_endpoint *)_hop; + + size_t off = 0; + while (off != packet->size) { + quicly_decoded_packet_t qp; + if (quicly_decode_packet(endpoint->quic != NULL ? quicly_get_context(endpoint->quic) : endpoint->accept_ctx, &qp, + packet->bytes, packet->size, &off) == SIZE_MAX) + break; + if (endpoint->quic == NULL) { + if (endpoint->accept_ctx != NULL) { + if (quicly_accept(&endpoint->quic, endpoint->accept_ctx, &packet->dest.sa, &packet->src.sa, &qp, NULL, + &next_quic_cid, NULL) == 0) { + assert(endpoint->quic != NULL); + ++next_quic_cid.master_id; + } else { + assert(endpoint->quic == NULL); + } + } + } else { + quicly_receive(endpoint->quic, &packet->dest.sa, &packet->src.sa, &qp); + } + } + + net_packet_destroy(packet); +} + +static int net_endpoint_is_receiver_of(struct net_hop *_hop, quicly_address_t *dest) +{ + struct net_endpoint *endpoint = (struct net_endpoint *)_hop; + + assert(endpoint->addr.sa.sa_family == AF_INET); + assert(dest->sa.sa_family == AF_INET); + + /* At the moment, port numbers aren't used to determine the destination */ + return endpoint->addr.sin.sin_addr.s_addr == dest->sin.sin_addr.s_addr; +} + +static double net_endpoint_next_run_at(struct net_hop *_hop) +{ + struct net_endpoint *endpoint = (struct net_endpoint *)_hop; + + if (endpoint->quic == NULL) + return INFINITY; + /* returned value is incremented by 0.1ms to avoid the timer firing earlier than specified due to rounding error */ + double at = quicly_get_first_timeout(endpoint->quic) / 1000. + 0.0001; + if (at < now) + at = now; + return at; +} + +static void net_endpoint_run(struct net_hop *_hop) +{ + struct net_endpoint *endpoint = (struct net_endpoint *)_hop; + quicly_address_t dest, src; + struct iovec datagrams[10]; + size_t num_datagrams = PTLS_ELEMENTSOF(datagrams); + uint8_t buf[PTLS_ELEMENTSOF(datagrams) * 1500]; + int ret; + + if ((ret = quicly_send(endpoint->quic, &dest, &src, datagrams, &num_datagrams, buf, sizeof(buf))) == 0) { + for (size_t i = 0; i < num_datagrams; ++i) { + struct net_packet *packet = + net_packet_create(&dest, &src, ptls_iovec_init(datagrams[i].iov_base, datagrams[i].iov_len)); + endpoint->egress->forward_(endpoint->egress, packet); + } + } else if (ret == QUICLY_ERROR_FREE_CONNECTION) { + quicly_free(endpoint->quic); + endpoint->quic = NULL; + } +} + +static void net_endpoint_init(struct net_endpoint *endpoint) +{ + *endpoint = (struct net_endpoint){ + .hop = {net_endpoint_forward, net_endpoint_is_receiver_of, net_endpoint_next_run_at, net_endpoint_run}, + .addr = new_address(), + }; +} + +static void run_hops(struct net_hop **hops) +{ + double next_now = INFINITY; + for (struct net_hop **hop = hops; *hop != NULL; ++hop) { + double at = (*hop)->next_run_at(*hop); + assert(at >= now); + if (next_now > at) + next_now = at; + } + + if (isinf(next_now)) + return; + + now = next_now; + for (struct net_hop **hop = hops; *hop != NULL; ++hop) { + if ((*hop)->next_run_at(*hop) <= now) + (*hop)->run(*hop); + } +} + +static uint64_t tls_now_cb(ptls_get_time_t *self) +{ + return (uint64_t)(now * 1000); +} + +static int64_t quic_now_cb(quicly_now_t *self) +{ + return (int64_t)(now * 1000); +} + +static void stream_destroy_cb(quicly_stream_t *stream, int err) +{ +} + +static void stream_egress_shift_cb(quicly_stream_t *stream, size_t delta) +{ +} + +static void stream_egress_emit_cb(quicly_stream_t *stream, size_t off, void *dst, size_t *len, int *wrote_all) +{ + assert(quicly_is_client(stream->conn)); + memset(dst, 'A', *len); + *wrote_all = 0; +} + +static void stream_on_stop_sending_cb(quicly_stream_t *stream, int err) +{ + assert(!"unexpected"); +} + +static void stream_on_receive_cb(quicly_stream_t *stream, size_t off, const void *src, size_t len) +{ + assert(!quicly_is_client(stream->conn)); + assert(!quicly_recvstate_transfer_complete(&stream->recvstate)); + + if (stream->recvstate.data_off < stream->recvstate.received.ranges[0].end) + quicly_stream_sync_recvbuf(stream, stream->recvstate.received.ranges[0].end - stream->recvstate.data_off); +} + +static void stream_on_receive_reset_cb(quicly_stream_t *stream, int err) +{ + assert(!"unexpected"); +} + +static int stream_open_cb(quicly_stream_open_t *self, quicly_stream_t *stream) +{ + static const quicly_stream_callbacks_t stream_callbacks = {stream_destroy_cb, stream_egress_shift_cb, + stream_egress_emit_cb, stream_on_stop_sending_cb, + stream_on_receive_cb, stream_on_receive_reset_cb}; + stream->callbacks = &stream_callbacks; + return 0; +} + +FILE *quicly_trace_fp; + +#define RSA_PRIVATE_KEY \ + "-----BEGIN RSA PRIVATE KEY-----\n" \ + "MIIEpAIBAAKCAQEA7zZheZ4ph98JaedBNv9kqsVA9CSmhd69kBc9ZAfVFMA4VQwp\n" \ + "rOj3ZGrxf20HB3FkvqGvew9ZogUF6NjbPumeiUObGpP21Y5wcYlPL4aojlrwMB/e\n" \ + "OxOCpuRyQTRSSe1hDPvdJABQdmshDP5ZSEBLdUSgrNn4KWhIDjFj1AHXIMqeqTXe\n" \ + "tFuRgNzHdtbXQx+UWBis2B6qZJuqSArb2msVOC8D5gNznPPlQw7FbdPCaLNXSb6G\n" \ + "nI0E0uj6QmYlAw9s6nkgP/zxjfFldqPNUprGcEqTwmAb8VVtd7XbANYrzubZ4Nn6\n" \ + "/WXrCrVxWUmh/7Spgdwa/I4Nr1JHv9HHyL2z/wIDAQABAoIBAEVPf2zKrAPnVwXt\n" \ + "cJLr6xIj908GM43EXS6b3TjXoCDUFT5nOMgV9GCPMAwY3hmE/IjTtlG0v+bXB8BQ\n" \ + "3S3caQgio5VO3A1CqUfsXhpKLRqaNM/s2+pIG+oZdRV5gIJVGnK1o3yj7qxxG/F0\n" \ + "3Q+3OWXwDZIn0eTFh2M9YkxygA/KtkREZWv8Q8qZpdOpJSBYZyGE97Jqy/yGc+DQ\n" \ + "Vpoa9B8WwnIdUn47TkZfsbzqGIYZxatJQDC1j7Y+F8So7zBbUhpz7YqATQwf5Efm\n" \ + "K2xwvlwfdwykq6ffEr2M/Xna0220G2JZlGq3Cs2X9GT9Pt9OS86Bz+EL46ELo0tZ\n" \ + "yfHQe/kCgYEA+zh4k2be6fhQG+ChiG3Ue5K/kH2prqyGBus61wHnt8XZavqBevEy\n" \ + "4pdmvJ6Q1Ta9Z2YCIqqNmlTdjZ6B35lvAK8YFITGy0MVV6K5NFYVfhALWCQC2r3B\n" \ + "6uH39FQ0mDo3gS5ZjYlUzbu67LGFnyX+pyMr2oxlhI1fCY3VchXQAOsCgYEA88Nt\n" \ + "CwSOaZ1fWmyNAgXEAX1Jx4XLFYgjcA/YBXW9gfQ0AfufB346y53PsgjX1lB+Bbcg\n" \ + "cY/o5W7F0b3A0R4K5LShlPCq8iB2DC+VnpKwTgo8ylh+VZCPy2BmMK0jrrmyqWeg\n" \ + "PzwgP0lp+7l/qW8LDImeYi8nWoqd6f1ye4iJdD0CgYEAlIApJljk5EFYeWIrmk3y\n" \ + "EKoKewsNRqfNAkICoh4KL2PQxaAW8emqPq9ol47T5nVZOMnf8UYINnZ8EL7l3psA\n" \ + "NtNJ1Lc4G+cnsooKGJnaUo6BZjTDSzJocsPoopE0Fdgz/zS60yOe8Y5LTKcTaaQ4\n" \ + "B+yOe74KNHSs/STOS4YBUskCgYAIqaRBZPsOo8oUs5DbRostpl8t2QJblIf13opF\n" \ + "v2ZprN0ASQngwUqjm8sav5e0BQ5Fc7mSb5POO36KMp0ckV2/vO+VFGxuyFqJmlNN\n" \ + "3Fapn1GDu1tZ/RYvGxDmn/CJsA26WXVnaeKXfStoB7KSueCBpI5dXOGgJRbxjtE3\n" \ + "tKV13QKBgQCtmLtTJPJ0Z+9n85C8kBonk2MCnD9JTYWoDQzNMYGabthzSqJqcEek\n" \ + "dvhr82XkcHM+r6+cirjdQr4Qj7/2bfZesHl5XLvoJDB1YJIXnNJOELwbktrJrXLc\n" \ + "dJ+MMvPvBAMah/tqr2DqgTGfWLDt9PJiCJVsuN2kD9toWHV08pY0Og==\n" \ + "-----END RSA PRIVATE KEY-----\n" + +#define RSA_CERTIFICATE \ + "-----BEGIN CERTIFICATE-----\n" \ + "MIIDOjCCAiKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDEwtIMk8g\n" \ + "VGVzdCBDQTAeFw0xNDEyMTAxOTMzMDVaFw0yNDEyMDcxOTMzMDVaMBsxGTAXBgNV\n" \ + "BAMTEDEyNy4wLjAuMS54aXAuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\n" \ + "AoIBAQDvNmF5nimH3wlp50E2/2SqxUD0JKaF3r2QFz1kB9UUwDhVDCms6PdkavF/\n" \ + "bQcHcWS+oa97D1miBQXo2Ns+6Z6JQ5sak/bVjnBxiU8vhqiOWvAwH947E4Km5HJB\n" \ + "NFJJ7WEM+90kAFB2ayEM/llIQEt1RKCs2fgpaEgOMWPUAdcgyp6pNd60W5GA3Md2\n" \ + "1tdDH5RYGKzYHqpkm6pICtvaaxU4LwPmA3Oc8+VDDsVt08Jos1dJvoacjQTS6PpC\n" \ + "ZiUDD2zqeSA//PGN8WV2o81SmsZwSpPCYBvxVW13tdsA1ivO5tng2fr9ZesKtXFZ\n" \ + "SaH/tKmB3Br8jg2vUke/0cfIvbP/AgMBAAGjgY0wgYowCQYDVR0TBAIwADAsBglg\n" \ + "hkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0O\n" \ + "BBYEFJXhddVQ68vtPvxoHWHsYkLnu3+4MDAGA1UdIwQpMCehGqQYMBYxFDASBgNV\n" \ + "BAMTC0gyTyBUZXN0IENBggkAmqS1V7DvzbYwDQYJKoZIhvcNAQELBQADggEBAJQ2\n" \ + "uvzL/lZnrsF4cvHhl/mg+s/RjHwvqFRrxOWUeWu2BQOGdd1Izqr8ZbF35pevPkXe\n" \ + "j3zQL4Nf8OxO/gx4w0165KL4dYxEW7EaxsDQUI2aXSW0JNSvK2UGugG4+E4aT+9y\n" \ + "cuBCtfWbL4/N6IMt2QW17B3DcigkreMoZavnnqRecQWkOx4nu0SmYg1g2QV4kRqT\n" \ + "nvLt29daSWjNhP3dkmLTxn19umx26/JH6rqcgokDfHHO8tlDbc9JfyxYH01ZP2Ps\n" \ + "esIiGa/LBXfKiPXxyHuNVQI+2cMmIWYf+Eu/1uNV3K55fA8806/FeklcQe/vvSCU\n" \ + "Vw6RN5S/14SQnMYWr7E=\n" \ + "-----END CERTIFICATE-----\n" + +int main(int argc, char **argv) +{ + ERR_load_CRYPTO_strings(); + OpenSSL_add_all_algorithms(); + + ptls_iovec_t cert = {}; + { + BIO *bio = BIO_new_mem_buf(RSA_CERTIFICATE, strlen(RSA_CERTIFICATE)); + X509 *x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); + assert(x509 != NULL || !!"failed to load certificate"); + BIO_free(bio); + cert.len = i2d_X509(x509, &cert.base); + X509_free(x509); + } + + ptls_openssl_sign_certificate_t cert_signer; + { + BIO *bio = BIO_new_mem_buf(RSA_PRIVATE_KEY, strlen(RSA_PRIVATE_KEY)); + EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + assert(pkey != NULL || !"failed to load private key"); + BIO_free(bio); + ptls_openssl_init_sign_certificate(&cert_signer, pkey); + EVP_PKEY_free(pkey); + } + ptls_get_time_t tls_now = {tls_now_cb}; + ptls_context_t tlsctx = {.random_bytes = ptls_openssl_random_bytes, + .get_time = &tls_now, + .key_exchanges = ptls_openssl_key_exchanges, + .cipher_suites = ptls_openssl_cipher_suites, + .certificates = {&cert, 1}, + .sign_certificate = &cert_signer.super}; + quicly_amend_ptls_context(&tlsctx); + + quicly_stream_open_t stream_open = {stream_open_cb}; + quicly_now_t quic_now = {quic_now_cb}; + quicly_context_t quicctx = quicly_spec_context; + quicctx.now = &quic_now; + quicctx.tls = &tlsctx; + quicctx.stream_open = &stream_open; + quicctx.transport_params.max_streams_uni = 10; + quicctx.transport_params.min_ack_delay_usec = UINT64_MAX; /* disable ack-delay extension */ + + /* parse args */ + double delay = 0.1, bw = 1e6, depth = 0.1; + int ch; + while ((ch = getopt(argc, argv, "b:c:d:q:h")) != -1) { + switch (ch) { + case 'b': + if (sscanf(optarg, "%lf", &bw) != 1) { + fprintf(stderr, "invalid bandwidth: %s\n", optarg); + exit(1); + } + break; + case 'c': { + quicly_cc_type_t **cc; + for (cc = quicly_cc_all_types; *cc != NULL; ++cc) + if (strcmp((*cc)->name, optarg) == 0) + break; + if (*cc != NULL) { + quicctx.init_cc = (*cc)->cc_init; + } else { + fprintf(stderr, "unknown congestion controller: %s\n", optarg); + exit(1); + } + } break; + case 'd': + if (sscanf(optarg, "%lf", &delay) != 1) { + fprintf(stderr, "invalid delay value: %s\n", optarg); + exit(1); + } + break; + case 'q': + if (sscanf(optarg, "%lf", &depth) != 1) { + fprintf(stderr, "invalid queue depth: %s\n", optarg); + exit(1); + } + break; + default: + printf("Usage: %s [-c name]\n\n", argv[0]); + exit(0); + } + } + + struct net_queue bottleneck; + struct net_endpoint server, client; + + /* init nodes */ + net_queue_init(&bottleneck, delay, bw, depth); + net_endpoint_init(&server); + net_endpoint_init(&client); + + /* client uploads to server through the bottleneck queue */ + client.egress = &bottleneck.hop; + bottleneck.next_hops[0] = &server.hop; + server.egress = &client.hop; + + /* start */ + server.accept_ctx = &quicctx; + int ret = quicly_connect(&client.quic, &quicctx, "hello.example.com", &server.addr.sa, &client.addr.sa, NULL, + ptls_iovec_init(NULL, 0), NULL, NULL); + assert(ret == 0); + quicly_stream_t *stream; + ret = quicly_open_stream(client.quic, &stream, 1); + assert(ret == 0); + ret = quicly_stream_sync_sendbuf(stream, 1); + assert(ret == 0); + + struct net_hop *hops[] = {&bottleneck.hop, &server.hop, &client.hop, NULL}; + while (now < 1050) + run_hops(hops); + + return 0; +} From 2b50cfeb20ea9dc573141a4b3a03218248dcf545 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 25 Aug 2021 19:25:05 +0900 Subject: [PATCH 132/361] no need to route, as we do not need multiple servers --- t/simulator.c | 110 ++++++++++++++++++++------------------------------ 1 file changed, 43 insertions(+), 67 deletions(-) diff --git a/t/simulator.c b/t/simulator.c index 194cca964..5214f9003 100644 --- a/t/simulator.c +++ b/t/simulator.c @@ -53,7 +53,7 @@ static quicly_address_t new_address(void) */ struct net_packet { /** - * used by hops to maintain the linked-list of packets being queued + * used by nodes to maintain the linked-list of packets being queued */ struct net_packet *next; /** @@ -93,16 +93,15 @@ static void net_packet_destroy(struct net_packet *packet) free(packet); } -struct net_hop { - void (*forward_)(struct net_hop *hop, struct net_packet *packet); - int (*is_receiver_of)(struct net_hop *hop, quicly_address_t *dest); - double (*next_run_at)(struct net_hop *hop); - void (*run)(struct net_hop *hop); +struct net_node { + void (*forward_)(struct net_node *node, struct net_packet *packet); + double (*next_run_at)(struct net_node *node); + void (*run)(struct net_node *node); }; struct net_queue { - struct net_hop hop; - struct net_hop *next_hops[10]; + struct net_node super; + struct net_node *next_node; struct { struct net_packet *first, **append_at; } queue; @@ -113,9 +112,9 @@ struct net_queue { size_t capacity; }; -static void net_queue_forward(struct net_hop *_hop, struct net_packet *packet) +static void net_queue_forward(struct net_node *_node, struct net_packet *packet) { - struct net_queue *queue = (struct net_queue *)_hop; + struct net_queue *queue = (struct net_queue *)_node; /* drop the packet if the queue is full */ if (queue->size + packet->size > queue->capacity) { @@ -131,14 +130,9 @@ static void net_queue_forward(struct net_hop *_hop, struct net_packet *packet) queue->size += packet->size; } -static int net_queue_is_receiver_of(struct net_hop *_hop, quicly_address_t *dest) +static double net_queue_next_run_at(struct net_node *_node) { - assert(!"not implemented"); -} - -static double net_queue_next_run_at(struct net_hop *_hop) -{ - struct net_queue *queue = (struct net_queue *)_hop; + struct net_queue *queue = (struct net_queue *)_node; if (queue->queue.first == NULL) return INFINITY; @@ -150,11 +144,11 @@ static double net_queue_next_run_at(struct net_hop *_hop) return emit_at; } -static void net_queue_run(struct net_hop *_hop) +static void net_queue_run(struct net_node *_node) { - struct net_queue *queue = (struct net_queue *)_hop; + struct net_queue *queue = (struct net_queue *)_node; - if (net_queue_next_run_at(&queue->hop) > now) + if (net_queue_next_run_at(&queue->super) > now) return; /* detach packet */ @@ -166,43 +160,36 @@ static void net_queue_run(struct net_hop *_hop) /* update next emission timer */ queue->next_emit_at = now + (double)packet->size / queue->bytes_per_sec; - /* find the next hop and forward */ - struct net_hop **next_hop = queue->next_hops; - for (; *next_hop != NULL; ++next_hop) - if ((*next_hop)->is_receiver_of(*next_hop, &packet->dest)) - break; - assert(*next_hop != NULL); - (*next_hop)->forward_(*next_hop, packet); + /* forward to the next node */ + queue->next_node->forward_(queue->next_node, packet); printf("shift %f %zu\n", now, queue->size); } static void net_queue_init(struct net_queue *queue, double prop_delay, double bytes_per_sec, double capacity_in_sec) { - queue->hop = (struct net_hop){net_queue_forward, net_queue_is_receiver_of, net_queue_next_run_at, net_queue_run}; - memset(queue->next_hops, 0, sizeof(*queue->next_hops)); - queue->queue.first = NULL; - queue->queue.append_at = &queue->queue.first; - queue->next_emit_at = 0; - queue->prop_delay = prop_delay; - queue->bytes_per_sec = bytes_per_sec; - queue->size = 0; - queue->capacity = (size_t)(bytes_per_sec * capacity_in_sec); + *queue = (struct net_queue){ + .super = {net_queue_forward, net_queue_next_run_at, net_queue_run}, + .queue = {.append_at = &queue->queue.first}, + .prop_delay = prop_delay, + .bytes_per_sec = bytes_per_sec, + .capacity = (size_t)(bytes_per_sec * capacity_in_sec), + }; } struct net_endpoint { - struct net_hop hop; + struct net_node super; quicly_address_t addr; - struct net_hop *egress; + struct net_node *egress; quicly_conn_t *quic; quicly_context_t *accept_ctx; }; static quicly_cid_plaintext_t next_quic_cid; -static void net_endpoint_forward(struct net_hop *_hop, struct net_packet *packet) +static void net_endpoint_forward(struct net_node *_node, struct net_packet *packet) { - struct net_endpoint *endpoint = (struct net_endpoint *)_hop; + struct net_endpoint *endpoint = (struct net_endpoint *)_node; size_t off = 0; while (off != packet->size) { @@ -228,20 +215,9 @@ static void net_endpoint_forward(struct net_hop *_hop, struct net_packet *packet net_packet_destroy(packet); } -static int net_endpoint_is_receiver_of(struct net_hop *_hop, quicly_address_t *dest) -{ - struct net_endpoint *endpoint = (struct net_endpoint *)_hop; - - assert(endpoint->addr.sa.sa_family == AF_INET); - assert(dest->sa.sa_family == AF_INET); - - /* At the moment, port numbers aren't used to determine the destination */ - return endpoint->addr.sin.sin_addr.s_addr == dest->sin.sin_addr.s_addr; -} - -static double net_endpoint_next_run_at(struct net_hop *_hop) +static double net_endpoint_next_run_at(struct net_node *_node) { - struct net_endpoint *endpoint = (struct net_endpoint *)_hop; + struct net_endpoint *endpoint = (struct net_endpoint *)_node; if (endpoint->quic == NULL) return INFINITY; @@ -252,9 +228,9 @@ static double net_endpoint_next_run_at(struct net_hop *_hop) return at; } -static void net_endpoint_run(struct net_hop *_hop) +static void net_endpoint_run(struct net_node *_node) { - struct net_endpoint *endpoint = (struct net_endpoint *)_hop; + struct net_endpoint *endpoint = (struct net_endpoint *)_node; quicly_address_t dest, src; struct iovec datagrams[10]; size_t num_datagrams = PTLS_ELEMENTSOF(datagrams); @@ -276,16 +252,16 @@ static void net_endpoint_run(struct net_hop *_hop) static void net_endpoint_init(struct net_endpoint *endpoint) { *endpoint = (struct net_endpoint){ - .hop = {net_endpoint_forward, net_endpoint_is_receiver_of, net_endpoint_next_run_at, net_endpoint_run}, + .super = {net_endpoint_forward, net_endpoint_next_run_at, net_endpoint_run}, .addr = new_address(), }; } -static void run_hops(struct net_hop **hops) +static void run_nodes(struct net_node **nodes) { double next_now = INFINITY; - for (struct net_hop **hop = hops; *hop != NULL; ++hop) { - double at = (*hop)->next_run_at(*hop); + for (struct net_node **node = nodes; *node != NULL; ++node) { + double at = (*node)->next_run_at(*node); assert(at >= now); if (next_now > at) next_now = at; @@ -295,9 +271,9 @@ static void run_hops(struct net_hop **hops) return; now = next_now; - for (struct net_hop **hop = hops; *hop != NULL; ++hop) { - if ((*hop)->next_run_at(*hop) <= now) - (*hop)->run(*hop); + for (struct net_node **node = nodes; *node != NULL; ++node) { + if ((*node)->next_run_at(*node) <= now) + (*node)->run(*node); } } @@ -499,9 +475,9 @@ int main(int argc, char **argv) net_endpoint_init(&client); /* client uploads to server through the bottleneck queue */ - client.egress = &bottleneck.hop; - bottleneck.next_hops[0] = &server.hop; - server.egress = &client.hop; + client.egress = &bottleneck.super; + bottleneck.next_node = &server.super; + server.egress = &client.super; /* start */ server.accept_ctx = &quicctx; @@ -514,9 +490,9 @@ int main(int argc, char **argv) ret = quicly_stream_sync_sendbuf(stream, 1); assert(ret == 0); - struct net_hop *hops[] = {&bottleneck.hop, &server.hop, &client.hop, NULL}; + struct net_node *nodes[] = {&bottleneck.super, &server.super, &client.super, NULL}; while (now < 1050) - run_hops(hops); + run_nodes(nodes); return 0; } From 6936befb494fc684b304e1a42bed2dbde8eb8904 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 25 Aug 2021 19:31:57 +0900 Subject: [PATCH 133/361] refactor --- t/simulator.c | 126 ++++++++++++++++++++++++++++---------------------- 1 file changed, 70 insertions(+), 56 deletions(-) diff --git a/t/simulator.c b/t/simulator.c index 5214f9003..64939638d 100644 --- a/t/simulator.c +++ b/t/simulator.c @@ -93,84 +93,98 @@ static void net_packet_destroy(struct net_packet *packet) free(packet); } +struct net_queue { + struct net_packet *first, **append_at; + size_t size; +}; + +static void net_queue_enqueue(struct net_queue *self, struct net_packet *packet) +{ + packet->enter_at = now; + *self->append_at = packet; + self->append_at = &packet->next; + self->size += packet->size; +} + +static struct net_packet *net_queue_dequeue(struct net_queue *self) +{ + struct net_packet *packet = self->first; + assert(packet != NULL); + if ((self->first = packet->next) == NULL) + self->append_at = &self->first; + self->size -= packet->size; + return packet; +} + struct net_node { void (*forward_)(struct net_node *node, struct net_packet *packet); double (*next_run_at)(struct net_node *node); void (*run)(struct net_node *node); }; -struct net_queue { +struct net_bottleneck { struct net_node super; struct net_node *next_node; - struct { - struct net_packet *first, **append_at; - } queue; + struct net_queue queue; double next_emit_at; double prop_delay; double bytes_per_sec; - size_t size; size_t capacity; }; -static void net_queue_forward(struct net_node *_node, struct net_packet *packet) +static void net_bottleneck_forward(struct net_node *_self, struct net_packet *packet) { - struct net_queue *queue = (struct net_queue *)_node; + struct net_bottleneck *self = (struct net_bottleneck *)_self; /* drop the packet if the queue is full */ - if (queue->size + packet->size > queue->capacity) { - printf("drop %f %zu\n", now, queue->size); + if (self->queue.size + packet->size > self->capacity) { + printf("drop %f %zu\n", now, self->queue.size); net_packet_destroy(packet); return; } - printf("enqueue %f %zu\n", now, queue->size); - packet->enter_at = now; - *queue->queue.append_at = packet; - queue->queue.append_at = &packet->next; - queue->size += packet->size; + printf("enqueue %f %zu\n", now, self->queue.size); + net_queue_enqueue(&self->queue, packet); } -static double net_queue_next_run_at(struct net_node *_node) +static double net_bottleneck_next_run_at(struct net_node *_self) { - struct net_queue *queue = (struct net_queue *)_node; + struct net_bottleneck *self = (struct net_bottleneck *)_self; - if (queue->queue.first == NULL) + if (self->queue.first == NULL) return INFINITY; - double emit_at = queue->queue.first->enter_at + queue->prop_delay; - if (emit_at < queue->next_emit_at) - emit_at = queue->next_emit_at; + double emit_at = self->queue.first->enter_at + self->prop_delay; + if (emit_at < self->next_emit_at) + emit_at = self->next_emit_at; return emit_at; } -static void net_queue_run(struct net_node *_node) +static void net_bottleneck_run(struct net_node *_self) { - struct net_queue *queue = (struct net_queue *)_node; + struct net_bottleneck *self = (struct net_bottleneck *)_self; - if (net_queue_next_run_at(&queue->super) > now) + if (net_bottleneck_next_run_at(&self->super) > now) return; /* detach packet */ - struct net_packet *packet = queue->queue.first; - if ((queue->queue.first = packet->next) == NULL) - queue->queue.append_at = &queue->queue.first; - queue->size -= packet->size; + struct net_packet *packet = net_queue_dequeue(&self->queue); /* update next emission timer */ - queue->next_emit_at = now + (double)packet->size / queue->bytes_per_sec; + self->next_emit_at = now + (double)packet->size / self->bytes_per_sec; /* forward to the next node */ - queue->next_node->forward_(queue->next_node, packet); + self->next_node->forward_(self->next_node, packet); - printf("shift %f %zu\n", now, queue->size); + printf("shift %f %zu\n", now, self->queue.size); } -static void net_queue_init(struct net_queue *queue, double prop_delay, double bytes_per_sec, double capacity_in_sec) +static void net_queue_init(struct net_bottleneck *self, double prop_delay, double bytes_per_sec, double capacity_in_sec) { - *queue = (struct net_queue){ - .super = {net_queue_forward, net_queue_next_run_at, net_queue_run}, - .queue = {.append_at = &queue->queue.first}, + *self = (struct net_bottleneck){ + .super = {net_bottleneck_forward, net_bottleneck_next_run_at, net_bottleneck_run}, + .queue = {.append_at = &self->queue.first}, .prop_delay = prop_delay, .bytes_per_sec = bytes_per_sec, .capacity = (size_t)(bytes_per_sec * capacity_in_sec), @@ -187,65 +201,65 @@ struct net_endpoint { static quicly_cid_plaintext_t next_quic_cid; -static void net_endpoint_forward(struct net_node *_node, struct net_packet *packet) +static void net_endpoint_forward(struct net_node *_self, struct net_packet *packet) { - struct net_endpoint *endpoint = (struct net_endpoint *)_node; + struct net_endpoint *self = (struct net_endpoint *)_self; size_t off = 0; while (off != packet->size) { quicly_decoded_packet_t qp; - if (quicly_decode_packet(endpoint->quic != NULL ? quicly_get_context(endpoint->quic) : endpoint->accept_ctx, &qp, - packet->bytes, packet->size, &off) == SIZE_MAX) + if (quicly_decode_packet(self->quic != NULL ? quicly_get_context(self->quic) : self->accept_ctx, &qp, packet->bytes, + packet->size, &off) == SIZE_MAX) break; - if (endpoint->quic == NULL) { - if (endpoint->accept_ctx != NULL) { - if (quicly_accept(&endpoint->quic, endpoint->accept_ctx, &packet->dest.sa, &packet->src.sa, &qp, NULL, - &next_quic_cid, NULL) == 0) { - assert(endpoint->quic != NULL); + if (self->quic == NULL) { + if (self->accept_ctx != NULL) { + if (quicly_accept(&self->quic, self->accept_ctx, &packet->dest.sa, &packet->src.sa, &qp, NULL, &next_quic_cid, + NULL) == 0) { + assert(self->quic != NULL); ++next_quic_cid.master_id; } else { - assert(endpoint->quic == NULL); + assert(self->quic == NULL); } } } else { - quicly_receive(endpoint->quic, &packet->dest.sa, &packet->src.sa, &qp); + quicly_receive(self->quic, &packet->dest.sa, &packet->src.sa, &qp); } } net_packet_destroy(packet); } -static double net_endpoint_next_run_at(struct net_node *_node) +static double net_endpoint_next_run_at(struct net_node *_self) { - struct net_endpoint *endpoint = (struct net_endpoint *)_node; + struct net_endpoint *self = (struct net_endpoint *)_self; - if (endpoint->quic == NULL) + if (self->quic == NULL) return INFINITY; /* returned value is incremented by 0.1ms to avoid the timer firing earlier than specified due to rounding error */ - double at = quicly_get_first_timeout(endpoint->quic) / 1000. + 0.0001; + double at = quicly_get_first_timeout(self->quic) / 1000. + 0.0001; if (at < now) at = now; return at; } -static void net_endpoint_run(struct net_node *_node) +static void net_endpoint_run(struct net_node *_self) { - struct net_endpoint *endpoint = (struct net_endpoint *)_node; + struct net_endpoint *self = (struct net_endpoint *)_self; quicly_address_t dest, src; struct iovec datagrams[10]; size_t num_datagrams = PTLS_ELEMENTSOF(datagrams); uint8_t buf[PTLS_ELEMENTSOF(datagrams) * 1500]; int ret; - if ((ret = quicly_send(endpoint->quic, &dest, &src, datagrams, &num_datagrams, buf, sizeof(buf))) == 0) { + if ((ret = quicly_send(self->quic, &dest, &src, datagrams, &num_datagrams, buf, sizeof(buf))) == 0) { for (size_t i = 0; i < num_datagrams; ++i) { struct net_packet *packet = net_packet_create(&dest, &src, ptls_iovec_init(datagrams[i].iov_base, datagrams[i].iov_len)); - endpoint->egress->forward_(endpoint->egress, packet); + self->egress->forward_(self->egress, packet); } } else if (ret == QUICLY_ERROR_FREE_CONNECTION) { - quicly_free(endpoint->quic); - endpoint->quic = NULL; + quicly_free(self->quic); + self->quic = NULL; } } @@ -466,7 +480,7 @@ int main(int argc, char **argv) } } - struct net_queue bottleneck; + struct net_bottleneck bottleneck; struct net_endpoint server, client; /* init nodes */ From 96ca94bb0d8fb0dcb568d81a4f6b0fabe56a03bf Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 25 Aug 2021 21:11:46 +0900 Subject: [PATCH 134/361] delay and bottleneck have to be different --- t/simulator.c | 72 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 16 deletions(-) diff --git a/t/simulator.c b/t/simulator.c index 64939638d..c94113ad1 100644 --- a/t/simulator.c +++ b/t/simulator.c @@ -100,6 +100,7 @@ struct net_queue { static void net_queue_enqueue(struct net_queue *self, struct net_packet *packet) { + packet->next = NULL; packet->enter_at = now; *self->append_at = packet; self->append_at = &packet->next; @@ -122,12 +123,49 @@ struct net_node { void (*run)(struct net_node *node); }; +struct net_delay { + struct net_node super; + struct net_node *next_node; + struct net_queue queue; + double delay; +}; + +static void net_delay_forward(struct net_node *_self, struct net_packet *packet) +{ + struct net_delay *self = (struct net_delay *)_self; + net_queue_enqueue(&self->queue, packet); +} + +static double net_delay_next_run_at(struct net_node *_self) +{ + struct net_delay *self = (struct net_delay *)_self; + return self->queue.first != NULL ? self->queue.first->enter_at + self->delay : INFINITY; +} + +static void net_delay_run(struct net_node *_self) +{ + struct net_delay *self = (struct net_delay *)_self; + + while (self->queue.first != NULL && self->queue.first->enter_at + self->delay <= now) { + struct net_packet *packet = net_queue_dequeue(&self->queue); + self->next_node->forward_(self->next_node, packet); + } +} + +static void net_delay_init(struct net_delay *self, double delay) +{ + *self = (struct net_delay){ + .super = {net_delay_forward, net_delay_next_run_at, net_delay_run}, + .queue = {.append_at = &self->queue.first}, + .delay = delay, + }; +} + struct net_bottleneck { struct net_node super; struct net_node *next_node; struct net_queue queue; double next_emit_at; - double prop_delay; double bytes_per_sec; size_t capacity; }; @@ -154,7 +192,7 @@ static double net_bottleneck_next_run_at(struct net_node *_self) if (self->queue.first == NULL) return INFINITY; - double emit_at = self->queue.first->enter_at + self->prop_delay; + double emit_at = self->queue.first->enter_at; if (emit_at < self->next_emit_at) emit_at = self->next_emit_at; @@ -180,12 +218,11 @@ static void net_bottleneck_run(struct net_node *_self) printf("shift %f %zu\n", now, self->queue.size); } -static void net_queue_init(struct net_bottleneck *self, double prop_delay, double bytes_per_sec, double capacity_in_sec) +static void net_queue_init(struct net_bottleneck *self, double bytes_per_sec, double capacity_in_sec) { *self = (struct net_bottleneck){ .super = {net_bottleneck_forward, net_bottleneck_next_run_at, net_bottleneck_run}, .queue = {.append_at = &self->queue.first}, - .prop_delay = prop_delay, .bytes_per_sec = bytes_per_sec, .capacity = (size_t)(bytes_per_sec * capacity_in_sec), }; @@ -480,31 +517,34 @@ int main(int argc, char **argv) } } - struct net_bottleneck bottleneck; - struct net_endpoint server, client; + struct net_bottleneck bottleneck_node; + struct net_delay delay_node; + struct net_endpoint server_node, client_node; /* init nodes */ - net_queue_init(&bottleneck, delay, bw, depth); - net_endpoint_init(&server); - net_endpoint_init(&client); + net_queue_init(&bottleneck_node, bw, depth); + net_delay_init(&delay_node, delay); + net_endpoint_init(&server_node); + net_endpoint_init(&client_node); /* client uploads to server through the bottleneck queue */ - client.egress = &bottleneck.super; - bottleneck.next_node = &server.super; - server.egress = &client.super; + client_node.egress = &delay_node.super; + delay_node.next_node = &bottleneck_node.super; + bottleneck_node.next_node = &server_node.super; + server_node.egress = &client_node.super; /* start */ - server.accept_ctx = &quicctx; - int ret = quicly_connect(&client.quic, &quicctx, "hello.example.com", &server.addr.sa, &client.addr.sa, NULL, + server_node.accept_ctx = &quicctx; + int ret = quicly_connect(&client_node.quic, &quicctx, "hello.example.com", &server_node.addr.sa, &client_node.addr.sa, NULL, ptls_iovec_init(NULL, 0), NULL, NULL); assert(ret == 0); quicly_stream_t *stream; - ret = quicly_open_stream(client.quic, &stream, 1); + ret = quicly_open_stream(client_node.quic, &stream, 1); assert(ret == 0); ret = quicly_stream_sync_sendbuf(stream, 1); assert(ret == 0); - struct net_node *nodes[] = {&bottleneck.super, &server.super, &client.super, NULL}; + struct net_node *nodes[] = {&bottleneck_node.super, &delay_node.super, &server_node.super, &client_node.super, NULL}; while (now < 1050) run_nodes(nodes); From 4b0cf3e6bd6fb3108ad88dd1f451a5aad88cd5e8 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 26 Aug 2021 08:01:06 +0900 Subject: [PATCH 135/361] use ldjson --- t/simulator.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/t/simulator.c b/t/simulator.c index c94113ad1..41c2e0f6e 100644 --- a/t/simulator.c +++ b/t/simulator.c @@ -170,18 +170,23 @@ struct net_bottleneck { size_t capacity; }; +static void net_bottleneck_print_stats(struct net_bottleneck *self, const char *event) +{ + printf("{\"bottleneck\": \"%s\", \"at\": %f, \"size\": %zu}\n", event, now, self->queue.size); +} + static void net_bottleneck_forward(struct net_node *_self, struct net_packet *packet) { struct net_bottleneck *self = (struct net_bottleneck *)_self; /* drop the packet if the queue is full */ if (self->queue.size + packet->size > self->capacity) { - printf("drop %f %zu\n", now, self->queue.size); + net_bottleneck_print_stats(self, "drop"); net_packet_destroy(packet); return; } - printf("enqueue %f %zu\n", now, self->queue.size); + net_bottleneck_print_stats(self, "enqueue"); net_queue_enqueue(&self->queue, packet); } @@ -215,7 +220,7 @@ static void net_bottleneck_run(struct net_node *_self) /* forward to the next node */ self->next_node->forward_(self->next_node, packet); - printf("shift %f %zu\n", now, self->queue.size); + net_bottleneck_print_stats(self, "dequeue"); } static void net_queue_init(struct net_bottleneck *self, double bytes_per_sec, double capacity_in_sec) From 17e8c378daa04d1c05e22818e363a78bdc6c2501 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 26 Aug 2021 08:10:06 +0900 Subject: [PATCH 136/361] support multiple flows --- t/simulator.c | 274 +++++++++++++++++++++++++++++--------------------- 1 file changed, 158 insertions(+), 116 deletions(-) diff --git a/t/simulator.c b/t/simulator.c index 41c2e0f6e..cfb4db570 100644 --- a/t/simulator.c +++ b/t/simulator.c @@ -39,7 +39,7 @@ static double now = 1000; static quicly_address_t new_address(void) { - static uint32_t next_ipaddr = 0xac100001; + static uint32_t next_ipaddr = 1; quicly_address_t addr = {}; addr.sin.sin_family = AF_INET; addr.sin.sin_addr.s_addr = htonl(next_ipaddr); @@ -48,6 +48,8 @@ static quicly_address_t new_address(void) return addr; } +struct net_endpoint; + /** * Packet */ @@ -57,9 +59,13 @@ struct net_packet { */ struct net_packet *next; /** - * 4-tuple + * source + */ + struct net_endpoint *src; + /** + * destination */ - quicly_address_t dest, src; + quicly_address_t dest; /** * used by queues to retain when the packet entered that queue */ @@ -74,13 +80,50 @@ struct net_packet { uint8_t bytes[1]; }; -static struct net_packet *net_packet_create(quicly_address_t *dest, quicly_address_t *src, ptls_iovec_t vec) +struct net_queue { + struct net_packet *first, **append_at; + size_t size; +}; + +struct net_node { + void (*forward_)(struct net_node *node, struct net_packet *packet); + double (*next_run_at)(struct net_node *node); + void (*run)(struct net_node *node); +}; + +struct net_delay { + struct net_node super; + struct net_node *next_node; + struct net_queue queue; + double delay; +}; + +struct net_bottleneck { + struct net_node super; + struct net_node *next_node; + struct net_queue queue; + double next_emit_at; + double bytes_per_sec; + size_t capacity; +}; + +struct net_endpoint { + struct net_node super; + quicly_address_t addr; + struct net_endpoint_conn { + quicly_conn_t *quic; + struct net_node *egress; + } conns[10]; + quicly_context_t *accept_ctx; +}; + +static struct net_packet *net_packet_create(struct net_endpoint *src, quicly_address_t *dest, ptls_iovec_t vec) { struct net_packet *p = malloc(offsetof(struct net_packet, bytes) + vec.len); p->next = NULL; + p->src = src; p->dest = *dest; - p->src = *src; p->enter_at = now; p->size = vec.len; memcpy(p->bytes, vec.base, vec.len); @@ -93,11 +136,6 @@ static void net_packet_destroy(struct net_packet *packet) free(packet); } -struct net_queue { - struct net_packet *first, **append_at; - size_t size; -}; - static void net_queue_enqueue(struct net_queue *self, struct net_packet *packet) { packet->next = NULL; @@ -117,19 +155,6 @@ static struct net_packet *net_queue_dequeue(struct net_queue *self) return packet; } -struct net_node { - void (*forward_)(struct net_node *node, struct net_packet *packet); - double (*next_run_at)(struct net_node *node); - void (*run)(struct net_node *node); -}; - -struct net_delay { - struct net_node super; - struct net_node *next_node; - struct net_queue queue; - double delay; -}; - static void net_delay_forward(struct net_node *_self, struct net_packet *packet) { struct net_delay *self = (struct net_delay *)_self; @@ -161,18 +186,10 @@ static void net_delay_init(struct net_delay *self, double delay) }; } -struct net_bottleneck { - struct net_node super; - struct net_node *next_node; - struct net_queue queue; - double next_emit_at; - double bytes_per_sec; - size_t capacity; -}; - -static void net_bottleneck_print_stats(struct net_bottleneck *self, const char *event) +static void net_bottleneck_print_stats(struct net_bottleneck *self, const char *event, struct net_packet *packet) { - printf("{\"bottleneck\": \"%s\", \"at\": %f, \"size\": %zu}\n", event, now, self->queue.size); + printf("{\"bottleneck\": \"%s\", \"at\": %f, \"queue-size\": %zu, \"packet-src\": %" PRIu32 ", \"packet-size\": %zu}\n", event, + now, self->queue.size, ntohl(packet->src->addr.sin.sin_addr.s_addr), packet->size); } static void net_bottleneck_forward(struct net_node *_self, struct net_packet *packet) @@ -181,12 +198,12 @@ static void net_bottleneck_forward(struct net_node *_self, struct net_packet *pa /* drop the packet if the queue is full */ if (self->queue.size + packet->size > self->capacity) { - net_bottleneck_print_stats(self, "drop"); + net_bottleneck_print_stats(self, "drop", packet); net_packet_destroy(packet); return; } - net_bottleneck_print_stats(self, "enqueue"); + net_bottleneck_print_stats(self, "enqueue", packet); net_queue_enqueue(&self->queue, packet); } @@ -213,17 +230,16 @@ static void net_bottleneck_run(struct net_node *_self) /* detach packet */ struct net_packet *packet = net_queue_dequeue(&self->queue); + net_bottleneck_print_stats(self, "dequeue", packet); /* update next emission timer */ self->next_emit_at = now + (double)packet->size / self->bytes_per_sec; /* forward to the next node */ self->next_node->forward_(self->next_node, packet); - - net_bottleneck_print_stats(self, "dequeue"); } -static void net_queue_init(struct net_bottleneck *self, double bytes_per_sec, double capacity_in_sec) +static void net_bottleneck_init(struct net_bottleneck *self, double bytes_per_sec, double capacity_in_sec) { *self = (struct net_bottleneck){ .super = {net_bottleneck_forward, net_bottleneck_next_run_at, net_bottleneck_run}, @@ -233,14 +249,6 @@ static void net_queue_init(struct net_bottleneck *self, double bytes_per_sec, do }; } -struct net_endpoint { - struct net_node super; - quicly_address_t addr; - struct net_node *egress; - quicly_conn_t *quic; - quicly_context_t *accept_ctx; -}; - static quicly_cid_plaintext_t next_quic_cid; static void net_endpoint_forward(struct net_node *_self, struct net_packet *packet) @@ -249,22 +257,29 @@ static void net_endpoint_forward(struct net_node *_self, struct net_packet *pack size_t off = 0; while (off != packet->size) { + /* decode packet */ quicly_decoded_packet_t qp; - if (quicly_decode_packet(self->quic != NULL ? quicly_get_context(self->quic) : self->accept_ctx, &qp, packet->bytes, - packet->size, &off) == SIZE_MAX) + if (quicly_decode_packet(self->conns[0].quic != NULL ? quicly_get_context(self->conns[0].quic) : self->accept_ctx, &qp, + packet->bytes, packet->size, &off) == SIZE_MAX) break; - if (self->quic == NULL) { - if (self->accept_ctx != NULL) { - if (quicly_accept(&self->quic, self->accept_ctx, &packet->dest.sa, &packet->src.sa, &qp, NULL, &next_quic_cid, - NULL) == 0) { - assert(self->quic != NULL); - ++next_quic_cid.master_id; - } else { - assert(self->quic == NULL); - } - } + /* find the matching connection, or where new state should be created */ + struct net_endpoint_conn *conn; + for (conn = self->conns; conn->quic != NULL; ++conn) + if (quicly_is_destination(conn->quic, &packet->dest.sa, &packet->src->addr.sa, &qp)) + break; + /* let the existing connection handle the packet, or accept a new connection */ + if (conn->quic != NULL) { + quicly_receive(conn->quic, &packet->dest.sa, &packet->src->addr.sa, &qp); } else { - quicly_receive(self->quic, &packet->dest.sa, &packet->src.sa, &qp); + assert(self->accept_ctx != NULL && "a packet for which we do not have state must be a new connection request"); + if (quicly_accept(&conn->quic, self->accept_ctx, &packet->dest.sa, &packet->src->addr.sa, &qp, NULL, &next_quic_cid, + NULL) == 0) { + assert(conn->quic != NULL); + ++next_quic_cid.master_id; + conn->egress = &packet->src->super; + } else { + assert(conn->quic == NULL); + } } } @@ -274,11 +289,15 @@ static void net_endpoint_forward(struct net_node *_self, struct net_packet *pack static double net_endpoint_next_run_at(struct net_node *_self) { struct net_endpoint *self = (struct net_endpoint *)_self; + double at = INFINITY; + + for (struct net_endpoint_conn *conn = self->conns; conn->quic != NULL; ++conn) { + /* value is incremented by 0.1ms to avoid the timer firing earlier than specified due to rounding error */ + double conn_at = quicly_get_first_timeout(conn->quic) / 1000. + 0.0001; + if (conn_at < at) + at = conn_at; + } - if (self->quic == NULL) - return INFINITY; - /* returned value is incremented by 0.1ms to avoid the timer firing earlier than specified due to rounding error */ - double at = quicly_get_first_timeout(self->quic) / 1000. + 0.0001; if (at < now) at = now; return at; @@ -287,21 +306,22 @@ static double net_endpoint_next_run_at(struct net_node *_self) static void net_endpoint_run(struct net_node *_self) { struct net_endpoint *self = (struct net_endpoint *)_self; - quicly_address_t dest, src; - struct iovec datagrams[10]; - size_t num_datagrams = PTLS_ELEMENTSOF(datagrams); - uint8_t buf[PTLS_ELEMENTSOF(datagrams) * 1500]; - int ret; - - if ((ret = quicly_send(self->quic, &dest, &src, datagrams, &num_datagrams, buf, sizeof(buf))) == 0) { - for (size_t i = 0; i < num_datagrams; ++i) { - struct net_packet *packet = - net_packet_create(&dest, &src, ptls_iovec_init(datagrams[i].iov_base, datagrams[i].iov_len)); - self->egress->forward_(self->egress, packet); + + for (struct net_endpoint_conn *conn = self->conns; conn->quic != NULL; ++conn) { + quicly_address_t dest, src; + struct iovec datagrams[10]; + size_t num_datagrams = PTLS_ELEMENTSOF(datagrams); + uint8_t buf[PTLS_ELEMENTSOF(datagrams) * 1500]; + int ret; + if ((ret = quicly_send(conn->quic, &dest, &src, datagrams, &num_datagrams, buf, sizeof(buf))) == 0) { + for (size_t i = 0; i < num_datagrams; ++i) { + struct net_packet *packet = + net_packet_create(self, &dest, ptls_iovec_init(datagrams[i].iov_base, datagrams[i].iov_len)); + conn->egress->forward_(conn->egress, packet); + } + } else { + assert(ret != QUICLY_ERROR_FREE_CONNECTION); } - } else if (ret == QUICLY_ERROR_FREE_CONNECTION) { - quicly_free(self->quic); - self->quic = NULL; } } @@ -386,7 +406,18 @@ static int stream_open_cb(quicly_stream_open_t *self, quicly_stream_t *stream) return 0; } -FILE *quicly_trace_fp; +static void usage(const char *cmd) +{ + printf("Usage: %s ...\n" + "\n" + "Options:\n" + " -n adds a sender using specified controller\n" + " -b bottleneck bandwidth\n" + " -d delay to be introduced between the sender and the botteneck\n" + " -q maximum depth of the bottleneck queue, in seconds\n" + "\n", + cmd); +} #define RSA_PRIVATE_KEY \ "-----BEGIN RSA PRIVATE KEY-----\n" \ @@ -479,20 +510,28 @@ int main(int argc, char **argv) quicctx.tls = &tlsctx; quicctx.stream_open = &stream_open; quicctx.transport_params.max_streams_uni = 10; + quicctx.transport_params.max_stream_data.uni = 128 * 1024 * 1024; + quicctx.transport_params.max_data = 128 * 1024 * 1824; quicctx.transport_params.min_ack_delay_usec = UINT64_MAX; /* disable ack-delay extension */ + struct net_bottleneck bottleneck_node; + struct { + struct net_endpoint node; + quicly_context_t accept_ctx; + } server_node; + struct net_node *nodes[20] = {}, **node_insert_at = nodes; + + net_endpoint_init(&server_node.node); + server_node.accept_ctx = quicctx; + server_node.node.accept_ctx = &server_node.accept_ctx; + *node_insert_at++ = &server_node.node.super; + /* parse args */ double delay = 0.1, bw = 1e6, depth = 0.1; int ch; - while ((ch = getopt(argc, argv, "b:c:d:q:h")) != -1) { + while ((ch = getopt(argc, argv, "n:b:d:q:h")) != -1) { switch (ch) { - case 'b': - if (sscanf(optarg, "%lf", &bw) != 1) { - fprintf(stderr, "invalid bandwidth: %s\n", optarg); - exit(1); - } - break; - case 'c': { + case 'n': { quicly_cc_type_t **cc; for (cc = quicly_cc_all_types; *cc != NULL; ++cc) if (strcmp((*cc)->name, optarg) == 0) @@ -503,7 +542,29 @@ int main(int argc, char **argv) fprintf(stderr, "unknown congestion controller: %s\n", optarg); exit(1); } + struct net_delay *delay_node = malloc(sizeof(*delay_node)); + net_delay_init(delay_node, delay); + delay_node->next_node = &bottleneck_node.super; + *node_insert_at++ = &delay_node->super; + struct net_endpoint *client_node = malloc(sizeof(*client_node)); + net_endpoint_init(client_node); + int ret = quicly_connect(&client_node->conns[0].quic, &quicctx, "hello.example.com", &server_node.node.addr.sa, + &client_node->addr.sa, NULL, ptls_iovec_init(NULL, 0), NULL, NULL); + assert(ret == 0); + quicly_stream_t *stream; + ret = quicly_open_stream(client_node->conns[0].quic, &stream, 1); + assert(ret == 0); + ret = quicly_stream_sync_sendbuf(stream, 1); + assert(ret == 0); + client_node->conns[0].egress = &delay_node->super; + *node_insert_at++ = &client_node->super; } break; + case 'b': + if (sscanf(optarg, "%lf", &bw) != 1) { + fprintf(stderr, "invalid bandwidth: %s\n", optarg); + exit(1); + } + break; case 'd': if (sscanf(optarg, "%lf", &delay) != 1) { fprintf(stderr, "invalid delay value: %s\n", optarg); @@ -517,41 +578,22 @@ int main(int argc, char **argv) } break; default: - printf("Usage: %s [-c name]\n\n", argv[0]); + usage(argv[0]); exit(0); } } + argc -= optind; + argv += optind; + + /* setup bottleneck */ + net_bottleneck_init(&bottleneck_node, bw, depth); + bottleneck_node.next_node = &server_node.node.super; + *node_insert_at++ = &bottleneck_node.super; - struct net_bottleneck bottleneck_node; - struct net_delay delay_node; - struct net_endpoint server_node, client_node; - - /* init nodes */ - net_queue_init(&bottleneck_node, bw, depth); - net_delay_init(&delay_node, delay); - net_endpoint_init(&server_node); - net_endpoint_init(&client_node); - - /* client uploads to server through the bottleneck queue */ - client_node.egress = &delay_node.super; - delay_node.next_node = &bottleneck_node.super; - bottleneck_node.next_node = &server_node.super; - server_node.egress = &client_node.super; - - /* start */ - server_node.accept_ctx = &quicctx; - int ret = quicly_connect(&client_node.quic, &quicctx, "hello.example.com", &server_node.addr.sa, &client_node.addr.sa, NULL, - ptls_iovec_init(NULL, 0), NULL, NULL); - assert(ret == 0); - quicly_stream_t *stream; - ret = quicly_open_stream(client_node.quic, &stream, 1); - assert(ret == 0); - ret = quicly_stream_sync_sendbuf(stream, 1); - assert(ret == 0); - - struct net_node *nodes[] = {&bottleneck_node.super, &delay_node.super, &server_node.super, &client_node.super, NULL}; while (now < 1050) run_nodes(nodes); return 0; } + +FILE *quicly_trace_fp; From 7615d616aeee3a40777cf62c7871228d3d8b6303 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 26 Aug 2021 14:18:23 +0900 Subject: [PATCH 137/361] prepare for modifications --- include/quicly/cc.h | 12 +++++-- lib/cc-pico.c | 85 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 81 insertions(+), 16 deletions(-) diff --git a/include/quicly/cc.h b/include/quicly/cc.h index bef3f4c85..a445bb0b3 100644 --- a/include/quicly/cc.h +++ b/include/quicly/cc.h @@ -66,8 +66,7 @@ typedef struct st_quicly_cc_t { */ union { /** - * State information for Reno congestion control. Pico also uses this (and therefore we can switch between Reno and Pico - * mid-connection). + * State information for Reno congestion control. */ struct { /** @@ -75,6 +74,15 @@ typedef struct st_quicly_cc_t { */ uint32_t stash; } reno; + /** + * State information for Pico. + */ + struct { + /** + * Stash of acknowledged bytes, used during congestion avoidance. + */ + uint32_t stash; + } pico; /** * State information for CUBIC congestion control. */ diff --git a/lib/cc-pico.c b/lib/cc-pico.c index ce37cb870..2bf9d9523 100644 --- a/lib/cc-pico.c +++ b/lib/cc-pico.c @@ -70,26 +70,83 @@ static void pico_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t b cc->cwnd_maximum = cc->cwnd; } +static void pico_on_lost(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t lost_pn, uint64_t next_pn, + int64_t now, uint32_t max_udp_payload_size) +{ + /* Nothing to do if loss is in recovery window. */ + if (lost_pn < cc->recovery_end) + return; + cc->recovery_end = next_pn; + + ++cc->num_loss_episodes; + if (cc->cwnd_exiting_slow_start == 0) + cc->cwnd_exiting_slow_start = cc->cwnd; + + /* Reduce congestion window. */ + cc->cwnd *= QUICLY_RENO_BETA; + if (cc->cwnd < QUICLY_MIN_CWND * max_udp_payload_size) + cc->cwnd = QUICLY_MIN_CWND * max_udp_payload_size; + cc->ssthresh = cc->cwnd; + + if (cc->cwnd_minimum > cc->cwnd) + cc->cwnd_minimum = cc->cwnd; +} + +static void pico_on_persistent_congestion(quicly_cc_t *cc, const quicly_loss_t *loss, int64_t now) +{ + /* TODO */ +} + +static void pico_on_sent(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, int64_t now) +{ + /* Unused */ +} + +static void pico_init_pico_state(quicly_cc_t *cc, uint32_t stash) +{ + cc->state.pico.stash = stash; +} + +static void pico_reset(quicly_cc_t *cc, uint32_t initcwnd) +{ + *cc = (quicly_cc_t){ + .type = &quicly_cc_type_pico, + .cwnd = initcwnd, + .cwnd_initial = initcwnd, + .cwnd_maximum = initcwnd, + .cwnd_minimum = UINT32_MAX, + .ssthresh = UINT32_MAX, + }; + pico_init_pico_state(cc, 0); +} + static int pico_on_switch(quicly_cc_t *cc) { - /* switch to reno then rewrite the type */ - if (!quicly_cc_type_reno.cc_switch(cc)) - return 0; - cc->type = &quicly_cc_type_pico; - return 1; + if (cc->type == &quicly_cc_type_pico) { + return 1; /* nothing to do */ + } else if (cc->type == &quicly_cc_type_reno) { + cc->type = &quicly_cc_type_reno; + pico_init_pico_state(cc, cc->state.reno.stash); + return 1; + } else if (cc->type == &quicly_cc_type_cubic) { + /* When in slow start, state can be reused as-is; otherwise, restart. */ + if (cc->cwnd_exiting_slow_start == 0) { + cc->type = &quicly_cc_type_reno; + pico_init_pico_state(cc, 0); + } else { + pico_reset(cc, cc->cwnd_initial); + } + return 1; + } + + return 0; } static void pico_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwnd, int64_t now) { - quicly_cc_type_reno.cc_init->cb(quicly_cc_type_reno.cc_init, cc, initcwnd, now); - cc->type = &quicly_cc_type_pico; + pico_reset(cc, initcwnd); } -quicly_cc_type_t quicly_cc_type_pico = {"pico", - &quicly_cc_pico_init, - pico_on_acked, - quicly_cc_reno_on_lost, - quicly_cc_reno_on_persistent_congestion, - quicly_cc_reno_on_sent, - pico_on_switch}; +quicly_cc_type_t quicly_cc_type_pico = { + "pico", &quicly_cc_pico_init, pico_on_acked, pico_on_lost, pico_on_persistent_congestion, pico_on_sent, pico_on_switch}; quicly_init_cc_t quicly_cc_pico_init = {pico_init}; From d0251dcddb2fa83c18b0bed6f85a20dab7320df9 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 26 Aug 2021 16:32:26 +0900 Subject: [PATCH 138/361] pass next_pn to `cc_on_acked` --- include/quicly/cc.h | 2 +- lib/cc-cubic.c | 2 +- lib/cc-pico.c | 2 +- lib/cc-reno.c | 2 +- lib/quicly.c | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/quicly/cc.h b/include/quicly/cc.h index a445bb0b3..1791f9325 100644 --- a/include/quicly/cc.h +++ b/include/quicly/cc.h @@ -144,7 +144,7 @@ struct st_quicly_cc_type_t { * Called when a packet is newly acknowledged. */ void (*cc_on_acked)(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t largest_acked, uint32_t inflight, - int64_t now, uint32_t max_udp_payload_size); + uint64_t next_pn, int64_t now, uint32_t max_udp_payload_size); /** * Called when a packet is detected as lost. |next_pn| is the next unsent packet number, * used for setting the recovery window. diff --git a/lib/cc-cubic.c b/lib/cc-cubic.c index 2b981a27d..e1b848d8b 100644 --- a/lib/cc-cubic.c +++ b/lib/cc-cubic.c @@ -61,7 +61,7 @@ static uint32_t calc_w_est(const quicly_cc_t *cc, cubic_float_t t_sec, cubic_flo /* TODO: Avoid increase if sender was application limited. */ static void cubic_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t largest_acked, uint32_t inflight, - int64_t now, uint32_t max_udp_payload_size) + uint64_t next_pn, int64_t now, uint32_t max_udp_payload_size) { assert(inflight >= bytes); /* Do not increase congestion window while in recovery. */ diff --git a/lib/cc-pico.c b/lib/cc-pico.c index 2bf9d9523..ee21ab277 100644 --- a/lib/cc-pico.c +++ b/lib/cc-pico.c @@ -44,7 +44,7 @@ static uint32_t calc_bytes_per_mtu_increase(uint32_t cwnd, uint32_t ssthresh, ui /* TODO: Avoid increase if sender was application limited. */ static void pico_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t largest_acked, uint32_t inflight, - int64_t now, uint32_t max_udp_payload_size) + uint64_t next_pn, int64_t now, uint32_t max_udp_payload_size) { assert(inflight >= bytes); diff --git a/lib/cc-reno.c b/lib/cc-reno.c index e4930ad81..059d003d3 100644 --- a/lib/cc-reno.c +++ b/lib/cc-reno.c @@ -24,7 +24,7 @@ /* TODO: Avoid increase if sender was application limited. */ static void reno_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t largest_acked, uint32_t inflight, - int64_t now, uint32_t max_udp_payload_size) + uint64_t next_pn, int64_t now, uint32_t max_udp_payload_size) { assert(inflight >= bytes); /* Do not increase congestion window while in recovery. */ diff --git a/lib/quicly.c b/lib/quicly.c index d87f9b154..bc456ed58 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -4879,8 +4879,8 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload /* OnPacketAcked and OnPacketAckedCC */ if (bytes_acked > 0) { conn->egress.cc.type->cc_on_acked(&conn->egress.cc, &conn->egress.loss, (uint32_t)bytes_acked, frame.largest_acknowledged, - (uint32_t)(conn->egress.loss.sentmap.bytes_in_flight + bytes_acked), conn->stash.now, - conn->egress.max_udp_payload_size); + (uint32_t)(conn->egress.loss.sentmap.bytes_in_flight + bytes_acked), + conn->egress.packet_number, conn->stash.now, conn->egress.max_udp_payload_size); QUICLY_PROBE(QUICTRACE_CC_ACK, conn, conn->stash.now, &conn->egress.loss.rtt, conn->egress.cc.cwnd, conn->egress.loss.sentmap.bytes_in_flight); } From 0e46c98e4797e6efc2c8c9faf172cc2381189663 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 27 Aug 2021 16:05:11 +0900 Subject: [PATCH 139/361] record number of bytes being acked --- include/quicly.h | 4 ++++ lib/quicly.c | 1 + 2 files changed, 5 insertions(+) diff --git a/include/quicly.h b/include/quicly.h index 38d84593d..37040613a 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -439,6 +439,10 @@ struct st_quicly_conn_streamgroup_state_t { * Total bytes sent but lost, at UDP datagram-level. \ */ \ uint64_t lost; \ + /** \ + * Total number of bytes for which acknowledgements have been received. \ + */ \ + uint64_t ack_received; \ /** \ * Total amount of stream-level payload being sent \ */ \ diff --git a/lib/quicly.c b/lib/quicly.c index d87f9b154..9c38325e1 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -4847,6 +4847,7 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload QUICLY_PROBE(PACKET_ACKED, conn, conn->stash.now, pn_acked, is_late_ack); if (sent->cc_bytes_in_flight != 0) { bytes_acked += sent->cc_bytes_in_flight; + conn->super.stats.num_bytes.ack_received += sent->cc_bytes_in_flight; } if ((ret = quicly_sentmap_update(&conn->egress.loss.sentmap, &iter, QUICLY_SENTMAP_EVENT_ACKED)) != 0) return ret; From 8e20409da2991c76946fc74a00243c9d94cbc309 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sat, 28 Aug 2021 19:35:16 +0900 Subject: [PATCH 140/361] delivery rate estimator --- include/quicly.h | 14 +++++++-- lib/quicly.c | 80 ++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 82 insertions(+), 12 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index 37040613a..14484d280 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -458,13 +458,21 @@ struct st_quicly_conn_streamgroup_state_t { struct { \ uint64_t padding, ping, ack, reset_stream, stop_sending, crypto, new_token, stream, max_data, max_stream_data, \ max_streams_bidi, max_streams_uni, data_blocked, stream_data_blocked, streams_blocked, new_connection_id, \ - retire_connection_id, path_challenge, path_response, transport_close, application_close, handshake_done, \ - datagram, ack_frequency; \ + retire_connection_id, path_challenge, path_response, transport_close, application_close, handshake_done, datagram, \ + ack_frequency; \ } num_frames_sent, num_frames_received; \ /** \ * Total number of PTOs observed during the connection. \ */ \ - uint64_t num_ptos + uint64_t num_ptos; \ + /** \ + * Delivery rate. All the values are represented as second / byte. \ + */ \ + struct { \ + double smoothed; \ + double variance; \ + double latest; \ + } delivery_rate typedef struct st_quicly_stats_t { /** diff --git a/lib/quicly.c b/lib/quicly.c index 9c38325e1..9b05b1db7 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -21,6 +21,7 @@ */ #include #include +#include #include #include #include @@ -74,6 +75,13 @@ */ #define QUICLY_NUM_ACK_BLOCKS_TO_INDUCE_ACKACK 8 +#ifndef QUICLY_DELIVERY_RATE_ESTIMATE_INTERVAL +/** + * interval between taking delivery rate estimation samples + */ +#define QUICLY_DELIVERY_RATE_ESTIMATE_INTERVAL 50 +#endif + KHASH_MAP_INIT_INT64(quicly_stream_t, quicly_stream_t *) #if QUICLY_USE_TRACER @@ -349,6 +357,13 @@ struct st_quicly_conn_t { ptls_iovec_t payloads[10]; size_t count; } datagram_frame_payloads; + /** + * + */ + struct { + int64_t at; + uint64_t bytes_acked; + } delivery_rate_sample; } egress; /** * crypto data @@ -1269,12 +1284,25 @@ static int scheduler_can_send(quicly_conn_t *conn) return conn->super.ctx->stream_scheduler->can_send(conn->super.ctx->stream_scheduler, conn, conn_is_saturated); } -static void update_loss_alarm(quicly_conn_t *conn, int is_after_send) +static void do_update_loss_alarm(quicly_conn_t *conn, int can_send_stream_data, int is_after_send) { int has_outstanding = conn->egress.loss.sentmap.bytes_in_flight != 0 || conn->super.remote.address_validation.send_probe, handshake_is_in_progress = conn->initial != NULL || conn->handshake != NULL; quicly_loss_update_alarm(&conn->egress.loss, conn->stash.now, conn->egress.last_retransmittable_sent_at, has_outstanding, - scheduler_can_send(conn), handshake_is_in_progress, conn->egress.max_data.sent, is_after_send); + can_send_stream_data, handshake_is_in_progress, conn->egress.max_data.sent, is_after_send); +} + +/** + * Updates the loss alarm, and adjusts the delivery rate estimator. From the send path, `do_update_loss_alarm` is called directly. + */ +static void update_loss_alarm(quicly_conn_t *conn) +{ + int can_send_stream_data = scheduler_can_send(conn); + + do_update_loss_alarm(conn, can_send_stream_data, 0); + + if (!can_send_stream_data) + conn->egress.delivery_rate_sample.at = INT64_MAX; } static int create_handshake_flow(quicly_conn_t *conn, size_t epoch) @@ -4432,7 +4460,17 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) if (ret == 0) { if (conn->application == NULL || conn->application->super.unacked_count == 0) conn->egress.send_ack_at = INT64_MAX; /* we have sent ACKs for every epoch (or before address validation) */ - update_loss_alarm(conn, 1); + int can_send_stream_data = scheduler_can_send(conn); + do_update_loss_alarm(conn, can_send_stream_data, 1); + if (can_send_stream_data && + (s->num_datagrams == s->max_datagrams || conn->egress.loss.sentmap.bytes_in_flight >= conn->egress.cc.cwnd)) { + if (conn->egress.delivery_rate_sample.at == INT64_MAX) { + conn->egress.delivery_rate_sample.at = conn->stash.now; + conn->egress.delivery_rate_sample.at = conn->super.stats.num_bytes.ack_received; + } + } else { + conn->egress.delivery_rate_sample.at = INT64_MAX; + } if (s->num_datagrams != 0) update_idle_timeout(conn, 0); } @@ -4627,7 +4665,7 @@ static int enter_close(quicly_conn_t *conn, int local_is_initiating, int wait_dr conn->egress.send_ack_at = wait_draining ? conn->stash.now + get_sentmap_expiration_time(conn) : 0; } - update_loss_alarm(conn, 0); + update_loss_alarm(conn); return 0; } @@ -4778,6 +4816,21 @@ static int handle_reset_stream_frame(quicly_conn_t *conn, struct st_quicly_handl return 0; } +static void update_delivery_rate(quicly_conn_t *conn, uint64_t bytes_acked, int64_t elapsed) +{ + conn->super.stats.delivery_rate.latest = elapsed / (bytes_acked * 1000.); + if (isnan(conn->super.stats.delivery_rate.smoothed)) { + /* first sample */ + conn->super.stats.delivery_rate.smoothed = conn->super.stats.delivery_rate.latest; + conn->super.stats.delivery_rate.variance = conn->super.stats.delivery_rate.latest / 2; + } else { + double absdiff = fabs(conn->super.stats.delivery_rate.smoothed - conn->super.stats.delivery_rate.latest); + conn->super.stats.delivery_rate.variance = (conn->super.stats.delivery_rate.variance * 4 + absdiff) / 5; + conn->super.stats.delivery_rate.smoothed = + (conn->super.stats.delivery_rate.smoothed * 9 + conn->super.stats.delivery_rate.latest) / 10; + } +} + static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) { quicly_ack_frame_t frame; @@ -4872,6 +4925,15 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload QUICLY_PROBE(ACK_DELAY_RECEIVED, conn, conn->stash.now, frame.ack_delay); + /* update delivery rate estimator */ + if (conn->egress.delivery_rate_sample.at <= conn->stash.now - QUICLY_DELIVERY_RATE_ESTIMATE_INTERVAL) { + int64_t elapsed = conn->stash.now - conn->egress.delivery_rate_sample.at; + uint64_t bytes_acked = conn->super.stats.num_bytes.ack_received - conn->egress.delivery_rate_sample.bytes_acked; + update_delivery_rate(conn, bytes_acked, elapsed); + conn->egress.delivery_rate_sample.at = conn->stash.now; + conn->egress.delivery_rate_sample.bytes_acked = conn->super.stats.num_bytes.ack_received; + } + /* Update loss detection engine on ack. The function uses ack_delay only when the largest_newly_acked is also the largest acked * so far. So, it does not matter if the ack_delay being passed in does not apply to the largest_newly_acked. */ quicly_loss_on_ack_received(&conn->egress.loss, largest_newly_acked.pn, state->epoch, conn->stash.now, @@ -4893,7 +4955,7 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload if ((ret = quicly_loss_detect_loss(&conn->egress.loss, conn->stash.now, conn->super.remote.transport_params.max_ack_delay, conn->initial == NULL && conn->handshake == NULL, on_loss_detected)) != 0) return ret; - update_loss_alarm(conn, 0); + update_loss_alarm(conn); return 0; } @@ -5375,7 +5437,7 @@ static int handle_handshake_done_frame(quicly_conn_t *conn, struct st_quicly_han conn->super.remote.address_validation.send_probe = 0; if ((ret = discard_handshake_context(conn, QUICLY_EPOCH_HANDSHAKE)) != 0) return ret; - update_loss_alarm(conn, 0); + update_loss_alarm(conn); return 0; } @@ -5870,7 +5932,7 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka if (conn->initial != NULL) { if ((ret = discard_handshake_context(conn, QUICLY_EPOCH_INITIAL)) != 0) goto Exit; - update_loss_alarm(conn, 0); + update_loss_alarm(conn); conn->super.remote.address_validation.validated = 1; } break; @@ -5893,7 +5955,7 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka if (quicly_is_client(conn) && conn->handshake != NULL && conn->handshake->cipher.egress.aead != NULL) { if ((ret = discard_handshake_context(conn, QUICLY_EPOCH_INITIAL)) != 0) goto Exit; - update_loss_alarm(conn, 0); + update_loss_alarm(conn); } break; case QUICLY_EPOCH_HANDSHAKE: @@ -5911,7 +5973,7 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka goto Exit; assert(conn->handshake == NULL); conn->egress.pending_flows |= QUICLY_PENDING_FLOW_HANDSHAKE_DONE_BIT; - update_loss_alarm(conn, 0); + update_loss_alarm(conn); } } break; From b03aa135f52f311f4018de80dd5229a0ff675c97 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sun, 29 Aug 2021 15:41:12 +0900 Subject: [PATCH 141/361] opportunistically reduce the number of ack ranges added to sentmap --- include/quicly/sentmap.h | 19 +++++- lib/quicly.c | 125 ++++++++++++++++++++++++++++----------- 2 files changed, 108 insertions(+), 36 deletions(-) diff --git a/include/quicly/sentmap.h b/include/quicly/sentmap.h index 20a6bfb3b..92db9a468 100644 --- a/include/quicly/sentmap.h +++ b/include/quicly/sentmap.h @@ -91,12 +91,29 @@ typedef enum en_quicly_sentmap_event_t { */ typedef int (*quicly_sent_acked_cb)(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *data); +struct st_quicly_sent_ack_additional_t { + uint8_t gap; + uint8_t length; +}; + struct st_quicly_sent_t { quicly_sent_acked_cb acked; union { quicly_sent_packet_t packet; struct { - quicly_range_t range; + uint64_t start; + union { + struct { + uint64_t start_length; + uint8_t num_additional; + struct st_quicly_sent_ack_additional_t additional[3]; + } ranges64; + struct { + uint8_t start_length; + uint8_t num_additional; + struct st_quicly_sent_ack_additional_t additional[7]; + } ranges8; + }; } ack; struct { quicly_stream_id_t stream_id; diff --git a/lib/quicly.c b/lib/quicly.c index d87f9b154..f8c8e71b7 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -2530,45 +2530,72 @@ static int decrypt_packet(ptls_cipher_context_t *header_protection, return 0; } -static int on_ack_ack(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent) +static int do_on_ack_ack(quicly_conn_t *conn, const quicly_sent_packet_t *packet, uint64_t start, uint64_t start_length, + struct st_quicly_sent_ack_additional_t *additional, size_t num_additional) { - quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); - - /* TODO log */ + /* find the pn space */ + struct st_quicly_pn_space_t *space; + switch (packet->ack_epoch) { + case QUICLY_EPOCH_INITIAL: + space = &conn->initial->super; + break; + case QUICLY_EPOCH_HANDSHAKE: + space = &conn->handshake->super; + break; + case QUICLY_EPOCH_1RTT: + space = &conn->application->super; + break; + default: + assert(!"FIXME"); + return QUICLY_TRANSPORT_ERROR_INTERNAL; + } - if (acked) { - /* find the pn space */ - struct st_quicly_pn_space_t *space; - switch (packet->ack_epoch) { - case QUICLY_EPOCH_INITIAL: - space = &conn->initial->super; - break; - case QUICLY_EPOCH_HANDSHAKE: - space = &conn->handshake->super; - break; - case QUICLY_EPOCH_1RTT: - space = &conn->application->super; - break; - default: - assert(!"FIXME"); - return QUICLY_TRANSPORT_ERROR_INTERNAL; - } - /* subtract given ACK range, then make adjustments */ - int ret; - if ((ret = quicly_ranges_subtract(&space->ack_queue, sent->data.ack.range.start, sent->data.ack.range.end)) != 0) + /* subtract given ACK ranges */ + int ret; + uint64_t end = start + start_length; + if ((ret = quicly_ranges_subtract(&space->ack_queue, start, end)) != 0) + return ret; + for (size_t i = 0; i < num_additional; ++i) { + start = end + additional[i].gap; + end = start + additional[i].length; + if ((ret = quicly_ranges_subtract(&space->ack_queue, start, end)) != 0) return ret; - if (space->ack_queue.num_ranges == 0) { - space->largest_pn_received_at = INT64_MAX; - space->unacked_count = 0; - } else if (space->ack_queue.num_ranges > QUICLY_MAX_ACK_BLOCKS) { - quicly_ranges_drop_by_range_indices(&space->ack_queue, space->ack_queue.num_ranges - QUICLY_MAX_ACK_BLOCKS, - space->ack_queue.num_ranges); - } + } + + /* make adjustments */ + if (space->ack_queue.num_ranges == 0) { + space->largest_pn_received_at = INT64_MAX; + space->unacked_count = 0; + } else if (space->ack_queue.num_ranges > QUICLY_MAX_ACK_BLOCKS) { + quicly_ranges_drop_by_range_indices(&space->ack_queue, space->ack_queue.num_ranges - QUICLY_MAX_ACK_BLOCKS, + space->ack_queue.num_ranges); } return 0; } +static int on_ack_ack_ranges64(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent) +{ + quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); + + /* TODO log */ + + return acked ? do_on_ack_ack(conn, packet, sent->data.ack.start, sent->data.ack.ranges64.start_length, + sent->data.ack.ranges64.additional, sent->data.ack.ranges64.num_additional) + : 0; +} + +static int on_ack_ack_ranges8(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent) +{ + quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); + + /* TODO log */ + + return acked ? do_on_ack_ack(conn, packet, sent->data.ack.start, sent->data.ack.ranges8.start_length, + sent->data.ack.ranges8.additional, sent->data.ack.ranges8.num_additional) + : 0; +} + static int on_ack_stream_ack_one(quicly_conn_t *conn, quicly_stream_id_t stream_id, quicly_sendstate_sent_t *sent) { quicly_stream_t *stream; @@ -3312,12 +3339,40 @@ static int send_ack(quicly_conn_t *conn, struct st_quicly_pn_space_t *space, qui s->dst = dst; { /* save what's inflight */ - size_t i; - for (i = 0; i != space->ack_queue.num_ranges; ++i) { + size_t range_index = 0; + while (range_index < space->ack_queue.num_ranges) { quicly_sent_t *sent; - if ((sent = quicly_sentmap_allocate(&conn->egress.loss.sentmap, on_ack_ack)) == NULL) + struct st_quicly_sent_ack_additional_t *additional; + uint8_t additional_capacity, *num_additional; + /* allocate */ + if ((sent = quicly_sentmap_allocate(&conn->egress.loss.sentmap, on_ack_ack_ranges8)) == NULL) return PTLS_ERROR_NO_MEMORY; - sent->data.ack.range = space->ack_queue.ranges[i]; + /* store the first range, as well as preparing references to the additional slots */ + sent->data.ack.start = space->ack_queue.ranges[range_index].start; + uint64_t length = space->ack_queue.ranges[range_index].end - space->ack_queue.ranges[range_index].start; + if (length < UINT8_MAX) { + sent->data.ack.ranges8.start_length = length; + additional = sent->data.ack.ranges8.additional; + additional_capacity = PTLS_ELEMENTSOF(sent->data.ack.ranges8.additional); + num_additional = &sent->data.ack.ranges8.num_additional; + } else { + sent->acked = on_ack_ack_ranges64; + sent->data.ack.ranges64.start_length = length; + additional = sent->data.ack.ranges64.additional; + additional_capacity = PTLS_ELEMENTSOF(sent->data.ack.ranges64.additional); + num_additional = &sent->data.ack.ranges64.num_additional; + } + /* store additional ranges, if possible */ + for (++range_index, *num_additional = 0; + range_index < space->ack_queue.num_ranges && *num_additional < additional_capacity; + ++range_index, ++*num_additional) { + uint64_t gap = space->ack_queue.ranges[range_index].start - space->ack_queue.ranges[range_index - 1].end; + uint64_t length = space->ack_queue.ranges[range_index].end - space->ack_queue.ranges[range_index].start; + if (gap > UINT8_MAX || length > UINT8_MAX) + break; + additional[*num_additional].gap = gap; + additional[*num_additional].length = length; + } } } From c22ea428a42525f85b50a62bd48cb226d0a751eb Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sun, 29 Aug 2021 16:53:24 +0900 Subject: [PATCH 142/361] 255 can be stored in uint8_t --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index f8c8e71b7..6f59b9c16 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3350,7 +3350,7 @@ static int send_ack(quicly_conn_t *conn, struct st_quicly_pn_space_t *space, qui /* store the first range, as well as preparing references to the additional slots */ sent->data.ack.start = space->ack_queue.ranges[range_index].start; uint64_t length = space->ack_queue.ranges[range_index].end - space->ack_queue.ranges[range_index].start; - if (length < UINT8_MAX) { + if (length <= UINT8_MAX) { sent->data.ack.ranges8.start_length = length; additional = sent->data.ack.ranges8.additional; additional_capacity = PTLS_ELEMENTSOF(sent->data.ack.ranges8.additional); From 17b409adf6efca4fc66fcdda37d46e225da8db5b Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sun, 29 Aug 2021 22:59:08 +0900 Subject: [PATCH 143/361] Omit `num_additional` to store one more. --- include/quicly/sentmap.h | 7 ++++--- lib/quicly.c | 29 ++++++++++++++--------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/quicly/sentmap.h b/include/quicly/sentmap.h index 92db9a468..bf022bbaa 100644 --- a/include/quicly/sentmap.h +++ b/include/quicly/sentmap.h @@ -100,17 +100,18 @@ struct st_quicly_sent_t { quicly_sent_acked_cb acked; union { quicly_sent_packet_t packet; + /** + * ACK frame. Represents up to 8 ack ranges. If not full, `additional` list is terminated by .gap = 0. + */ struct { uint64_t start; union { struct { uint64_t start_length; - uint8_t num_additional; - struct st_quicly_sent_ack_additional_t additional[3]; + struct st_quicly_sent_ack_additional_t additional[4]; } ranges64; struct { uint8_t start_length; - uint8_t num_additional; struct st_quicly_sent_ack_additional_t additional[7]; } ranges8; }; diff --git a/lib/quicly.c b/lib/quicly.c index 6f59b9c16..3245a7354 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -2531,7 +2531,7 @@ static int decrypt_packet(ptls_cipher_context_t *header_protection, } static int do_on_ack_ack(quicly_conn_t *conn, const quicly_sent_packet_t *packet, uint64_t start, uint64_t start_length, - struct st_quicly_sent_ack_additional_t *additional, size_t num_additional) + struct st_quicly_sent_ack_additional_t *additional, size_t additional_capacity) { /* find the pn space */ struct st_quicly_pn_space_t *space; @@ -2555,7 +2555,7 @@ static int do_on_ack_ack(quicly_conn_t *conn, const quicly_sent_packet_t *packet uint64_t end = start + start_length; if ((ret = quicly_ranges_subtract(&space->ack_queue, start, end)) != 0) return ret; - for (size_t i = 0; i < num_additional; ++i) { + for (size_t i = 0; i < additional_capacity && additional[i].gap != 0; ++i) { start = end + additional[i].gap; end = start + additional[i].length; if ((ret = quicly_ranges_subtract(&space->ack_queue, start, end)) != 0) @@ -2581,7 +2581,7 @@ static int on_ack_ack_ranges64(quicly_sentmap_t *map, const quicly_sent_packet_t /* TODO log */ return acked ? do_on_ack_ack(conn, packet, sent->data.ack.start, sent->data.ack.ranges64.start_length, - sent->data.ack.ranges64.additional, sent->data.ack.ranges64.num_additional) + sent->data.ack.ranges64.additional, PTLS_ELEMENTSOF(sent->data.ack.ranges64.additional)) : 0; } @@ -2592,7 +2592,7 @@ static int on_ack_ack_ranges8(quicly_sentmap_t *map, const quicly_sent_packet_t /* TODO log */ return acked ? do_on_ack_ack(conn, packet, sent->data.ack.start, sent->data.ack.ranges8.start_length, - sent->data.ack.ranges8.additional, sent->data.ack.ranges8.num_additional) + sent->data.ack.ranges8.additional, PTLS_ELEMENTSOF(sent->data.ack.ranges8.additional)) : 0; } @@ -3342,8 +3342,7 @@ static int send_ack(quicly_conn_t *conn, struct st_quicly_pn_space_t *space, qui size_t range_index = 0; while (range_index < space->ack_queue.num_ranges) { quicly_sent_t *sent; - struct st_quicly_sent_ack_additional_t *additional; - uint8_t additional_capacity, *num_additional; + struct st_quicly_sent_ack_additional_t *additional, *additional_end; /* allocate */ if ((sent = quicly_sentmap_allocate(&conn->egress.loss.sentmap, on_ack_ack_ranges8)) == NULL) return PTLS_ERROR_NO_MEMORY; @@ -3353,26 +3352,26 @@ static int send_ack(quicly_conn_t *conn, struct st_quicly_pn_space_t *space, qui if (length <= UINT8_MAX) { sent->data.ack.ranges8.start_length = length; additional = sent->data.ack.ranges8.additional; - additional_capacity = PTLS_ELEMENTSOF(sent->data.ack.ranges8.additional); - num_additional = &sent->data.ack.ranges8.num_additional; + additional_end = additional + PTLS_ELEMENTSOF(sent->data.ack.ranges8.additional); } else { sent->acked = on_ack_ack_ranges64; sent->data.ack.ranges64.start_length = length; additional = sent->data.ack.ranges64.additional; - additional_capacity = PTLS_ELEMENTSOF(sent->data.ack.ranges64.additional); - num_additional = &sent->data.ack.ranges64.num_additional; + additional_end = additional + PTLS_ELEMENTSOF(sent->data.ack.ranges64.additional); } /* store additional ranges, if possible */ - for (++range_index, *num_additional = 0; - range_index < space->ack_queue.num_ranges && *num_additional < additional_capacity; - ++range_index, ++*num_additional) { + for (++range_index; range_index < space->ack_queue.num_ranges && additional < additional_end; + ++range_index, ++additional) { uint64_t gap = space->ack_queue.ranges[range_index].start - space->ack_queue.ranges[range_index - 1].end; uint64_t length = space->ack_queue.ranges[range_index].end - space->ack_queue.ranges[range_index].start; if (gap > UINT8_MAX || length > UINT8_MAX) break; - additional[*num_additional].gap = gap; - additional[*num_additional].length = length; + additional->gap = gap; + additional->length = length; } + /* additional list is zero-terminated, if not full */ + if (additional < additional_end) + additional->gap = 0; } } From cc23087fec3db20c8ea2c28019926b32a1158d22 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 30 Aug 2021 14:30:09 +0900 Subject: [PATCH 144/361] ignore MAX_STREAM_DATA frames that do not carry a new limit - otherwise we'd see ping-pong of STREAM_DATA_BLOCKED vs. STREAM_DATA --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index d87f9b154..3f4acde73 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -4914,7 +4914,7 @@ static int handle_max_stream_data_frame(quicly_conn_t *conn, struct st_quicly_ha if ((stream = quicly_get_stream(conn, frame.stream_id)) == NULL) return 0; - if (frame.max_stream_data < stream->_send_aux.max_stream_data) + if (frame.max_stream_data <= stream->_send_aux.max_stream_data) return 0; stream->_send_aux.max_stream_data = frame.max_stream_data; stream->_send_aux.blocked = QUICLY_SENDER_STATE_NONE; From 87b5a345feb49a9df47d5bf62de01de4fa7483a5 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 31 Aug 2021 17:03:56 +0900 Subject: [PATCH 145/361] Update lib/quicly.c Co-authored-by: Jana Iyengar --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 9b05b1db7..48c04c5ca 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -4466,7 +4466,7 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) (s->num_datagrams == s->max_datagrams || conn->egress.loss.sentmap.bytes_in_flight >= conn->egress.cc.cwnd)) { if (conn->egress.delivery_rate_sample.at == INT64_MAX) { conn->egress.delivery_rate_sample.at = conn->stash.now; - conn->egress.delivery_rate_sample.at = conn->super.stats.num_bytes.ack_received; + conn->egress.delivery_rate_sample.bytes_acked = conn->super.stats.num_bytes.ack_received; } } else { conn->egress.delivery_rate_sample.at = INT64_MAX; From 29422c8b8c2c1773ada3b64991d2ef9bde1feadd Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 31 Aug 2021 17:10:04 +0900 Subject: [PATCH 146/361] rename --- lib/quicly.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 48c04c5ca..d217ea938 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1284,7 +1284,7 @@ static int scheduler_can_send(quicly_conn_t *conn) return conn->super.ctx->stream_scheduler->can_send(conn->super.ctx->stream_scheduler, conn, conn_is_saturated); } -static void do_update_loss_alarm(quicly_conn_t *conn, int can_send_stream_data, int is_after_send) +static void update_send_alarm(quicly_conn_t *conn, int can_send_stream_data, int is_after_send) { int has_outstanding = conn->egress.loss.sentmap.bytes_in_flight != 0 || conn->super.remote.address_validation.send_probe, handshake_is_in_progress = conn->initial != NULL || conn->handshake != NULL; @@ -1293,13 +1293,14 @@ static void do_update_loss_alarm(quicly_conn_t *conn, int can_send_stream_data, } /** - * Updates the loss alarm, and adjusts the delivery rate estimator. From the send path, `do_update_loss_alarm` is called directly. + * Updates the send alarm and adjusts the delivery rate estimator. This function is called from the receive path. From the sendp + * path, `update_send_alarm` is called directly. */ -static void update_loss_alarm(quicly_conn_t *conn) +static void setup_next_send(quicly_conn_t *conn) { int can_send_stream_data = scheduler_can_send(conn); - do_update_loss_alarm(conn, can_send_stream_data, 0); + update_send_alarm(conn, can_send_stream_data, 0); if (!can_send_stream_data) conn->egress.delivery_rate_sample.at = INT64_MAX; @@ -4461,7 +4462,7 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) if (conn->application == NULL || conn->application->super.unacked_count == 0) conn->egress.send_ack_at = INT64_MAX; /* we have sent ACKs for every epoch (or before address validation) */ int can_send_stream_data = scheduler_can_send(conn); - do_update_loss_alarm(conn, can_send_stream_data, 1); + update_send_alarm(conn, can_send_stream_data, 1); if (can_send_stream_data && (s->num_datagrams == s->max_datagrams || conn->egress.loss.sentmap.bytes_in_flight >= conn->egress.cc.cwnd)) { if (conn->egress.delivery_rate_sample.at == INT64_MAX) { @@ -4665,7 +4666,7 @@ static int enter_close(quicly_conn_t *conn, int local_is_initiating, int wait_dr conn->egress.send_ack_at = wait_draining ? conn->stash.now + get_sentmap_expiration_time(conn) : 0; } - update_loss_alarm(conn); + setup_next_send(conn); return 0; } @@ -4955,7 +4956,7 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload if ((ret = quicly_loss_detect_loss(&conn->egress.loss, conn->stash.now, conn->super.remote.transport_params.max_ack_delay, conn->initial == NULL && conn->handshake == NULL, on_loss_detected)) != 0) return ret; - update_loss_alarm(conn); + setup_next_send(conn); return 0; } @@ -5437,7 +5438,7 @@ static int handle_handshake_done_frame(quicly_conn_t *conn, struct st_quicly_han conn->super.remote.address_validation.send_probe = 0; if ((ret = discard_handshake_context(conn, QUICLY_EPOCH_HANDSHAKE)) != 0) return ret; - update_loss_alarm(conn); + setup_next_send(conn); return 0; } @@ -5932,7 +5933,7 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka if (conn->initial != NULL) { if ((ret = discard_handshake_context(conn, QUICLY_EPOCH_INITIAL)) != 0) goto Exit; - update_loss_alarm(conn); + setup_next_send(conn); conn->super.remote.address_validation.validated = 1; } break; @@ -5955,7 +5956,7 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka if (quicly_is_client(conn) && conn->handshake != NULL && conn->handshake->cipher.egress.aead != NULL) { if ((ret = discard_handshake_context(conn, QUICLY_EPOCH_INITIAL)) != 0) goto Exit; - update_loss_alarm(conn); + setup_next_send(conn); } break; case QUICLY_EPOCH_HANDSHAKE: @@ -5973,7 +5974,7 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka goto Exit; assert(conn->handshake == NULL); conn->egress.pending_flows |= QUICLY_PENDING_FLOW_HANDSHAKE_DONE_BIT; - update_loss_alarm(conn); + setup_next_send(conn); } } break; From eafefd28f9b1da5e350b7c56ef43ec8f1b9e8538 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 31 Aug 2021 17:45:07 +0900 Subject: [PATCH 147/361] instead of EMEA, use moving average of 10 samples (500ms) --- include/quicly.h | 18 ++++----- lib/quicly.c | 101 ++++++++++++++++++++++++++++++++--------------- 2 files changed, 78 insertions(+), 41 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index 14484d280..df1214ce2 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -464,15 +464,7 @@ struct st_quicly_conn_streamgroup_state_t { /** \ * Total number of PTOs observed during the connection. \ */ \ - uint64_t num_ptos; \ - /** \ - * Delivery rate. All the values are represented as second / byte. \ - */ \ - struct { \ - double smoothed; \ - double variance; \ - double latest; \ - } delivery_rate + uint64_t num_ptos typedef struct st_quicly_stats_t { /** @@ -487,6 +479,14 @@ typedef struct st_quicly_stats_t { * Congestion control stats (experimental; TODO cherry-pick what can be exposed as part of a stable API). */ quicly_cc_t cc; + /** + * Estimated delivery rate, in bytes/second. + */ + struct { + uint64_t latest; + uint64_t smoothed; + uint64_t variance; + } delivery_rate; } quicly_stats_t; /** diff --git a/lib/quicly.c b/lib/quicly.c index d217ea938..662f7cfa1 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -75,11 +75,18 @@ */ #define QUICLY_NUM_ACK_BLOCKS_TO_INDUCE_ACKACK 8 -#ifndef QUICLY_DELIVERY_RATE_ESTIMATE_INTERVAL +#ifndef QUICLY_DELIVERY_RATE_SAMPLE_PERIOD /** - * interval between taking delivery rate estimation samples + * sampling period of delivery rate, in milliseconds */ -#define QUICLY_DELIVERY_RATE_ESTIMATE_INTERVAL 50 +#define QUICLY_DELIVERY_RATE_SAMPLE_PERIOD 50 +#endif + +#ifndef QUICLY_DELIVERY_RATE_SAMPLE_COUNT +/** + * number of samples to retain (and to calculate average from) + */ +#define QUICLY_DELIVERY_RATE_SAMPLE_COUNT 10 #endif KHASH_MAP_INIT_INT64(quicly_stream_t, quicly_stream_t *) @@ -361,9 +368,16 @@ struct st_quicly_conn_t { * */ struct { - int64_t at; - uint64_t bytes_acked; - } delivery_rate_sample; + struct st_quicly_delivery_rate_sample_t { + uint32_t elapsed; + uint32_t bytes_acked; + } samples[10]; + size_t next_sample_index; + struct { + int64_t at; + uint64_t bytes_acked; + } next_sample_start; + } delivery_rate; } egress; /** * crypto data @@ -1224,6 +1238,41 @@ int quicly_get_stats(quicly_conn_t *conn, quicly_stats_t *stats) /* set or generate the non-pre-built stats fields here */ stats->rtt = conn->egress.loss.rtt; stats->cc = conn->egress.cc; + + /* delivery rate, calculate the numbers if we've got samples, otherwise set to zero */ + if (conn->egress.delivery_rate.samples[0].elapsed != 0) { + { /* calculate latest */ + struct st_quicly_delivery_rate_sample_t *latest = + &conn->egress.delivery_rate.samples[conn->egress.delivery_rate.next_sample_index != 0 + ? conn->egress.delivery_rate.next_sample_index - 1 + : PTLS_ELEMENTSOF(conn->egress.delivery_rate.samples) - 1]; + stats->delivery_rate.latest = (uint64_t)latest->bytes_acked * 1000 / latest->elapsed; + } + { /* calculate average */ + uint64_t total_acked = 0; + uint32_t total_elapsed = 0; + size_t i; + for (i = 0; + i < PTLS_ELEMENTSOF(conn->egress.delivery_rate.samples) && conn->egress.delivery_rate.samples[i].elapsed != 0; + ++i) { + total_acked += conn->egress.delivery_rate.samples[i].bytes_acked; + total_elapsed += conn->egress.delivery_rate.samples[i].elapsed; + } + stats->delivery_rate.smoothed = total_acked * 1000 / total_elapsed; + } + { /* calculate variance */ + uint64_t sum = 0; + size_t i; + for (i = 0; + i < PTLS_ELEMENTSOF(conn->egress.delivery_rate.samples) && conn->egress.delivery_rate.samples[i].elapsed != 0; + ++i) { + uint64_t sample = conn->egress.delivery_rate.samples[i].bytes_acked * (1000 / QUICLY_DELIVERY_RATE_SAMPLE_PERIOD); + sum += (sample - stats->delivery_rate.smoothed) * (sample - stats->delivery_rate.smoothed); + } + stats->delivery_rate.variance = sum / i; + } + } + return 0; } @@ -1303,7 +1352,7 @@ static void setup_next_send(quicly_conn_t *conn) update_send_alarm(conn, can_send_stream_data, 0); if (!can_send_stream_data) - conn->egress.delivery_rate_sample.at = INT64_MAX; + conn->egress.delivery_rate.next_sample_start.at = INT64_MAX; } static int create_handshake_flow(quicly_conn_t *conn, size_t epoch) @@ -4465,12 +4514,12 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) update_send_alarm(conn, can_send_stream_data, 1); if (can_send_stream_data && (s->num_datagrams == s->max_datagrams || conn->egress.loss.sentmap.bytes_in_flight >= conn->egress.cc.cwnd)) { - if (conn->egress.delivery_rate_sample.at == INT64_MAX) { - conn->egress.delivery_rate_sample.at = conn->stash.now; - conn->egress.delivery_rate_sample.bytes_acked = conn->super.stats.num_bytes.ack_received; + if (conn->egress.delivery_rate.next_sample_start.at == INT64_MAX) { + conn->egress.delivery_rate.next_sample_start.at = conn->stash.now; + conn->egress.delivery_rate.next_sample_start.bytes_acked = conn->super.stats.num_bytes.ack_received; } } else { - conn->egress.delivery_rate_sample.at = INT64_MAX; + conn->egress.delivery_rate.next_sample_start.at = INT64_MAX; } if (s->num_datagrams != 0) update_idle_timeout(conn, 0); @@ -4817,21 +4866,6 @@ static int handle_reset_stream_frame(quicly_conn_t *conn, struct st_quicly_handl return 0; } -static void update_delivery_rate(quicly_conn_t *conn, uint64_t bytes_acked, int64_t elapsed) -{ - conn->super.stats.delivery_rate.latest = elapsed / (bytes_acked * 1000.); - if (isnan(conn->super.stats.delivery_rate.smoothed)) { - /* first sample */ - conn->super.stats.delivery_rate.smoothed = conn->super.stats.delivery_rate.latest; - conn->super.stats.delivery_rate.variance = conn->super.stats.delivery_rate.latest / 2; - } else { - double absdiff = fabs(conn->super.stats.delivery_rate.smoothed - conn->super.stats.delivery_rate.latest); - conn->super.stats.delivery_rate.variance = (conn->super.stats.delivery_rate.variance * 4 + absdiff) / 5; - conn->super.stats.delivery_rate.smoothed = - (conn->super.stats.delivery_rate.smoothed * 9 + conn->super.stats.delivery_rate.latest) / 10; - } -} - static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) { quicly_ack_frame_t frame; @@ -4927,12 +4961,15 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload QUICLY_PROBE(ACK_DELAY_RECEIVED, conn, conn->stash.now, frame.ack_delay); /* update delivery rate estimator */ - if (conn->egress.delivery_rate_sample.at <= conn->stash.now - QUICLY_DELIVERY_RATE_ESTIMATE_INTERVAL) { - int64_t elapsed = conn->stash.now - conn->egress.delivery_rate_sample.at; - uint64_t bytes_acked = conn->super.stats.num_bytes.ack_received - conn->egress.delivery_rate_sample.bytes_acked; - update_delivery_rate(conn, bytes_acked, elapsed); - conn->egress.delivery_rate_sample.at = conn->stash.now; - conn->egress.delivery_rate_sample.bytes_acked = conn->super.stats.num_bytes.ack_received; + if (conn->egress.delivery_rate.next_sample_start.at <= conn->stash.now - QUICLY_DELIVERY_RATE_SAMPLE_PERIOD) { + conn->egress.delivery_rate.samples[conn->egress.delivery_rate.next_sample_index] = + (struct st_quicly_delivery_rate_sample_t){ + .elapsed = (uint32_t)(conn->stash.now - conn->egress.delivery_rate.next_sample_start.at), + .bytes_acked = + (uint32_t)(conn->super.stats.num_bytes.ack_received - conn->egress.delivery_rate.next_sample_start.bytes_acked), + }; + if (++conn->egress.delivery_rate.next_sample_index >= PTLS_ELEMENTSOF(conn->egress.delivery_rate.samples)) + conn->egress.delivery_rate.next_sample_index = 0; } /* Update loss detection engine on ack. The function uses ack_delay only when the largest_newly_acked is also the largest acked From 0f74ae978a52a25f845ec79a821d418c516d1d88 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 31 Aug 2021 18:05:48 +0900 Subject: [PATCH 148/361] no longer use fp --- lib/quicly.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 662f7cfa1..fd3bcd574 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -21,7 +21,6 @@ */ #include #include -#include #include #include #include From e99d5ae69af404b4c19b0219b97e26c0be039865 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 31 Aug 2021 19:30:01 +0900 Subject: [PATCH 149/361] start collecting samples only after starting to receive ACKs that were sent in the current CWND-limited phase --- lib/quicly.c | 76 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 17 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index fd3bcd574..674e93b27 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -364,14 +364,28 @@ struct st_quicly_conn_t { size_t count; } datagram_frame_payloads; /** - * + * delivery rate estimator */ struct { + /** + * ring buffer retaining 10 most recent samples + */ struct st_quicly_delivery_rate_sample_t { uint32_t elapsed; uint32_t bytes_acked; } samples[10]; + /** + * next write slot + */ size_t next_sample_index; + /** + * packet number from which the estimator should be run + */ + uint64_t pn_cwnd_limited_from; + /** + * When running, retains the start of the sampling period as well as the value of `stats.num_bytes.ack_received`. When + * not running, at is set to INT64_MAX. + */ struct { int64_t at; uint64_t bytes_acked; @@ -1291,6 +1305,12 @@ void quicly_get_max_data(quicly_conn_t *conn, uint64_t *send_permitted, uint64_t *consumed = conn->ingress.max_data.bytes_consumed; } +static void stop_delivery_rate_sampling(quicly_conn_t *conn) +{ + conn->egress.delivery_rate.pn_cwnd_limited_from = UINT64_MAX; + conn->egress.delivery_rate.next_sample_start.at = INT64_MAX; +} + static void update_idle_timeout(quicly_conn_t *conn, int is_in_receive) { if (!is_in_receive && !conn->idle_timeout.should_rearm_on_send) @@ -1350,8 +1370,9 @@ static void setup_next_send(quicly_conn_t *conn) update_send_alarm(conn, can_send_stream_data, 0); + /* When the flow becomes application-limited due to receiving some information, stop collecting delivery rate samples. */ if (!can_send_stream_data) - conn->egress.delivery_rate.next_sample_start.at = INT64_MAX; + stop_delivery_rate_sampling(conn); } static int create_handshake_flow(quicly_conn_t *conn, size_t epoch) @@ -2202,6 +2223,7 @@ static quicly_conn_t *create_connection(quicly_context_t *ctx, uint32_t protocol *ptls_get_data_ptr(tls) = conn; + stop_delivery_rate_sampling(conn); update_open_count(conn->super.ctx, 1); return conn; @@ -3089,6 +3111,10 @@ struct st_quicly_send_context_t { * address at which payload starts */ uint8_t *dst_payload_from; + /** + * first packet number to be used within the lifetime of this send context + */ + uint64_t first_packet_number; }; static int commit_send_packet(quicly_conn_t *conn, quicly_send_context_t *s, int coalesced) @@ -4507,18 +4533,18 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) commit_send_packet(conn, s, 0); } if (ret == 0) { + /* update timers, start / stop delivery rate estimator */ if (conn->application == NULL || conn->application->super.unacked_count == 0) conn->egress.send_ack_at = INT64_MAX; /* we have sent ACKs for every epoch (or before address validation) */ int can_send_stream_data = scheduler_can_send(conn); update_send_alarm(conn, can_send_stream_data, 1); if (can_send_stream_data && (s->num_datagrams == s->max_datagrams || conn->egress.loss.sentmap.bytes_in_flight >= conn->egress.cc.cwnd)) { - if (conn->egress.delivery_rate.next_sample_start.at == INT64_MAX) { - conn->egress.delivery_rate.next_sample_start.at = conn->stash.now; - conn->egress.delivery_rate.next_sample_start.bytes_acked = conn->super.stats.num_bytes.ack_received; - } + /* as the flow is CWND-limited, start delivery rate estimator */ + if (conn->egress.delivery_rate.pn_cwnd_limited_from == UINT64_MAX) + conn->egress.delivery_rate.pn_cwnd_limited_from = s->first_packet_number; } else { - conn->egress.delivery_rate.next_sample_start.at = INT64_MAX; + stop_delivery_rate_sampling(conn); } if (s->num_datagrams != 0) update_idle_timeout(conn, 0); @@ -4548,7 +4574,11 @@ int quicly_set_cc(quicly_conn_t *conn, quicly_cc_type_t *cc) int quicly_send(quicly_conn_t *conn, quicly_address_t *dest, quicly_address_t *src, struct iovec *datagrams, size_t *num_datagrams, void *buf, size_t bufsize) { - quicly_send_context_t s = {{NULL, -1}, {}, datagrams, *num_datagrams, 0, {buf, (uint8_t *)buf + bufsize}}; + quicly_send_context_t s = {.current = {.first_byte = -1}, + .datagrams = datagrams, + .max_datagrams = *num_datagrams, + .payload_buf = {.datagram = buf, .end = (uint8_t *)buf + bufsize}, + .first_packet_number = conn->egress.packet_number}; int ret; lock_now(conn, 0); @@ -4960,15 +4990,27 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload QUICLY_PROBE(ACK_DELAY_RECEIVED, conn, conn->stash.now, frame.ack_delay); /* update delivery rate estimator */ - if (conn->egress.delivery_rate.next_sample_start.at <= conn->stash.now - QUICLY_DELIVERY_RATE_SAMPLE_PERIOD) { - conn->egress.delivery_rate.samples[conn->egress.delivery_rate.next_sample_index] = - (struct st_quicly_delivery_rate_sample_t){ - .elapsed = (uint32_t)(conn->stash.now - conn->egress.delivery_rate.next_sample_start.at), - .bytes_acked = - (uint32_t)(conn->super.stats.num_bytes.ack_received - conn->egress.delivery_rate.next_sample_start.bytes_acked), - }; - if (++conn->egress.delivery_rate.next_sample_index >= PTLS_ELEMENTSOF(conn->egress.delivery_rate.samples)) - conn->egress.delivery_rate.next_sample_index = 0; + if (conn->egress.delivery_rate.pn_cwnd_limited_from <= largest_newly_acked.pn) { +#define START_SAMPLING() \ + do { \ + conn->egress.delivery_rate.next_sample_start.at = conn->stash.now; \ + conn->egress.delivery_rate.next_sample_start.bytes_acked = conn->super.stats.num_bytes.ack_received; \ + } while (0) + if (conn->egress.delivery_rate.next_sample_start.at <= conn->stash.now - QUICLY_DELIVERY_RATE_SAMPLE_PERIOD) { + /* Enough time has elapsed since the start of the next sample. Record it. */ + conn->egress.delivery_rate.samples[conn->egress.delivery_rate.next_sample_index] = + (struct st_quicly_delivery_rate_sample_t){ + .elapsed = (uint32_t)(conn->stash.now - conn->egress.delivery_rate.next_sample_start.at), + .bytes_acked = (uint32_t)(conn->super.stats.num_bytes.ack_received - + conn->egress.delivery_rate.next_sample_start.bytes_acked), + }; + if (++conn->egress.delivery_rate.next_sample_index >= PTLS_ELEMENTSOF(conn->egress.delivery_rate.samples)) + conn->egress.delivery_rate.next_sample_index = 0; + START_SAMPLING(); + } else if (conn->egress.delivery_rate.next_sample_start.at == INT64_MAX) { + START_SAMPLING(); + } +#undef START_SAMPLING } /* Update loss detection engine on ack. The function uses ack_delay only when the largest_newly_acked is also the largest acked From 2c11d69083c0dba5b9de5c4d2d547b60421124cb Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 1 Sep 2021 13:58:20 +0900 Subject: [PATCH 150/361] add doc-comment explaining the size --- include/quicly/sentmap.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/quicly/sentmap.h b/include/quicly/sentmap.h index bf022bbaa..2aea9cb84 100644 --- a/include/quicly/sentmap.h +++ b/include/quicly/sentmap.h @@ -96,6 +96,11 @@ struct st_quicly_sent_ack_additional_t { uint8_t length; }; +/** + * Describes what is inside a packet or frame being sent. Within the sentmap, each packet-level entry (identified by .acked == + * quicly_sentmap__type_packet) is followed by a number of frame-level entries. Size of `quicly_sent_t` is kept as 256 bits (64-bit + * * 4). + */ struct st_quicly_sent_t { quicly_sent_acked_cb acked; union { From 31100b1fadafc621d31fec9efc31cf38eefa3481 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 1 Sep 2021 17:37:20 +0900 Subject: [PATCH 151/361] extract implementation, add unit tests --- CMakeLists.txt | 2 + include/quicly/delivery-rate.h | 107 +++++++++++++++++++++ lib/delivery-rate.c | 158 +++++++++++++++++++++++++++++++ lib/quicly.c | 117 ++--------------------- quicly.xcodeproj/project.pbxproj | 16 +++- t/delivery-rate.c | 113 ++++++++++++++++++++++ t/test.c | 1 + t/test.h | 1 + 8 files changed, 407 insertions(+), 108 deletions(-) create mode 100644 include/quicly/delivery-rate.h create mode 100644 lib/delivery-rate.c create mode 100644 t/delivery-rate.c diff --git a/CMakeLists.txt b/CMakeLists.txt index a2ed00ec0..82e79c4b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,7 @@ SET(QUICLY_LIBRARY_FILES lib/cc-cubic.c lib/cc-pico.c lib/defaults.c + lib/delivery-rate.c lib/local_cid.c lib/loss.c lib/quicly.c @@ -67,6 +68,7 @@ SET(QUICLY_LIBRARY_FILES SET(UNITTEST_SOURCE_FILES deps/picotest/picotest.c + t/delivery-rate.c t/frame.c t/local_cid.c t/loss.c diff --git a/include/quicly/delivery-rate.h b/include/quicly/delivery-rate.h new file mode 100644 index 000000000..d3c642cbf --- /dev/null +++ b/include/quicly/delivery-rate.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2021 Fastly, Kazuho Oku + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef quicly_delivery_rate_h +#define quicly_delivery_rate_h + +#include +#include "quicly/ranges.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef QUICLY_DELIVERY_RATE_SAMPLE_PERIOD +/** + * sampling period of delivery rate, in milliseconds + */ +#define QUICLY_DELIVERY_RATE_SAMPLE_PERIOD 50 +#endif + +#ifndef QUICLY_DELIVERY_RATE_SAMPLE_COUNT +/** + * number of samples to retain (and to calculate average from) + */ +#define QUICLY_DELIVERY_RATE_SAMPLE_COUNT 10 +#endif + +struct st_quicly_delivery_rate_sample_t { + uint32_t elapsed; + uint32_t bytes_acked; +}; + +/** + * State used for estimating the delivery rate. + */ +typedef struct st_quicly_delivery_rate_t { + /** + * ring buffer retaining 10 most recent samples + */ + struct { + struct st_quicly_delivery_rate_sample_t entries[QUICLY_DELIVERY_RATE_SAMPLE_COUNT]; + size_t slot; + } past_samples; + /** + * packet number range within with the flow has been CWND-limited + */ + quicly_range_t pn_cwnd_limited; + /** + * When running, retains the start of the sampling period as well as the value of `stats.num_bytes.ack_received`. When + * not running, at is set to INT64_MAX. + */ + struct { + struct { + int64_t at; + uint64_t bytes_acked; + } start; + struct st_quicly_delivery_rate_sample_t sample; + } current; +} quicly_delivery_rate_t; + +/** + * + */ +void quicly_delivery_rate_init(quicly_delivery_rate_t *dr); +/** + * Notifies the estimator that the flow is CWND-limited at the point of sending packets *starting* from packet number `pn`. + */ +void quicly_delivery_rate_in_cwnd_limited(quicly_delivery_rate_t *dr, uint64_t pn); +/** + * Notifies that the estimator that the flow is not CWND-limited when the packet number of the next packet will be `pn`. + */ +void quicly_delivery_rate_not_cwnd_limited(quicly_delivery_rate_t *dr, uint64_t pn); +/** + * Given three values, update the estimation. + * @param bytes_acked total number of bytes being acked from the beginning of the connection; i.e., + * `quicly_stats_t::num_bytes.ack_received` + */ +void quicly_delivery_rate_on_ack(quicly_delivery_rate_t *dr, int64_t now, uint64_t bytes_acked, uint64_t pn); +/** + * Returns three indicators of the delivery rate estimate + */ +void quicly_delivery_rate_report(quicly_delivery_rate_t *dr, uint64_t *latest, uint64_t *smoothed, uint64_t *variance); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/delivery-rate.c b/lib/delivery-rate.c new file mode 100644 index 000000000..58b352fe6 --- /dev/null +++ b/lib/delivery-rate.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2021 Fastly, Kazuho Oku + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "picotls.h" +#include "quicly/delivery-rate.h" + +static void start_sampling(quicly_delivery_rate_t *dr, int64_t now, uint64_t bytes_acked) +{ + dr->current.start.at = now; + dr->current.start.bytes_acked = bytes_acked; +} + +static void commit_sample(quicly_delivery_rate_t *dr) +{ + dr->past_samples.entries[dr->past_samples.slot] = dr->current.sample; + ++dr->past_samples.slot; + if (dr->past_samples.slot >= PTLS_ELEMENTSOF(dr->past_samples.entries)) + dr->past_samples.slot = 0; + + dr->current.start.at = INT64_MAX; + dr->current.sample = (struct st_quicly_delivery_rate_sample_t){}; +} + +void quicly_delivery_rate_init(quicly_delivery_rate_t *dr) +{ + *dr = (quicly_delivery_rate_t){ + .pn_cwnd_limited = {.start = UINT64_MAX, .end = UINT64_MAX}, + .current = {.start = {.at = INT64_MAX}}, + }; +} + +void quicly_delivery_rate_in_cwnd_limited(quicly_delivery_rate_t *dr, uint64_t pn) +{ + /* bail out if already in cwnd-limited phase */ + if (dr->pn_cwnd_limited.start != UINT64_MAX && dr->pn_cwnd_limited.end == UINT64_MAX) + return; + + /* if the estimator was waiting for the end of the previous phase, and if a valid partial sample exists, commit it now */ + if (dr->pn_cwnd_limited.end != UINT64_MAX && dr->current.sample.elapsed != 0) + commit_sample(dr); + + /* begin new cwnd-limited phase */ + dr->pn_cwnd_limited = (quicly_range_t){.start = pn, .end = UINT64_MAX}; +} + +void quicly_delivery_rate_not_cwnd_limited(quicly_delivery_rate_t *dr, uint64_t pn) +{ + if (dr->pn_cwnd_limited.start != UINT64_MAX && dr->pn_cwnd_limited.end == UINT64_MAX) + dr->pn_cwnd_limited.end = pn; +} + +void quicly_delivery_rate_on_ack(quicly_delivery_rate_t *dr, int64_t now, uint64_t bytes_acked, uint64_t pn) +{ + if (dr->pn_cwnd_limited.start <= pn && pn < dr->pn_cwnd_limited.end) { + /* At the moment, the flow is CWND-limited. Either start the timer or update. */ + if (dr->current.start.at == INT64_MAX) { + start_sampling(dr, now, bytes_acked); + } else { + dr->current.sample = (struct st_quicly_delivery_rate_sample_t){ + .elapsed = (uint32_t)(now - dr->current.start.at), + .bytes_acked = (uint32_t)(bytes_acked - dr->current.start.bytes_acked), + }; + if (dr->current.sample.elapsed >= QUICLY_DELIVERY_RATE_SAMPLE_PERIOD) { + commit_sample(dr); + start_sampling(dr, now, bytes_acked); + } + } + } else if (dr->pn_cwnd_limited.end <= pn) { + /* We have exitted CWND-limited state. Save current value, if any. */ + if (dr->current.start.at != INT64_MAX) { + if (dr->current.sample.elapsed != 0) + commit_sample(dr); + dr->pn_cwnd_limited = (quicly_range_t){.start = UINT64_MAX, .end = UINT64_MAX}; + dr->current.start.at = INT64_MAX; + } + } + +#undef START_SAMPLING +#undef ADVANCE_SLOT +} + +static uint64_t to_speed(uint64_t bytes_acked, uint32_t elapsed) +{ + return bytes_acked * 1000 / elapsed; +} + +void quicly_delivery_rate_report(quicly_delivery_rate_t *dr, uint64_t *latest, uint64_t *smoothed, uint64_t *variance) +{ + { /* Calculate latest, or return if there are no samples at all. `latest` being reported will be the most recent "full" sample + * if available, or else a partial sample. */ + const struct st_quicly_delivery_rate_sample_t *latest_sample = + &dr->past_samples + .entries[dr->past_samples.slot != 0 ? dr->past_samples.slot - 1 : PTLS_ELEMENTSOF(dr->past_samples.entries) - 1]; + if (latest_sample->elapsed == 0) { + latest_sample = &dr->current.sample; + if (latest_sample->elapsed == 0) { + *latest = *smoothed = *variance = 0; + return; + } + } + *latest = to_speed(latest_sample->bytes_acked, latest_sample->elapsed); + } + +#define FOREACH_SAMPLE(func) \ + do { \ + const struct st_quicly_delivery_rate_sample_t *sample; \ + for (size_t i = 0; i < PTLS_ELEMENTSOF(dr->past_samples.entries); ++i) { \ + if ((sample = &dr->past_samples.entries[i])->elapsed != 0) { \ + func \ + } \ + } \ + if ((sample = &dr->current.sample)->elapsed != 0) { \ + func \ + } \ + } while (0) + + { /* calculate average */ + uint64_t total_acked = 0; + uint32_t total_elapsed = 0; + FOREACH_SAMPLE({ + total_acked += sample->bytes_acked; + total_elapsed += sample->elapsed; + }); + *smoothed = to_speed(total_acked, total_elapsed); + } + + { /* calculate variance */ + uint64_t sum = 0; + size_t count = 0; + FOREACH_SAMPLE({ + uint64_t sample_speed = to_speed(sample->bytes_acked, sample->elapsed); + sum += (sample_speed - *smoothed) * (sample_speed - *smoothed); + ++count; + }); + *variance = sum / count; + } + +#undef FOREACH_SAMPLE +} diff --git a/lib/quicly.c b/lib/quicly.c index bdf72a8ae..ca7c4c02b 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -35,6 +35,7 @@ #include "quicly/frame.h" #include "quicly/streambuf.h" #include "quicly/cc.h" +#include "quicly/delivery-rate.h" #if QUICLY_USE_EMBEDDED_PROBES #include "embedded-probes.h" #elif QUICLY_USE_DTRACE @@ -74,20 +75,6 @@ */ #define QUICLY_NUM_ACK_BLOCKS_TO_INDUCE_ACKACK 8 -#ifndef QUICLY_DELIVERY_RATE_SAMPLE_PERIOD -/** - * sampling period of delivery rate, in milliseconds - */ -#define QUICLY_DELIVERY_RATE_SAMPLE_PERIOD 50 -#endif - -#ifndef QUICLY_DELIVERY_RATE_SAMPLE_COUNT -/** - * number of samples to retain (and to calculate average from) - */ -#define QUICLY_DELIVERY_RATE_SAMPLE_COUNT 10 -#endif - KHASH_MAP_INIT_INT64(quicly_stream_t, quicly_stream_t *) #if QUICLY_USE_TRACER @@ -366,31 +353,7 @@ struct st_quicly_conn_t { /** * delivery rate estimator */ - struct { - /** - * ring buffer retaining 10 most recent samples - */ - struct st_quicly_delivery_rate_sample_t { - uint32_t elapsed; - uint32_t bytes_acked; - } samples[10]; - /** - * next write slot - */ - size_t next_sample_index; - /** - * packet number from which the estimator should be run - */ - uint64_t pn_cwnd_limited_from; - /** - * When running, retains the start of the sampling period as well as the value of `stats.num_bytes.ack_received`. When - * not running, at is set to INT64_MAX. - */ - struct { - int64_t at; - uint64_t bytes_acked; - } next_sample_start; - } delivery_rate; + quicly_delivery_rate_t delivery_rate; } egress; /** * crypto data @@ -1251,40 +1214,8 @@ int quicly_get_stats(quicly_conn_t *conn, quicly_stats_t *stats) /* set or generate the non-pre-built stats fields here */ stats->rtt = conn->egress.loss.rtt; stats->cc = conn->egress.cc; - - /* delivery rate, calculate the numbers if we've got samples, otherwise set to zero */ - if (conn->egress.delivery_rate.samples[0].elapsed != 0) { - { /* calculate latest */ - struct st_quicly_delivery_rate_sample_t *latest = - &conn->egress.delivery_rate.samples[conn->egress.delivery_rate.next_sample_index != 0 - ? conn->egress.delivery_rate.next_sample_index - 1 - : PTLS_ELEMENTSOF(conn->egress.delivery_rate.samples) - 1]; - stats->delivery_rate.latest = (uint64_t)latest->bytes_acked * 1000 / latest->elapsed; - } - { /* calculate average */ - uint64_t total_acked = 0; - uint32_t total_elapsed = 0; - size_t i; - for (i = 0; - i < PTLS_ELEMENTSOF(conn->egress.delivery_rate.samples) && conn->egress.delivery_rate.samples[i].elapsed != 0; - ++i) { - total_acked += conn->egress.delivery_rate.samples[i].bytes_acked; - total_elapsed += conn->egress.delivery_rate.samples[i].elapsed; - } - stats->delivery_rate.smoothed = total_acked * 1000 / total_elapsed; - } - { /* calculate variance */ - uint64_t sum = 0; - size_t i; - for (i = 0; - i < PTLS_ELEMENTSOF(conn->egress.delivery_rate.samples) && conn->egress.delivery_rate.samples[i].elapsed != 0; - ++i) { - uint64_t sample = conn->egress.delivery_rate.samples[i].bytes_acked * (1000 / QUICLY_DELIVERY_RATE_SAMPLE_PERIOD); - sum += (sample - stats->delivery_rate.smoothed) * (sample - stats->delivery_rate.smoothed); - } - stats->delivery_rate.variance = sum / i; - } - } + quicly_delivery_rate_report(&conn->egress.delivery_rate, &stats->delivery_rate.latest, &stats->delivery_rate.smoothed, + &stats->delivery_rate.variance); return 0; } @@ -1305,12 +1236,6 @@ void quicly_get_max_data(quicly_conn_t *conn, uint64_t *send_permitted, uint64_t *consumed = conn->ingress.max_data.bytes_consumed; } -static void stop_delivery_rate_sampling(quicly_conn_t *conn) -{ - conn->egress.delivery_rate.pn_cwnd_limited_from = UINT64_MAX; - conn->egress.delivery_rate.next_sample_start.at = INT64_MAX; -} - static void update_idle_timeout(quicly_conn_t *conn, int is_in_receive) { if (!is_in_receive && !conn->idle_timeout.should_rearm_on_send) @@ -1372,7 +1297,7 @@ static void setup_next_send(quicly_conn_t *conn) /* When the flow becomes application-limited due to receiving some information, stop collecting delivery rate samples. */ if (!can_send_stream_data) - stop_delivery_rate_sampling(conn); + quicly_delivery_rate_not_cwnd_limited(&conn->egress.delivery_rate, conn->egress.packet_number); } static int create_handshake_flow(quicly_conn_t *conn, size_t epoch) @@ -2206,6 +2131,7 @@ static quicly_conn_t *create_connection(quicly_context_t *ctx, uint32_t protocol quicly_linklist_init(&conn->egress.pending_streams.blocked.uni); quicly_linklist_init(&conn->egress.pending_streams.blocked.bidi); quicly_linklist_init(&conn->egress.pending_streams.control); + quicly_delivery_rate_init(&conn->egress.delivery_rate); conn->crypto.tls = tls; if (handshake_properties != NULL) { assert(handshake_properties->additional_extensions == NULL); @@ -2223,7 +2149,6 @@ static quicly_conn_t *create_connection(quicly_context_t *ctx, uint32_t protocol *ptls_get_data_ptr(tls) = conn; - stop_delivery_rate_sampling(conn); update_open_count(conn->super.ctx, 1); return conn; @@ -4598,10 +4523,9 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) if (can_send_stream_data && (s->num_datagrams == s->max_datagrams || conn->egress.loss.sentmap.bytes_in_flight >= conn->egress.cc.cwnd)) { /* as the flow is CWND-limited, start delivery rate estimator */ - if (conn->egress.delivery_rate.pn_cwnd_limited_from == UINT64_MAX) - conn->egress.delivery_rate.pn_cwnd_limited_from = s->first_packet_number; + quicly_delivery_rate_in_cwnd_limited(&conn->egress.delivery_rate, s->first_packet_number); } else { - stop_delivery_rate_sampling(conn); + quicly_delivery_rate_not_cwnd_limited(&conn->egress.delivery_rate, conn->egress.packet_number); } if (s->num_datagrams != 0) update_idle_timeout(conn, 0); @@ -5046,29 +4970,8 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload QUICLY_PROBE(ACK_DELAY_RECEIVED, conn, conn->stash.now, frame.ack_delay); - /* update delivery rate estimator */ - if (conn->egress.delivery_rate.pn_cwnd_limited_from <= largest_newly_acked.pn) { -#define START_SAMPLING() \ - do { \ - conn->egress.delivery_rate.next_sample_start.at = conn->stash.now; \ - conn->egress.delivery_rate.next_sample_start.bytes_acked = conn->super.stats.num_bytes.ack_received; \ - } while (0) - if (conn->egress.delivery_rate.next_sample_start.at <= conn->stash.now - QUICLY_DELIVERY_RATE_SAMPLE_PERIOD) { - /* Enough time has elapsed since the start of the next sample. Record it. */ - conn->egress.delivery_rate.samples[conn->egress.delivery_rate.next_sample_index] = - (struct st_quicly_delivery_rate_sample_t){ - .elapsed = (uint32_t)(conn->stash.now - conn->egress.delivery_rate.next_sample_start.at), - .bytes_acked = (uint32_t)(conn->super.stats.num_bytes.ack_received - - conn->egress.delivery_rate.next_sample_start.bytes_acked), - }; - if (++conn->egress.delivery_rate.next_sample_index >= PTLS_ELEMENTSOF(conn->egress.delivery_rate.samples)) - conn->egress.delivery_rate.next_sample_index = 0; - START_SAMPLING(); - } else if (conn->egress.delivery_rate.next_sample_start.at == INT64_MAX) { - START_SAMPLING(); - } -#undef START_SAMPLING - } + quicly_delivery_rate_on_ack(&conn->egress.delivery_rate, conn->stash.now, conn->super.stats.num_bytes.ack_received, + largest_newly_acked.pn); /* Update loss detection engine on ack. The function uses ack_delay only when the largest_newly_acked is also the largest acked * so far. So, it does not matter if the ack_delay being passed in does not apply to the largest_newly_acked. */ diff --git a/quicly.xcodeproj/project.pbxproj b/quicly.xcodeproj/project.pbxproj index 2f7ac86d1..1492c1008 100644 --- a/quicly.xcodeproj/project.pbxproj +++ b/quicly.xcodeproj/project.pbxproj @@ -10,6 +10,10 @@ 082195082683498900E3EFCF /* cc-pico.c in Sources */ = {isa = PBXBuildFile; fileRef = 082195072683498900E3EFCF /* cc-pico.c */; }; 082195092683498900E3EFCF /* cc-pico.c in Sources */ = {isa = PBXBuildFile; fileRef = 082195072683498900E3EFCF /* cc-pico.c */; }; 0821950A2683498900E3EFCF /* cc-pico.c in Sources */ = {isa = PBXBuildFile; fileRef = 082195072683498900E3EFCF /* cc-pico.c */; }; + 0829878E26E03D4D0053638F /* delivery-rate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0829878D26E03D4D0053638F /* delivery-rate.c */; }; + 0829878F26E03D4D0053638F /* delivery-rate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0829878D26E03D4D0053638F /* delivery-rate.c */; }; + 0829879026E03D4D0053638F /* delivery-rate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0829878D26E03D4D0053638F /* delivery-rate.c */; }; + 0829879226E0A9DF0053638F /* delivery-rate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0829879126E0A9DF0053638F /* delivery-rate.c */; }; E904233D24AED0410072C5B7 /* loss.c in Sources */ = {isa = PBXBuildFile; fileRef = E904233C24AED0410072C5B7 /* loss.c */; }; E904233E24AED0410072C5B7 /* loss.c in Sources */ = {isa = PBXBuildFile; fileRef = E904233C24AED0410072C5B7 /* loss.c */; }; E904233F24AED0410072C5B7 /* loss.c in Sources */ = {isa = PBXBuildFile; fileRef = E904233C24AED0410072C5B7 /* loss.c */; }; @@ -145,6 +149,9 @@ /* Begin PBXFileReference section */ 082195072683498900E3EFCF /* cc-pico.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "cc-pico.c"; sourceTree = ""; }; + 0829878C26DF775B0053638F /* delivery-rate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "delivery-rate.h"; sourceTree = ""; }; + 0829878D26E03D4D0053638F /* delivery-rate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "delivery-rate.c"; sourceTree = ""; }; + 0829879126E0A9DF0053638F /* delivery-rate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "delivery-rate.c"; sourceTree = ""; }; E904233C24AED0410072C5B7 /* loss.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = loss.c; sourceTree = ""; }; E904234024AEFB980072C5B7 /* loss.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = loss.c; sourceTree = ""; }; E9056C071F56965300E2B96C /* linklist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = linklist.h; sourceTree = ""; }; @@ -332,6 +339,7 @@ E98041C522383C62008B9745 /* cc-reno.c */, E9736527246FD3AC0039AA49 /* remote_cid.c */, E98042352244A5D7008B9745 /* defaults.c */, + 0829878D26E03D4D0053638F /* delivery-rate.c */, E99F8C251F4E9EBF00C26B3D /* frame.c */, E9736529246FD3AC0039AA49 /* local_cid.c */, E904233C24AED0410072C5B7 /* loss.c */, @@ -414,14 +422,15 @@ E9CC44121EC1926000DC7D3E /* t */ = { isa = PBXGroup; children = ( + 0829879126E0A9DF0053638F /* delivery-rate.c */, E98884C221E3F23A0060F010 /* e2e.t */, - E9736534246FD3DA0039AA49 /* remote_cid.c */, E99F8C281F4EAEF800C26B3D /* frame.c */, E9736533246FD3DA0039AA49 /* local_cid.c */, E904234024AEFB980072C5B7 /* loss.c */, E920D22F1F49EE0B00799777 /* lossy.c */, E99B75E61F5CF96900CF503E /* maxsender.c */, E9F6A4291F3C3B7B0083F0B2 /* ranges.c */, + E9736534246FD3DA0039AA49 /* remote_cid.c */, E9736535246FD3DA0039AA49 /* retire_cid.c */, E920D22D1F4981E500799777 /* sentmap.c */, E920D2241F49412900799777 /* simple.c */, @@ -450,6 +459,7 @@ E920D2201F44047C00799777 /* constants.h */, E9736521246FD3890039AA49 /* remote_cid.h */, E98042332244A539008B9745 /* defaults.h */, + 0829878C26DF775B0053638F /* delivery-rate.h */, E99F8C231F4E863200C26B3D /* frame.h */, E9736520246FD3880039AA49 /* local_cid.h */, E9056C071F56965300E2B96C /* linklist.h */, @@ -711,6 +721,7 @@ E920D22B1F49533800799777 /* sentmap.c in Sources */, E9D3CCCF21D22F4300516202 /* streambuf.c in Sources */, E973652C246FD3AC0039AA49 /* local_cid.c in Sources */, + 0829878E26E03D4D0053638F /* delivery-rate.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -733,6 +744,7 @@ E9B43E12246943D300824E51 /* fusion.c in Sources */, E941428E23B0B845002D3CE0 /* defaults.c in Sources */, E941429023B0B861002D3CE0 /* streambuf.c in Sources */, + 0829878F26E03D4D0053638F /* delivery-rate.c in Sources */, E93E546A1F663851001C50FE /* pembase64.c in Sources */, E98042282239531A008B9745 /* cli.c in Sources */, E941429223B0B870002D3CE0 /* sendstate.c in Sources */, @@ -758,6 +770,7 @@ E9736537246FD3DA0039AA49 /* remote_cid.c in Sources */, E99F8C291F4EAEF800C26B3D /* frame.c in Sources */, E98041C722383C7A008B9745 /* cc-reno.c in Sources */, + 0829879026E03D4D0053638F /* delivery-rate.c in Sources */, E9D31DD1232DEDB400ACD5EC /* quicly-probes.d in Sources */, E9736530246FD3B50039AA49 /* local_cid.c in Sources */, E920D22C1F49533800799777 /* sentmap.c in Sources */, @@ -786,6 +799,7 @@ E98042372244A5D7008B9745 /* defaults.c in Sources */, E99F8C271F4E9F5D00C26B3D /* frame.c in Sources */, E9736536246FD3DA0039AA49 /* local_cid.c in Sources */, + 0829879226E0A9DF0053638F /* delivery-rate.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/t/delivery-rate.c b/t/delivery-rate.c new file mode 100644 index 000000000..1c3ae38d1 --- /dev/null +++ b/t/delivery-rate.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2021 Fastly, Kazuho Oku + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "quicly/delivery-rate.h" +#include "test.h" + +#define CHECK_REPORT(el, es, ev) \ + do { \ + uint64_t latest, smoothed, variance; \ + quicly_delivery_rate_report(&dr, &latest, &smoothed, &variance); \ + ok(latest == el); \ + ok(smoothed == es); \ + ok(variance == ev); \ + } while (0) + +static void test_basic(void) +{ + quicly_delivery_rate_t dr; + + quicly_delivery_rate_init(&dr); + CHECK_REPORT(0, 0, 0); + + uint64_t pn = 0, bytes_acked = 0; + int64_t now = 1000; + + /* send 1KB packet every 20ms, in CWND-limited state */ + for (; pn < 100; ++pn) { + quicly_delivery_rate_in_cwnd_limited(&dr, pn); + bytes_acked += 1000; + now += 20; + quicly_delivery_rate_on_ack(&dr, now, bytes_acked, pn); + } + CHECK_REPORT(50000, 50000, 0); + + /* send at a slow rate, in application-limited state */ + for (; pn < 200; ++pn) { + quicly_delivery_rate_not_cwnd_limited(&dr, pn); + bytes_acked += 10; + now += 20; + quicly_delivery_rate_on_ack(&dr, now, bytes_acked, pn); + } + CHECK_REPORT(50000, 50000, 0); + + /* send 2KB packet every 20ms, in CWND-limited state */ + for (; pn < 300; ++pn) { + quicly_delivery_rate_in_cwnd_limited(&dr, pn); + bytes_acked += 2000; + now += 20; + quicly_delivery_rate_on_ack(&dr, now, bytes_acked, pn); + } + CHECK_REPORT(100000, 100000, 0); +} + +static void test_burst(void) +{ + quicly_delivery_rate_t dr; + + quicly_delivery_rate_init(&dr); + CHECK_REPORT(0, 0, 0); + + /* send 10 packet burst (pn=1 to 10) */ + quicly_delivery_rate_in_cwnd_limited(&dr, 1); + quicly_delivery_rate_not_cwnd_limited(&dr, 11); + + /* ack every 2 packets up to pn=9, every 20ms */ + uint64_t pn = 0, bytes_acked = 0; + int64_t now = 1000; + while (1) { + pn += 2; + bytes_acked += 2000; + now += 20; + quicly_delivery_rate_on_ack(&dr, now, bytes_acked, pn); + if (pn == 10) + break; + } + CHECK_REPORT(100000, 100000, 0); + + ok(dr.current.sample.elapsed != 0); /* we have an active sample ... */ + + pn += 1; + bytes_acked += 50; + now += 20; + quicly_delivery_rate_on_ack(&dr, now, bytes_acked, pn); + + ok(dr.current.sample.elapsed == 0); /* that gets committed by the next pn out of the window */ + + CHECK_REPORT(100000, 100000, 0); +} + +void test_delivery_rate(void) +{ + subtest("basic", test_basic); + subtest("burst", test_burst); +} diff --git a/t/test.c b/t/test.c index a89c3bb64..6a6bbf671 100644 --- a/t/test.c +++ b/t/test.c @@ -625,6 +625,7 @@ int main(int argc, char **argv) quicly_amend_ptls_context(quic_ctx.tls); + subtest("delivery-rate", test_delivery_rate); subtest("next-packet-number", test_next_packet_number); subtest("address-token-codec", test_address_token_codec); subtest("ranges", test_ranges); diff --git a/t/test.h b/t/test.h index 8d50be7a5..728563069 100644 --- a/t/test.h +++ b/t/test.h @@ -49,6 +49,7 @@ size_t transmit(quicly_conn_t *src, quicly_conn_t *dst); int max_data_is_equal(quicly_conn_t *client, quicly_conn_t *server); void test_ranges(void); +void test_delivery_rate(void); void test_frame(void); void test_maxsender(void); void test_sentmap(void); From 3e40e1171488695dcb7be362aa9fc021e341eadc Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 2 Sep 2021 17:13:51 +0900 Subject: [PATCH 152/361] remove unneeded undefs --- lib/delivery-rate.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/delivery-rate.c b/lib/delivery-rate.c index 58b352fe6..bd022bdaa 100644 --- a/lib/delivery-rate.c +++ b/lib/delivery-rate.c @@ -93,9 +93,6 @@ void quicly_delivery_rate_on_ack(quicly_delivery_rate_t *dr, int64_t now, uint64 dr->current.start.at = INT64_MAX; } } - -#undef START_SAMPLING -#undef ADVANCE_SLOT } static uint64_t to_speed(uint64_t bytes_acked, uint32_t elapsed) From 5fca40c099e3538e31a0e75ff5aedb0268452f24 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 2 Sep 2021 17:23:22 +0900 Subject: [PATCH 153/361] point to the latest, rather than the next --- include/quicly/delivery-rate.h | 6 +++--- lib/delivery-rate.c | 13 ++++++------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/include/quicly/delivery-rate.h b/include/quicly/delivery-rate.h index d3c642cbf..584647bbd 100644 --- a/include/quicly/delivery-rate.h +++ b/include/quicly/delivery-rate.h @@ -54,14 +54,14 @@ struct st_quicly_delivery_rate_sample_t { */ typedef struct st_quicly_delivery_rate_t { /** - * ring buffer retaining 10 most recent samples + * ring buffer retaining the most recent samples */ struct { struct st_quicly_delivery_rate_sample_t entries[QUICLY_DELIVERY_RATE_SAMPLE_COUNT]; - size_t slot; + size_t latest; } past_samples; /** - * packet number range within with the flow has been CWND-limited + * packet number range within which the flow has been CWND-limited */ quicly_range_t pn_cwnd_limited; /** diff --git a/lib/delivery-rate.c b/lib/delivery-rate.c index bd022bdaa..e2ead2a3e 100644 --- a/lib/delivery-rate.c +++ b/lib/delivery-rate.c @@ -31,10 +31,10 @@ static void start_sampling(quicly_delivery_rate_t *dr, int64_t now, uint64_t byt static void commit_sample(quicly_delivery_rate_t *dr) { - dr->past_samples.entries[dr->past_samples.slot] = dr->current.sample; - ++dr->past_samples.slot; - if (dr->past_samples.slot >= PTLS_ELEMENTSOF(dr->past_samples.entries)) - dr->past_samples.slot = 0; + ++dr->past_samples.latest; + if (dr->past_samples.latest >= PTLS_ELEMENTSOF(dr->past_samples.entries)) + dr->past_samples.latest = 0; + dr->past_samples.entries[dr->past_samples.latest] = dr->current.sample; dr->current.start.at = INT64_MAX; dr->current.sample = (struct st_quicly_delivery_rate_sample_t){}; @@ -43,6 +43,7 @@ static void commit_sample(quicly_delivery_rate_t *dr) void quicly_delivery_rate_init(quicly_delivery_rate_t *dr) { *dr = (quicly_delivery_rate_t){ + .past_samples = {.latest = PTLS_ELEMENTSOF(dr->past_samples.entries) - 1}, .pn_cwnd_limited = {.start = UINT64_MAX, .end = UINT64_MAX}, .current = {.start = {.at = INT64_MAX}}, }; @@ -104,9 +105,7 @@ void quicly_delivery_rate_report(quicly_delivery_rate_t *dr, uint64_t *latest, u { { /* Calculate latest, or return if there are no samples at all. `latest` being reported will be the most recent "full" sample * if available, or else a partial sample. */ - const struct st_quicly_delivery_rate_sample_t *latest_sample = - &dr->past_samples - .entries[dr->past_samples.slot != 0 ? dr->past_samples.slot - 1 : PTLS_ELEMENTSOF(dr->past_samples.entries) - 1]; + const struct st_quicly_delivery_rate_sample_t *latest_sample = &dr->past_samples.entries[dr->past_samples.latest]; if (latest_sample->elapsed == 0) { latest_sample = &dr->current.sample; if (latest_sample->elapsed == 0) { From abb6c200a606bc15902cf80c3e8c73b993e38476 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 2 Sep 2021 17:36:49 +0900 Subject: [PATCH 154/361] update comment --- include/quicly/delivery-rate.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/quicly/delivery-rate.h b/include/quicly/delivery-rate.h index 584647bbd..5c6b8b48a 100644 --- a/include/quicly/delivery-rate.h +++ b/include/quicly/delivery-rate.h @@ -65,8 +65,8 @@ typedef struct st_quicly_delivery_rate_t { */ quicly_range_t pn_cwnd_limited; /** - * When running, retains the start of the sampling period as well as the value of `stats.num_bytes.ack_received`. When - * not running, at is set to INT64_MAX. + * Current sample being corrected, if any. When running, `start.at` and `start.bytes_acked` retains the values at the start of + * the current sampling period. When not, `start.at` is set to INT64_MAX, and `sample` is zero-cleared. */ struct { struct { From 058623fa31e3aaf12262fc29de0314c79906cfba Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 2 Sep 2021 17:37:57 +0900 Subject: [PATCH 155/361] typo --- include/quicly/delivery-rate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/quicly/delivery-rate.h b/include/quicly/delivery-rate.h index 5c6b8b48a..89a9dbcfe 100644 --- a/include/quicly/delivery-rate.h +++ b/include/quicly/delivery-rate.h @@ -65,7 +65,7 @@ typedef struct st_quicly_delivery_rate_t { */ quicly_range_t pn_cwnd_limited; /** - * Current sample being corrected, if any. When running, `start.at` and `start.bytes_acked` retains the values at the start of + * Current sample being collected, if any. When running, `start.at` and `start.bytes_acked` retains the values at the start of * the current sampling period. When not, `start.at` is set to INT64_MAX, and `sample` is zero-cleared. */ struct { From bc6923eecce4fbaf8e9dee382695c84b3e7f8626 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 3 Sep 2021 11:41:51 +0900 Subject: [PATCH 156/361] use terms "rate", "ratemeter" --- include/quicly/delivery-rate.h | 20 ++++++++++---------- lib/delivery-rate.c | 24 ++++++++++++------------ lib/quicly.c | 18 +++++++++--------- t/delivery-rate.c | 34 +++++++++++++++++----------------- 4 files changed, 48 insertions(+), 48 deletions(-) diff --git a/include/quicly/delivery-rate.h b/include/quicly/delivery-rate.h index 89a9dbcfe..431630b1f 100644 --- a/include/quicly/delivery-rate.h +++ b/include/quicly/delivery-rate.h @@ -44,7 +44,7 @@ extern "C" { #define QUICLY_DELIVERY_RATE_SAMPLE_COUNT 10 #endif -struct st_quicly_delivery_rate_sample_t { +struct st_quicly_rate_sample_t { uint32_t elapsed; uint32_t bytes_acked; }; @@ -52,12 +52,12 @@ struct st_quicly_delivery_rate_sample_t { /** * State used for estimating the delivery rate. */ -typedef struct st_quicly_delivery_rate_t { +typedef struct st_quicly_ratemeter_t { /** * ring buffer retaining the most recent samples */ struct { - struct st_quicly_delivery_rate_sample_t entries[QUICLY_DELIVERY_RATE_SAMPLE_COUNT]; + struct st_quicly_rate_sample_t entries[QUICLY_DELIVERY_RATE_SAMPLE_COUNT]; size_t latest; } past_samples; /** @@ -73,32 +73,32 @@ typedef struct st_quicly_delivery_rate_t { int64_t at; uint64_t bytes_acked; } start; - struct st_quicly_delivery_rate_sample_t sample; + struct st_quicly_rate_sample_t sample; } current; -} quicly_delivery_rate_t; +} quicly_ratemeter_t; /** * */ -void quicly_delivery_rate_init(quicly_delivery_rate_t *dr); +void quicly_ratemeter_init(quicly_ratemeter_t *dr); /** * Notifies the estimator that the flow is CWND-limited at the point of sending packets *starting* from packet number `pn`. */ -void quicly_delivery_rate_in_cwnd_limited(quicly_delivery_rate_t *dr, uint64_t pn); +void quicly_ratemeter_in_cwnd_limited(quicly_ratemeter_t *dr, uint64_t pn); /** * Notifies that the estimator that the flow is not CWND-limited when the packet number of the next packet will be `pn`. */ -void quicly_delivery_rate_not_cwnd_limited(quicly_delivery_rate_t *dr, uint64_t pn); +void quicly_ratemeter_not_cwnd_limited(quicly_ratemeter_t *dr, uint64_t pn); /** * Given three values, update the estimation. * @param bytes_acked total number of bytes being acked from the beginning of the connection; i.e., * `quicly_stats_t::num_bytes.ack_received` */ -void quicly_delivery_rate_on_ack(quicly_delivery_rate_t *dr, int64_t now, uint64_t bytes_acked, uint64_t pn); +void quicly_ratemeter_on_ack(quicly_ratemeter_t *dr, int64_t now, uint64_t bytes_acked, uint64_t pn); /** * Returns three indicators of the delivery rate estimate */ -void quicly_delivery_rate_report(quicly_delivery_rate_t *dr, uint64_t *latest, uint64_t *smoothed, uint64_t *variance); +void quicly_ratemeter_report(quicly_ratemeter_t *dr, uint64_t *latest, uint64_t *smoothed, uint64_t *variance); #ifdef __cplusplus } diff --git a/lib/delivery-rate.c b/lib/delivery-rate.c index e2ead2a3e..171ad52c6 100644 --- a/lib/delivery-rate.c +++ b/lib/delivery-rate.c @@ -23,13 +23,13 @@ #include "picotls.h" #include "quicly/delivery-rate.h" -static void start_sampling(quicly_delivery_rate_t *dr, int64_t now, uint64_t bytes_acked) +static void start_sampling(quicly_ratemeter_t *dr, int64_t now, uint64_t bytes_acked) { dr->current.start.at = now; dr->current.start.bytes_acked = bytes_acked; } -static void commit_sample(quicly_delivery_rate_t *dr) +static void commit_sample(quicly_ratemeter_t *dr) { ++dr->past_samples.latest; if (dr->past_samples.latest >= PTLS_ELEMENTSOF(dr->past_samples.entries)) @@ -37,19 +37,19 @@ static void commit_sample(quicly_delivery_rate_t *dr) dr->past_samples.entries[dr->past_samples.latest] = dr->current.sample; dr->current.start.at = INT64_MAX; - dr->current.sample = (struct st_quicly_delivery_rate_sample_t){}; + dr->current.sample = (struct st_quicly_rate_sample_t){}; } -void quicly_delivery_rate_init(quicly_delivery_rate_t *dr) +void quicly_ratemeter_init(quicly_ratemeter_t *dr) { - *dr = (quicly_delivery_rate_t){ + *dr = (quicly_ratemeter_t){ .past_samples = {.latest = PTLS_ELEMENTSOF(dr->past_samples.entries) - 1}, .pn_cwnd_limited = {.start = UINT64_MAX, .end = UINT64_MAX}, .current = {.start = {.at = INT64_MAX}}, }; } -void quicly_delivery_rate_in_cwnd_limited(quicly_delivery_rate_t *dr, uint64_t pn) +void quicly_ratemeter_in_cwnd_limited(quicly_ratemeter_t *dr, uint64_t pn) { /* bail out if already in cwnd-limited phase */ if (dr->pn_cwnd_limited.start != UINT64_MAX && dr->pn_cwnd_limited.end == UINT64_MAX) @@ -63,20 +63,20 @@ void quicly_delivery_rate_in_cwnd_limited(quicly_delivery_rate_t *dr, uint64_t p dr->pn_cwnd_limited = (quicly_range_t){.start = pn, .end = UINT64_MAX}; } -void quicly_delivery_rate_not_cwnd_limited(quicly_delivery_rate_t *dr, uint64_t pn) +void quicly_ratemeter_not_cwnd_limited(quicly_ratemeter_t *dr, uint64_t pn) { if (dr->pn_cwnd_limited.start != UINT64_MAX && dr->pn_cwnd_limited.end == UINT64_MAX) dr->pn_cwnd_limited.end = pn; } -void quicly_delivery_rate_on_ack(quicly_delivery_rate_t *dr, int64_t now, uint64_t bytes_acked, uint64_t pn) +void quicly_ratemeter_on_ack(quicly_ratemeter_t *dr, int64_t now, uint64_t bytes_acked, uint64_t pn) { if (dr->pn_cwnd_limited.start <= pn && pn < dr->pn_cwnd_limited.end) { /* At the moment, the flow is CWND-limited. Either start the timer or update. */ if (dr->current.start.at == INT64_MAX) { start_sampling(dr, now, bytes_acked); } else { - dr->current.sample = (struct st_quicly_delivery_rate_sample_t){ + dr->current.sample = (struct st_quicly_rate_sample_t){ .elapsed = (uint32_t)(now - dr->current.start.at), .bytes_acked = (uint32_t)(bytes_acked - dr->current.start.bytes_acked), }; @@ -101,11 +101,11 @@ static uint64_t to_speed(uint64_t bytes_acked, uint32_t elapsed) return bytes_acked * 1000 / elapsed; } -void quicly_delivery_rate_report(quicly_delivery_rate_t *dr, uint64_t *latest, uint64_t *smoothed, uint64_t *variance) +void quicly_ratemeter_report(quicly_ratemeter_t *dr, uint64_t *latest, uint64_t *smoothed, uint64_t *variance) { { /* Calculate latest, or return if there are no samples at all. `latest` being reported will be the most recent "full" sample * if available, or else a partial sample. */ - const struct st_quicly_delivery_rate_sample_t *latest_sample = &dr->past_samples.entries[dr->past_samples.latest]; + const struct st_quicly_rate_sample_t *latest_sample = &dr->past_samples.entries[dr->past_samples.latest]; if (latest_sample->elapsed == 0) { latest_sample = &dr->current.sample; if (latest_sample->elapsed == 0) { @@ -118,7 +118,7 @@ void quicly_delivery_rate_report(quicly_delivery_rate_t *dr, uint64_t *latest, u #define FOREACH_SAMPLE(func) \ do { \ - const struct st_quicly_delivery_rate_sample_t *sample; \ + const struct st_quicly_rate_sample_t *sample; \ for (size_t i = 0; i < PTLS_ELEMENTSOF(dr->past_samples.entries); ++i) { \ if ((sample = &dr->past_samples.entries[i])->elapsed != 0) { \ func \ diff --git a/lib/quicly.c b/lib/quicly.c index ca7c4c02b..794f1fd82 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -353,7 +353,7 @@ struct st_quicly_conn_t { /** * delivery rate estimator */ - quicly_delivery_rate_t delivery_rate; + quicly_ratemeter_t ratemeter; } egress; /** * crypto data @@ -1214,8 +1214,8 @@ int quicly_get_stats(quicly_conn_t *conn, quicly_stats_t *stats) /* set or generate the non-pre-built stats fields here */ stats->rtt = conn->egress.loss.rtt; stats->cc = conn->egress.cc; - quicly_delivery_rate_report(&conn->egress.delivery_rate, &stats->delivery_rate.latest, &stats->delivery_rate.smoothed, - &stats->delivery_rate.variance); + quicly_ratemeter_report(&conn->egress.ratemeter, &stats->delivery_rate.latest, &stats->delivery_rate.smoothed, + &stats->delivery_rate.variance); return 0; } @@ -1297,7 +1297,7 @@ static void setup_next_send(quicly_conn_t *conn) /* When the flow becomes application-limited due to receiving some information, stop collecting delivery rate samples. */ if (!can_send_stream_data) - quicly_delivery_rate_not_cwnd_limited(&conn->egress.delivery_rate, conn->egress.packet_number); + quicly_ratemeter_not_cwnd_limited(&conn->egress.ratemeter, conn->egress.packet_number); } static int create_handshake_flow(quicly_conn_t *conn, size_t epoch) @@ -2131,7 +2131,7 @@ static quicly_conn_t *create_connection(quicly_context_t *ctx, uint32_t protocol quicly_linklist_init(&conn->egress.pending_streams.blocked.uni); quicly_linklist_init(&conn->egress.pending_streams.blocked.bidi); quicly_linklist_init(&conn->egress.pending_streams.control); - quicly_delivery_rate_init(&conn->egress.delivery_rate); + quicly_ratemeter_init(&conn->egress.ratemeter); conn->crypto.tls = tls; if (handshake_properties != NULL) { assert(handshake_properties->additional_extensions == NULL); @@ -4523,9 +4523,9 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) if (can_send_stream_data && (s->num_datagrams == s->max_datagrams || conn->egress.loss.sentmap.bytes_in_flight >= conn->egress.cc.cwnd)) { /* as the flow is CWND-limited, start delivery rate estimator */ - quicly_delivery_rate_in_cwnd_limited(&conn->egress.delivery_rate, s->first_packet_number); + quicly_ratemeter_in_cwnd_limited(&conn->egress.ratemeter, s->first_packet_number); } else { - quicly_delivery_rate_not_cwnd_limited(&conn->egress.delivery_rate, conn->egress.packet_number); + quicly_ratemeter_not_cwnd_limited(&conn->egress.ratemeter, conn->egress.packet_number); } if (s->num_datagrams != 0) update_idle_timeout(conn, 0); @@ -4970,8 +4970,8 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload QUICLY_PROBE(ACK_DELAY_RECEIVED, conn, conn->stash.now, frame.ack_delay); - quicly_delivery_rate_on_ack(&conn->egress.delivery_rate, conn->stash.now, conn->super.stats.num_bytes.ack_received, - largest_newly_acked.pn); + quicly_ratemeter_on_ack(&conn->egress.ratemeter, conn->stash.now, conn->super.stats.num_bytes.ack_received, + largest_newly_acked.pn); /* Update loss detection engine on ack. The function uses ack_delay only when the largest_newly_acked is also the largest acked * so far. So, it does not matter if the ack_delay being passed in does not apply to the largest_newly_acked. */ diff --git a/t/delivery-rate.c b/t/delivery-rate.c index 1c3ae38d1..590d718e6 100644 --- a/t/delivery-rate.c +++ b/t/delivery-rate.c @@ -26,7 +26,7 @@ #define CHECK_REPORT(el, es, ev) \ do { \ uint64_t latest, smoothed, variance; \ - quicly_delivery_rate_report(&dr, &latest, &smoothed, &variance); \ + quicly_ratemeter_report(&meter, &latest, &smoothed, &variance); \ ok(latest == el); \ ok(smoothed == es); \ ok(variance == ev); \ @@ -34,9 +34,9 @@ static void test_basic(void) { - quicly_delivery_rate_t dr; + quicly_ratemeter_t meter; - quicly_delivery_rate_init(&dr); + quicly_ratemeter_init(&meter); CHECK_REPORT(0, 0, 0); uint64_t pn = 0, bytes_acked = 0; @@ -44,42 +44,42 @@ static void test_basic(void) /* send 1KB packet every 20ms, in CWND-limited state */ for (; pn < 100; ++pn) { - quicly_delivery_rate_in_cwnd_limited(&dr, pn); + quicly_ratemeter_in_cwnd_limited(&meter, pn); bytes_acked += 1000; now += 20; - quicly_delivery_rate_on_ack(&dr, now, bytes_acked, pn); + quicly_ratemeter_on_ack(&meter, now, bytes_acked, pn); } CHECK_REPORT(50000, 50000, 0); /* send at a slow rate, in application-limited state */ for (; pn < 200; ++pn) { - quicly_delivery_rate_not_cwnd_limited(&dr, pn); + quicly_ratemeter_not_cwnd_limited(&meter, pn); bytes_acked += 10; now += 20; - quicly_delivery_rate_on_ack(&dr, now, bytes_acked, pn); + quicly_ratemeter_on_ack(&meter, now, bytes_acked, pn); } CHECK_REPORT(50000, 50000, 0); /* send 2KB packet every 20ms, in CWND-limited state */ for (; pn < 300; ++pn) { - quicly_delivery_rate_in_cwnd_limited(&dr, pn); + quicly_ratemeter_in_cwnd_limited(&meter, pn); bytes_acked += 2000; now += 20; - quicly_delivery_rate_on_ack(&dr, now, bytes_acked, pn); + quicly_ratemeter_on_ack(&meter, now, bytes_acked, pn); } CHECK_REPORT(100000, 100000, 0); } static void test_burst(void) { - quicly_delivery_rate_t dr; + quicly_ratemeter_t meter; - quicly_delivery_rate_init(&dr); + quicly_ratemeter_init(&meter); CHECK_REPORT(0, 0, 0); /* send 10 packet burst (pn=1 to 10) */ - quicly_delivery_rate_in_cwnd_limited(&dr, 1); - quicly_delivery_rate_not_cwnd_limited(&dr, 11); + quicly_ratemeter_in_cwnd_limited(&meter, 1); + quicly_ratemeter_not_cwnd_limited(&meter, 11); /* ack every 2 packets up to pn=9, every 20ms */ uint64_t pn = 0, bytes_acked = 0; @@ -88,20 +88,20 @@ static void test_burst(void) pn += 2; bytes_acked += 2000; now += 20; - quicly_delivery_rate_on_ack(&dr, now, bytes_acked, pn); + quicly_ratemeter_on_ack(&meter, now, bytes_acked, pn); if (pn == 10) break; } CHECK_REPORT(100000, 100000, 0); - ok(dr.current.sample.elapsed != 0); /* we have an active sample ... */ + ok(meter.current.sample.elapsed != 0); /* we have an active sample ... */ pn += 1; bytes_acked += 50; now += 20; - quicly_delivery_rate_on_ack(&dr, now, bytes_acked, pn); + quicly_ratemeter_on_ack(&meter, now, bytes_acked, pn); - ok(dr.current.sample.elapsed == 0); /* that gets committed by the next pn out of the window */ + ok(meter.current.sample.elapsed == 0); /* that gets committed by the next pn out of the window */ CHECK_REPORT(100000, 100000, 0); } From 29ae3aa6a3f05692b7997c64fb2b9d4ea0be2f48 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 3 Sep 2021 11:46:01 +0900 Subject: [PATCH 157/361] change the filenames too --- CMakeLists.txt | 4 ++-- include/quicly/{delivery-rate.h => rate.h} | 4 ++-- lib/quicly.c | 2 +- lib/{delivery-rate.c => rate.c} | 2 +- quicly.xcodeproj/project.pbxproj | 28 +++++++++++----------- t/{delivery-rate.c => rate.c} | 4 ++-- t/test.c | 2 +- t/test.h | 2 +- 8 files changed, 24 insertions(+), 24 deletions(-) rename include/quicly/{delivery-rate.h => rate.h} (98%) rename lib/{delivery-rate.c => rate.c} (99%) rename t/{delivery-rate.c => rate.c} (98%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 82e79c4b3..c8deecba2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,11 +53,11 @@ SET(QUICLY_LIBRARY_FILES lib/cc-cubic.c lib/cc-pico.c lib/defaults.c - lib/delivery-rate.c lib/local_cid.c lib/loss.c lib/quicly.c lib/ranges.c + lib/rate.c lib/recvstate.c lib/remote_cid.c lib/retire_cid.c @@ -68,13 +68,13 @@ SET(QUICLY_LIBRARY_FILES SET(UNITTEST_SOURCE_FILES deps/picotest/picotest.c - t/delivery-rate.c t/frame.c t/local_cid.c t/loss.c t/lossy.c t/maxsender.c t/ranges.c + t/rate.c t/remote_cid.c t/retire_cid.c t/sentmap.c diff --git a/include/quicly/delivery-rate.h b/include/quicly/rate.h similarity index 98% rename from include/quicly/delivery-rate.h rename to include/quicly/rate.h index 431630b1f..4c0c99e10 100644 --- a/include/quicly/delivery-rate.h +++ b/include/quicly/rate.h @@ -20,8 +20,8 @@ * IN THE SOFTWARE. */ -#ifndef quicly_delivery_rate_h -#define quicly_delivery_rate_h +#ifndef quicly_rate_h +#define quicly_rate_h #include #include "quicly/ranges.h" diff --git a/lib/quicly.c b/lib/quicly.c index 794f1fd82..c6d9ab4fe 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -35,7 +35,7 @@ #include "quicly/frame.h" #include "quicly/streambuf.h" #include "quicly/cc.h" -#include "quicly/delivery-rate.h" +#include "quicly/rate.h" #if QUICLY_USE_EMBEDDED_PROBES #include "embedded-probes.h" #elif QUICLY_USE_DTRACE diff --git a/lib/delivery-rate.c b/lib/rate.c similarity index 99% rename from lib/delivery-rate.c rename to lib/rate.c index 171ad52c6..8e6f10830 100644 --- a/lib/delivery-rate.c +++ b/lib/rate.c @@ -21,7 +21,7 @@ */ #include "picotls.h" -#include "quicly/delivery-rate.h" +#include "quicly/rate.h" static void start_sampling(quicly_ratemeter_t *dr, int64_t now, uint64_t bytes_acked) { diff --git a/quicly.xcodeproj/project.pbxproj b/quicly.xcodeproj/project.pbxproj index 1492c1008..6aebcafc5 100644 --- a/quicly.xcodeproj/project.pbxproj +++ b/quicly.xcodeproj/project.pbxproj @@ -10,10 +10,10 @@ 082195082683498900E3EFCF /* cc-pico.c in Sources */ = {isa = PBXBuildFile; fileRef = 082195072683498900E3EFCF /* cc-pico.c */; }; 082195092683498900E3EFCF /* cc-pico.c in Sources */ = {isa = PBXBuildFile; fileRef = 082195072683498900E3EFCF /* cc-pico.c */; }; 0821950A2683498900E3EFCF /* cc-pico.c in Sources */ = {isa = PBXBuildFile; fileRef = 082195072683498900E3EFCF /* cc-pico.c */; }; - 0829878E26E03D4D0053638F /* delivery-rate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0829878D26E03D4D0053638F /* delivery-rate.c */; }; - 0829878F26E03D4D0053638F /* delivery-rate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0829878D26E03D4D0053638F /* delivery-rate.c */; }; - 0829879026E03D4D0053638F /* delivery-rate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0829878D26E03D4D0053638F /* delivery-rate.c */; }; - 0829879226E0A9DF0053638F /* delivery-rate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0829879126E0A9DF0053638F /* delivery-rate.c */; }; + 0829878E26E03D4D0053638F /* rate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0829878D26E03D4D0053638F /* rate.c */; }; + 0829878F26E03D4D0053638F /* rate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0829878D26E03D4D0053638F /* rate.c */; }; + 0829879026E03D4D0053638F /* rate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0829878D26E03D4D0053638F /* rate.c */; }; + 0829879226E0A9DF0053638F /* rate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0829879126E0A9DF0053638F /* rate.c */; }; E904233D24AED0410072C5B7 /* loss.c in Sources */ = {isa = PBXBuildFile; fileRef = E904233C24AED0410072C5B7 /* loss.c */; }; E904233E24AED0410072C5B7 /* loss.c in Sources */ = {isa = PBXBuildFile; fileRef = E904233C24AED0410072C5B7 /* loss.c */; }; E904233F24AED0410072C5B7 /* loss.c in Sources */ = {isa = PBXBuildFile; fileRef = E904233C24AED0410072C5B7 /* loss.c */; }; @@ -149,9 +149,9 @@ /* Begin PBXFileReference section */ 082195072683498900E3EFCF /* cc-pico.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "cc-pico.c"; sourceTree = ""; }; - 0829878C26DF775B0053638F /* delivery-rate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "delivery-rate.h"; sourceTree = ""; }; - 0829878D26E03D4D0053638F /* delivery-rate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "delivery-rate.c"; sourceTree = ""; }; - 0829879126E0A9DF0053638F /* delivery-rate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "delivery-rate.c"; sourceTree = ""; }; + 0829878C26DF775B0053638F /* rate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = rate.h; sourceTree = ""; }; + 0829878D26E03D4D0053638F /* rate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = rate.c; sourceTree = ""; }; + 0829879126E0A9DF0053638F /* rate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = rate.c; sourceTree = ""; }; E904233C24AED0410072C5B7 /* loss.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = loss.c; sourceTree = ""; }; E904234024AEFB980072C5B7 /* loss.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = loss.c; sourceTree = ""; }; E9056C071F56965300E2B96C /* linklist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = linklist.h; sourceTree = ""; }; @@ -339,12 +339,12 @@ E98041C522383C62008B9745 /* cc-reno.c */, E9736527246FD3AC0039AA49 /* remote_cid.c */, E98042352244A5D7008B9745 /* defaults.c */, - 0829878D26E03D4D0053638F /* delivery-rate.c */, E99F8C251F4E9EBF00C26B3D /* frame.c */, E9736529246FD3AC0039AA49 /* local_cid.c */, E904233C24AED0410072C5B7 /* loss.c */, E98448411EA490A500390927 /* quicly.c */, E9F6A41F1F3C0B6D0083F0B2 /* ranges.c */, + 0829878D26E03D4D0053638F /* rate.c */, E920D21D1F43E05000799777 /* recvstate.c */, E9736528246FD3AC0039AA49 /* retire_cid.c */, E9F6A42D1F41375B0083F0B2 /* sendstate.c */, @@ -422,7 +422,6 @@ E9CC44121EC1926000DC7D3E /* t */ = { isa = PBXGroup; children = ( - 0829879126E0A9DF0053638F /* delivery-rate.c */, E98884C221E3F23A0060F010 /* e2e.t */, E99F8C281F4EAEF800C26B3D /* frame.c */, E9736533246FD3DA0039AA49 /* local_cid.c */, @@ -430,6 +429,7 @@ E920D22F1F49EE0B00799777 /* lossy.c */, E99B75E61F5CF96900CF503E /* maxsender.c */, E9F6A4291F3C3B7B0083F0B2 /* ranges.c */, + 0829879126E0A9DF0053638F /* rate.c */, E9736534246FD3DA0039AA49 /* remote_cid.c */, E9736535246FD3DA0039AA49 /* retire_cid.c */, E920D22D1F4981E500799777 /* sentmap.c */, @@ -459,13 +459,13 @@ E920D2201F44047C00799777 /* constants.h */, E9736521246FD3890039AA49 /* remote_cid.h */, E98042332244A539008B9745 /* defaults.h */, - 0829878C26DF775B0053638F /* delivery-rate.h */, E99F8C231F4E863200C26B3D /* frame.h */, E9736520246FD3880039AA49 /* local_cid.h */, E9056C071F56965300E2B96C /* linklist.h */, E93E54BA1F69B750001C50FE /* loss.h */, E920D2221F4536CB00799777 /* maxsender.h */, E9F6A4261F3C3B050083F0B2 /* ranges.h */, + 0829878C26DF775B0053638F /* rate.h */, E920D21B1F43DE4100799777 /* recvstate.h */, E9736522246FD3890039AA49 /* retire_cid.h */, E92D43EC1F41DCF5002AC767 /* sendstate.h */, @@ -721,7 +721,7 @@ E920D22B1F49533800799777 /* sentmap.c in Sources */, E9D3CCCF21D22F4300516202 /* streambuf.c in Sources */, E973652C246FD3AC0039AA49 /* local_cid.c in Sources */, - 0829878E26E03D4D0053638F /* delivery-rate.c in Sources */, + 0829878E26E03D4D0053638F /* rate.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -744,7 +744,7 @@ E9B43E12246943D300824E51 /* fusion.c in Sources */, E941428E23B0B845002D3CE0 /* defaults.c in Sources */, E941429023B0B861002D3CE0 /* streambuf.c in Sources */, - 0829878F26E03D4D0053638F /* delivery-rate.c in Sources */, + 0829878F26E03D4D0053638F /* rate.c in Sources */, E93E546A1F663851001C50FE /* pembase64.c in Sources */, E98042282239531A008B9745 /* cli.c in Sources */, E941429223B0B870002D3CE0 /* sendstate.c in Sources */, @@ -770,7 +770,7 @@ E9736537246FD3DA0039AA49 /* remote_cid.c in Sources */, E99F8C291F4EAEF800C26B3D /* frame.c in Sources */, E98041C722383C7A008B9745 /* cc-reno.c in Sources */, - 0829879026E03D4D0053638F /* delivery-rate.c in Sources */, + 0829879026E03D4D0053638F /* rate.c in Sources */, E9D31DD1232DEDB400ACD5EC /* quicly-probes.d in Sources */, E9736530246FD3B50039AA49 /* local_cid.c in Sources */, E920D22C1F49533800799777 /* sentmap.c in Sources */, @@ -799,7 +799,7 @@ E98042372244A5D7008B9745 /* defaults.c in Sources */, E99F8C271F4E9F5D00C26B3D /* frame.c in Sources */, E9736536246FD3DA0039AA49 /* local_cid.c in Sources */, - 0829879226E0A9DF0053638F /* delivery-rate.c in Sources */, + 0829879226E0A9DF0053638F /* rate.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/t/delivery-rate.c b/t/rate.c similarity index 98% rename from t/delivery-rate.c rename to t/rate.c index 590d718e6..fa9b1a0cb 100644 --- a/t/delivery-rate.c +++ b/t/rate.c @@ -20,7 +20,7 @@ * IN THE SOFTWARE. */ -#include "quicly/delivery-rate.h" +#include "quicly/rate.h" #include "test.h" #define CHECK_REPORT(el, es, ev) \ @@ -106,7 +106,7 @@ static void test_burst(void) CHECK_REPORT(100000, 100000, 0); } -void test_delivery_rate(void) +void test_rate(void) { subtest("basic", test_basic); subtest("burst", test_burst); diff --git a/t/test.c b/t/test.c index 6a6bbf671..85520cf07 100644 --- a/t/test.c +++ b/t/test.c @@ -625,10 +625,10 @@ int main(int argc, char **argv) quicly_amend_ptls_context(quic_ctx.tls); - subtest("delivery-rate", test_delivery_rate); subtest("next-packet-number", test_next_packet_number); subtest("address-token-codec", test_address_token_codec); subtest("ranges", test_ranges); + subtest("rate", test_rate); subtest("record-receipt", test_record_receipt); subtest("frame", test_frame); subtest("maxsender", test_maxsender); diff --git a/t/test.h b/t/test.h index 728563069..6ffc482d5 100644 --- a/t/test.h +++ b/t/test.h @@ -49,7 +49,7 @@ size_t transmit(quicly_conn_t *src, quicly_conn_t *dst); int max_data_is_equal(quicly_conn_t *client, quicly_conn_t *server); void test_ranges(void); -void test_delivery_rate(void); +void test_rate(void); void test_frame(void); void test_maxsender(void); void test_sentmap(void); From 0bb0bbc3b6c36cfb825bf79f06816891f5759f94 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 3 Sep 2021 11:55:04 +0900 Subject: [PATCH 158/361] define output type --- include/quicly.h | 7 ++----- include/quicly/rate.h | 13 +++++++++++-- lib/quicly.c | 4 +--- lib/rate.c | 12 ++++++------ t/rate.c | 10 +++++----- 5 files changed, 25 insertions(+), 21 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index df1214ce2..af0159c70 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -39,6 +39,7 @@ extern "C" { #include "quicly/linklist.h" #include "quicly/loss.h" #include "quicly/cc.h" +#include "quicly/rate.h" #include "quicly/recvstate.h" #include "quicly/sendstate.h" #include "quicly/maxsender.h" @@ -482,11 +483,7 @@ typedef struct st_quicly_stats_t { /** * Estimated delivery rate, in bytes/second. */ - struct { - uint64_t latest; - uint64_t smoothed; - uint64_t variance; - } delivery_rate; + quicly_rate_t delivery_rate; } quicly_stats_t; /** diff --git a/include/quicly/rate.h b/include/quicly/rate.h index 4c0c99e10..f9b729d24 100644 --- a/include/quicly/rate.h +++ b/include/quicly/rate.h @@ -77,6 +77,15 @@ typedef struct st_quicly_ratemeter_t { } current; } quicly_ratemeter_t; +/** + * Estimated delivery rate, in bytes / second. + */ +typedef struct st_quicly_rate_t { + uint64_t latest; + uint64_t smoothed; + uint64_t variance; +} quicly_rate_t; + /** * */ @@ -96,9 +105,9 @@ void quicly_ratemeter_not_cwnd_limited(quicly_ratemeter_t *dr, uint64_t pn); */ void quicly_ratemeter_on_ack(quicly_ratemeter_t *dr, int64_t now, uint64_t bytes_acked, uint64_t pn); /** - * Returns three indicators of the delivery rate estimate + * Returns the delivery rate estimate */ -void quicly_ratemeter_report(quicly_ratemeter_t *dr, uint64_t *latest, uint64_t *smoothed, uint64_t *variance); +void quicly_ratemeter_report(quicly_ratemeter_t *dr, quicly_rate_t *rate); #ifdef __cplusplus } diff --git a/lib/quicly.c b/lib/quicly.c index c6d9ab4fe..805c8d267 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -35,7 +35,6 @@ #include "quicly/frame.h" #include "quicly/streambuf.h" #include "quicly/cc.h" -#include "quicly/rate.h" #if QUICLY_USE_EMBEDDED_PROBES #include "embedded-probes.h" #elif QUICLY_USE_DTRACE @@ -1214,8 +1213,7 @@ int quicly_get_stats(quicly_conn_t *conn, quicly_stats_t *stats) /* set or generate the non-pre-built stats fields here */ stats->rtt = conn->egress.loss.rtt; stats->cc = conn->egress.cc; - quicly_ratemeter_report(&conn->egress.ratemeter, &stats->delivery_rate.latest, &stats->delivery_rate.smoothed, - &stats->delivery_rate.variance); + quicly_ratemeter_report(&conn->egress.ratemeter, &stats->delivery_rate); return 0; } diff --git a/lib/rate.c b/lib/rate.c index 8e6f10830..b4aa1c871 100644 --- a/lib/rate.c +++ b/lib/rate.c @@ -101,7 +101,7 @@ static uint64_t to_speed(uint64_t bytes_acked, uint32_t elapsed) return bytes_acked * 1000 / elapsed; } -void quicly_ratemeter_report(quicly_ratemeter_t *dr, uint64_t *latest, uint64_t *smoothed, uint64_t *variance) +void quicly_ratemeter_report(quicly_ratemeter_t *dr, quicly_rate_t *rate) { { /* Calculate latest, or return if there are no samples at all. `latest` being reported will be the most recent "full" sample * if available, or else a partial sample. */ @@ -109,11 +109,11 @@ void quicly_ratemeter_report(quicly_ratemeter_t *dr, uint64_t *latest, uint64_t if (latest_sample->elapsed == 0) { latest_sample = &dr->current.sample; if (latest_sample->elapsed == 0) { - *latest = *smoothed = *variance = 0; + rate->latest = rate->smoothed = rate->variance = 0; return; } } - *latest = to_speed(latest_sample->bytes_acked, latest_sample->elapsed); + rate->latest = to_speed(latest_sample->bytes_acked, latest_sample->elapsed); } #define FOREACH_SAMPLE(func) \ @@ -136,7 +136,7 @@ void quicly_ratemeter_report(quicly_ratemeter_t *dr, uint64_t *latest, uint64_t total_acked += sample->bytes_acked; total_elapsed += sample->elapsed; }); - *smoothed = to_speed(total_acked, total_elapsed); + rate->smoothed = to_speed(total_acked, total_elapsed); } { /* calculate variance */ @@ -144,10 +144,10 @@ void quicly_ratemeter_report(quicly_ratemeter_t *dr, uint64_t *latest, uint64_t size_t count = 0; FOREACH_SAMPLE({ uint64_t sample_speed = to_speed(sample->bytes_acked, sample->elapsed); - sum += (sample_speed - *smoothed) * (sample_speed - *smoothed); + sum += (sample_speed - rate->smoothed) * (sample_speed - rate->smoothed); ++count; }); - *variance = sum / count; + rate->variance = sum / count; } #undef FOREACH_SAMPLE diff --git a/t/rate.c b/t/rate.c index fa9b1a0cb..796c3b453 100644 --- a/t/rate.c +++ b/t/rate.c @@ -25,11 +25,11 @@ #define CHECK_REPORT(el, es, ev) \ do { \ - uint64_t latest, smoothed, variance; \ - quicly_ratemeter_report(&meter, &latest, &smoothed, &variance); \ - ok(latest == el); \ - ok(smoothed == es); \ - ok(variance == ev); \ + quicly_rate_t rate; \ + quicly_ratemeter_report(&meter, &rate); \ + ok(rate.latest == el); \ + ok(rate.smoothed == es); \ + ok(rate.variance == ev); \ } while (0) static void test_basic(void) From 1f6e0752fb95405b5715ea3cd91c40b406a6d1ea Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 3 Sep 2021 12:08:47 +0900 Subject: [PATCH 159/361] "dr" as a name no longer makes sense --- include/quicly/rate.h | 10 ++--- lib/rate.c | 86 +++++++++++++++++++++---------------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/include/quicly/rate.h b/include/quicly/rate.h index f9b729d24..f46e73586 100644 --- a/include/quicly/rate.h +++ b/include/quicly/rate.h @@ -89,25 +89,25 @@ typedef struct st_quicly_rate_t { /** * */ -void quicly_ratemeter_init(quicly_ratemeter_t *dr); +void quicly_ratemeter_init(quicly_ratemeter_t *meter); /** * Notifies the estimator that the flow is CWND-limited at the point of sending packets *starting* from packet number `pn`. */ -void quicly_ratemeter_in_cwnd_limited(quicly_ratemeter_t *dr, uint64_t pn); +void quicly_ratemeter_in_cwnd_limited(quicly_ratemeter_t *meter, uint64_t pn); /** * Notifies that the estimator that the flow is not CWND-limited when the packet number of the next packet will be `pn`. */ -void quicly_ratemeter_not_cwnd_limited(quicly_ratemeter_t *dr, uint64_t pn); +void quicly_ratemeter_not_cwnd_limited(quicly_ratemeter_t *meter, uint64_t pn); /** * Given three values, update the estimation. * @param bytes_acked total number of bytes being acked from the beginning of the connection; i.e., * `quicly_stats_t::num_bytes.ack_received` */ -void quicly_ratemeter_on_ack(quicly_ratemeter_t *dr, int64_t now, uint64_t bytes_acked, uint64_t pn); +void quicly_ratemeter_on_ack(quicly_ratemeter_t *meter, int64_t now, uint64_t bytes_acked, uint64_t pn); /** * Returns the delivery rate estimate */ -void quicly_ratemeter_report(quicly_ratemeter_t *dr, quicly_rate_t *rate); +void quicly_ratemeter_report(quicly_ratemeter_t *meter, quicly_rate_t *rate); #ifdef __cplusplus } diff --git a/lib/rate.c b/lib/rate.c index b4aa1c871..c0abafc5f 100644 --- a/lib/rate.c +++ b/lib/rate.c @@ -23,75 +23,75 @@ #include "picotls.h" #include "quicly/rate.h" -static void start_sampling(quicly_ratemeter_t *dr, int64_t now, uint64_t bytes_acked) +static void start_sampling(quicly_ratemeter_t *meter, int64_t now, uint64_t bytes_acked) { - dr->current.start.at = now; - dr->current.start.bytes_acked = bytes_acked; + meter->current.start.at = now; + meter->current.start.bytes_acked = bytes_acked; } -static void commit_sample(quicly_ratemeter_t *dr) +static void commit_sample(quicly_ratemeter_t *meter) { - ++dr->past_samples.latest; - if (dr->past_samples.latest >= PTLS_ELEMENTSOF(dr->past_samples.entries)) - dr->past_samples.latest = 0; - dr->past_samples.entries[dr->past_samples.latest] = dr->current.sample; + ++meter->past_samples.latest; + if (meter->past_samples.latest >= PTLS_ELEMENTSOF(meter->past_samples.entries)) + meter->past_samples.latest = 0; + meter->past_samples.entries[meter->past_samples.latest] = meter->current.sample; - dr->current.start.at = INT64_MAX; - dr->current.sample = (struct st_quicly_rate_sample_t){}; + meter->current.start.at = INT64_MAX; + meter->current.sample = (struct st_quicly_rate_sample_t){}; } -void quicly_ratemeter_init(quicly_ratemeter_t *dr) +void quicly_ratemeter_init(quicly_ratemeter_t *meter) { - *dr = (quicly_ratemeter_t){ - .past_samples = {.latest = PTLS_ELEMENTSOF(dr->past_samples.entries) - 1}, + *meter = (quicly_ratemeter_t){ + .past_samples = {.latest = PTLS_ELEMENTSOF(meter->past_samples.entries) - 1}, .pn_cwnd_limited = {.start = UINT64_MAX, .end = UINT64_MAX}, .current = {.start = {.at = INT64_MAX}}, }; } -void quicly_ratemeter_in_cwnd_limited(quicly_ratemeter_t *dr, uint64_t pn) +void quicly_ratemeter_in_cwnd_limited(quicly_ratemeter_t *meter, uint64_t pn) { /* bail out if already in cwnd-limited phase */ - if (dr->pn_cwnd_limited.start != UINT64_MAX && dr->pn_cwnd_limited.end == UINT64_MAX) + if (meter->pn_cwnd_limited.start != UINT64_MAX && meter->pn_cwnd_limited.end == UINT64_MAX) return; /* if the estimator was waiting for the end of the previous phase, and if a valid partial sample exists, commit it now */ - if (dr->pn_cwnd_limited.end != UINT64_MAX && dr->current.sample.elapsed != 0) - commit_sample(dr); + if (meter->pn_cwnd_limited.end != UINT64_MAX && meter->current.sample.elapsed != 0) + commit_sample(meter); /* begin new cwnd-limited phase */ - dr->pn_cwnd_limited = (quicly_range_t){.start = pn, .end = UINT64_MAX}; + meter->pn_cwnd_limited = (quicly_range_t){.start = pn, .end = UINT64_MAX}; } -void quicly_ratemeter_not_cwnd_limited(quicly_ratemeter_t *dr, uint64_t pn) +void quicly_ratemeter_not_cwnd_limited(quicly_ratemeter_t *meter, uint64_t pn) { - if (dr->pn_cwnd_limited.start != UINT64_MAX && dr->pn_cwnd_limited.end == UINT64_MAX) - dr->pn_cwnd_limited.end = pn; + if (meter->pn_cwnd_limited.start != UINT64_MAX && meter->pn_cwnd_limited.end == UINT64_MAX) + meter->pn_cwnd_limited.end = pn; } -void quicly_ratemeter_on_ack(quicly_ratemeter_t *dr, int64_t now, uint64_t bytes_acked, uint64_t pn) +void quicly_ratemeter_on_ack(quicly_ratemeter_t *meter, int64_t now, uint64_t bytes_acked, uint64_t pn) { - if (dr->pn_cwnd_limited.start <= pn && pn < dr->pn_cwnd_limited.end) { + if (meter->pn_cwnd_limited.start <= pn && pn < meter->pn_cwnd_limited.end) { /* At the moment, the flow is CWND-limited. Either start the timer or update. */ - if (dr->current.start.at == INT64_MAX) { - start_sampling(dr, now, bytes_acked); + if (meter->current.start.at == INT64_MAX) { + start_sampling(meter, now, bytes_acked); } else { - dr->current.sample = (struct st_quicly_rate_sample_t){ - .elapsed = (uint32_t)(now - dr->current.start.at), - .bytes_acked = (uint32_t)(bytes_acked - dr->current.start.bytes_acked), + meter->current.sample = (struct st_quicly_rate_sample_t){ + .elapsed = (uint32_t)(now - meter->current.start.at), + .bytes_acked = (uint32_t)(bytes_acked - meter->current.start.bytes_acked), }; - if (dr->current.sample.elapsed >= QUICLY_DELIVERY_RATE_SAMPLE_PERIOD) { - commit_sample(dr); - start_sampling(dr, now, bytes_acked); + if (meter->current.sample.elapsed >= QUICLY_DELIVERY_RATE_SAMPLE_PERIOD) { + commit_sample(meter); + start_sampling(meter, now, bytes_acked); } } - } else if (dr->pn_cwnd_limited.end <= pn) { + } else if (meter->pn_cwnd_limited.end <= pn) { /* We have exitted CWND-limited state. Save current value, if any. */ - if (dr->current.start.at != INT64_MAX) { - if (dr->current.sample.elapsed != 0) - commit_sample(dr); - dr->pn_cwnd_limited = (quicly_range_t){.start = UINT64_MAX, .end = UINT64_MAX}; - dr->current.start.at = INT64_MAX; + if (meter->current.start.at != INT64_MAX) { + if (meter->current.sample.elapsed != 0) + commit_sample(meter); + meter->pn_cwnd_limited = (quicly_range_t){.start = UINT64_MAX, .end = UINT64_MAX}; + meter->current.start.at = INT64_MAX; } } } @@ -101,13 +101,13 @@ static uint64_t to_speed(uint64_t bytes_acked, uint32_t elapsed) return bytes_acked * 1000 / elapsed; } -void quicly_ratemeter_report(quicly_ratemeter_t *dr, quicly_rate_t *rate) +void quicly_ratemeter_report(quicly_ratemeter_t *meter, quicly_rate_t *rate) { { /* Calculate latest, or return if there are no samples at all. `latest` being reported will be the most recent "full" sample * if available, or else a partial sample. */ - const struct st_quicly_rate_sample_t *latest_sample = &dr->past_samples.entries[dr->past_samples.latest]; + const struct st_quicly_rate_sample_t *latest_sample = &meter->past_samples.entries[meter->past_samples.latest]; if (latest_sample->elapsed == 0) { - latest_sample = &dr->current.sample; + latest_sample = &meter->current.sample; if (latest_sample->elapsed == 0) { rate->latest = rate->smoothed = rate->variance = 0; return; @@ -119,12 +119,12 @@ void quicly_ratemeter_report(quicly_ratemeter_t *dr, quicly_rate_t *rate) #define FOREACH_SAMPLE(func) \ do { \ const struct st_quicly_rate_sample_t *sample; \ - for (size_t i = 0; i < PTLS_ELEMENTSOF(dr->past_samples.entries); ++i) { \ - if ((sample = &dr->past_samples.entries[i])->elapsed != 0) { \ + for (size_t i = 0; i < PTLS_ELEMENTSOF(meter->past_samples.entries); ++i) { \ + if ((sample = &meter->past_samples.entries[i])->elapsed != 0) { \ func \ } \ } \ - if ((sample = &dr->current.sample)->elapsed != 0) { \ + if ((sample = &meter->current.sample)->elapsed != 0) { \ func \ } \ } while (0) From ad9d10ea72696d995ed3ae28f56f164de88c4d54 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 3 Sep 2021 12:10:48 +0900 Subject: [PATCH 160/361] add public API for obtaining just the delivery rate --- include/quicly.h | 4 ++++ lib/quicly.c | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/include/quicly.h b/include/quicly.h index af0159c70..7b63f75d1 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -884,6 +884,10 @@ static struct sockaddr *quicly_get_peername(quicly_conn_t *conn); * */ int quicly_get_stats(quicly_conn_t *conn, quicly_stats_t *stats); +/** + * + */ +int quicly_get_delivery_rate(quicly_conn_t *conn, quicly_rate_t *delivery_rate); /** * */ diff --git a/lib/quicly.c b/lib/quicly.c index 805c8d267..8d275f330 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1218,6 +1218,12 @@ int quicly_get_stats(quicly_conn_t *conn, quicly_stats_t *stats) return 0; } +int quicly_get_delivery_rate(quicly_conn_t *conn, quicly_rate_t *delivery_rate) +{ + quicly_ratemeter_report(&conn->egress.ratemeter, delivery_rate); + return 0; +} + quicly_stream_id_t quicly_get_ingress_max_streams(quicly_conn_t *conn, int uni) { quicly_maxsender_t *maxsender = uni ? &conn->ingress.max_streams.uni : &conn->ingress.max_streams.bidi; From 0ea264f82010236737744e58a4a19a8709d58b01 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 7 Sep 2021 09:35:14 +0900 Subject: [PATCH 161/361] add `-l` option for setting the length of the simulation --- t/simulator.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/t/simulator.c b/t/simulator.c index cfb4db570..562eefd3b 100644 --- a/t/simulator.c +++ b/t/simulator.c @@ -412,9 +412,11 @@ static void usage(const char *cmd) "\n" "Options:\n" " -n adds a sender using specified controller\n" - " -b bottleneck bandwidth\n" - " -d delay to be introduced between the sender and the botteneck\n" - " -q maximum depth of the bottleneck queue, in seconds\n" + " -b bottleneck bandwidth (default: 1000000, i.e., 1MB/s)\n" + " -l number of seconds to simulate (default: 100)\n" + " -d delay to be introduced between the sender and the botteneck, in seconds (default: 0.1)\n" + " -q maximum depth of the bottleneck queue, in seconds (default: 0.1)\n" + " -h print this help\n" "\n", cmd); } @@ -528,8 +530,9 @@ int main(int argc, char **argv) /* parse args */ double delay = 0.1, bw = 1e6, depth = 0.1; + unsigned length = 100; int ch; - while ((ch = getopt(argc, argv, "n:b:d:q:h")) != -1) { + while ((ch = getopt(argc, argv, "n:b:d:l:q:h")) != -1) { switch (ch) { case 'n': { quicly_cc_type_t **cc; @@ -571,6 +574,12 @@ int main(int argc, char **argv) exit(1); } break; + case 'l': + if (sscanf(optarg, "%u", &length) != 1) { + fprintf(stderr, "invalid length: %s\n", optarg); + exit(1); + } + break; case 'q': if (sscanf(optarg, "%lf", &depth) != 1) { fprintf(stderr, "invalid queue depth: %s\n", optarg); @@ -590,7 +599,7 @@ int main(int argc, char **argv) bottleneck_node.next_node = &server_node.node.super; *node_insert_at++ = &bottleneck_node.super; - while (now < 1050) + while (now < 1000 + length) run_nodes(nodes); return 0; From 459912a38dccd5f7e1859d423576f2d2192c82e8 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 7 Sep 2021 15:59:48 +0900 Subject: [PATCH 162/361] add `-s` option specifying that start delay --- t/simulator.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/t/simulator.c b/t/simulator.c index 562eefd3b..87ccd7fe0 100644 --- a/t/simulator.c +++ b/t/simulator.c @@ -110,6 +110,7 @@ struct net_bottleneck { struct net_endpoint { struct net_node super; quicly_address_t addr; + double start_at; struct net_endpoint_conn { quicly_conn_t *quic; struct net_node *egress; @@ -289,15 +290,17 @@ static void net_endpoint_forward(struct net_node *_self, struct net_packet *pack static double net_endpoint_next_run_at(struct net_node *_self) { struct net_endpoint *self = (struct net_endpoint *)_self; - double at = INFINITY; + if (now < self->start_at) + return self->start_at; + + double at = INFINITY; for (struct net_endpoint_conn *conn = self->conns; conn->quic != NULL; ++conn) { /* value is incremented by 0.1ms to avoid the timer firing earlier than specified due to rounding error */ double conn_at = quicly_get_first_timeout(conn->quic) / 1000. + 0.0001; if (conn_at < at) at = conn_at; } - if (at < now) at = now; return at; @@ -307,6 +310,9 @@ static void net_endpoint_run(struct net_node *_self) { struct net_endpoint *self = (struct net_endpoint *)_self; + if (now < self->start_at) + return; + for (struct net_endpoint_conn *conn = self->conns; conn->quic != NULL; ++conn) { quicly_address_t dest, src; struct iovec datagrams[10]; @@ -416,6 +422,7 @@ static void usage(const char *cmd) " -l number of seconds to simulate (default: 100)\n" " -d delay to be introduced between the sender and the botteneck, in seconds (default: 0.1)\n" " -q maximum depth of the bottleneck queue, in seconds (default: 0.1)\n" + " -s delay until the sender is introduced to the simulation (default: 0)\n" " -h print this help\n" "\n", cmd); @@ -529,10 +536,10 @@ int main(int argc, char **argv) *node_insert_at++ = &server_node.node.super; /* parse args */ - double delay = 0.1, bw = 1e6, depth = 0.1; + double delay = 0.1, bw = 1e6, depth = 0.1, start = 0; unsigned length = 100; int ch; - while ((ch = getopt(argc, argv, "n:b:d:l:q:h")) != -1) { + while ((ch = getopt(argc, argv, "n:b:d:s:l:q:h")) != -1) { switch (ch) { case 'n': { quicly_cc_type_t **cc; @@ -551,6 +558,7 @@ int main(int argc, char **argv) *node_insert_at++ = &delay_node->super; struct net_endpoint *client_node = malloc(sizeof(*client_node)); net_endpoint_init(client_node); + client_node->start_at = now + start; int ret = quicly_connect(&client_node->conns[0].quic, &quicctx, "hello.example.com", &server_node.node.addr.sa, &client_node->addr.sa, NULL, ptls_iovec_init(NULL, 0), NULL, NULL); assert(ret == 0); @@ -574,6 +582,12 @@ int main(int argc, char **argv) exit(1); } break; + case 's': + if (sscanf(optarg, "%lf", &start) != 1) { + fprintf(stderr, "invaild start: %s\n", optarg); + exit(1); + } + break; case 'l': if (sscanf(optarg, "%u", &length) != 1) { fprintf(stderr, "invalid length: %s\n", optarg); From 444ea9bcdc057cdba89b939660dcfbcb57c2adf9 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sun, 12 Sep 2021 09:20:19 +0900 Subject: [PATCH 163/361] Update lib/rate.c --- lib/rate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rate.c b/lib/rate.c index c0abafc5f..1b22953f6 100644 --- a/lib/rate.c +++ b/lib/rate.c @@ -86,7 +86,7 @@ void quicly_ratemeter_on_ack(quicly_ratemeter_t *meter, int64_t now, uint64_t by } } } else if (meter->pn_cwnd_limited.end <= pn) { - /* We have exitted CWND-limited state. Save current value, if any. */ + /* We have exited CWND-limited state. Save current value, if any. */ if (meter->current.start.at != INT64_MAX) { if (meter->current.sample.elapsed != 0) commit_sample(meter); From fc909e5cdc3a1d563bedc86055878da7316c97fc Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sun, 12 Sep 2021 12:57:02 +0900 Subject: [PATCH 164/361] add `-r` option to specify PLR --- t/simulator.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/t/simulator.c b/t/simulator.c index 87ccd7fe0..3709eef25 100644 --- a/t/simulator.c +++ b/t/simulator.c @@ -98,6 +98,12 @@ struct net_delay { double delay; }; +struct net_random_loss { + struct net_node super; + struct net_node *next_node; + double loss_ratio; +}; + struct net_bottleneck { struct net_node super; struct net_node *next_node; @@ -187,6 +193,33 @@ static void net_delay_init(struct net_delay *self, double delay) }; } +static void net_random_loss_forward(struct net_node *_self, struct net_packet *packet) +{ + struct net_random_loss *self = (struct net_random_loss *)_self; + + if (rand() % 65536 < self->loss_ratio * 65536) { + printf("{\"random-loss\": \"drop\", \"at\": %f, \"packet-src\": %" PRIu32 "}\n", now, + ntohl(packet->src->addr.sin.sin_addr.s_addr)); + net_packet_destroy(packet); + return; + } + + self->next_node->forward_(self->next_node, packet); +} + +static double net_random_loss_next_run_at(struct net_node *self) +{ + return INFINITY; +} + +static void net_random_loss_init(struct net_random_loss *self, double loss_ratio) +{ + *self = (struct net_random_loss){ + .super = {net_random_loss_forward, net_random_loss_next_run_at, NULL}, + .loss_ratio = loss_ratio, + }; +} + static void net_bottleneck_print_stats(struct net_bottleneck *self, const char *event, struct net_packet *packet) { printf("{\"bottleneck\": \"%s\", \"at\": %f, \"queue-size\": %zu, \"packet-src\": %" PRIu32 ", \"packet-size\": %zu}\n", event, @@ -422,6 +455,7 @@ static void usage(const char *cmd) " -l number of seconds to simulate (default: 100)\n" " -d delay to be introduced between the sender and the botteneck, in seconds (default: 0.1)\n" " -q maximum depth of the bottleneck queue, in seconds (default: 0.1)\n" + " -r introduce random loss at specified probability (default: 0)\n" " -s delay until the sender is introduced to the simulation (default: 0)\n" " -h print this help\n" "\n", @@ -524,6 +558,7 @@ int main(int argc, char **argv) quicctx.transport_params.min_ack_delay_usec = UINT64_MAX; /* disable ack-delay extension */ struct net_bottleneck bottleneck_node; + struct net_random_loss random_loss_node; struct { struct net_endpoint node; quicly_context_t accept_ctx; @@ -536,10 +571,10 @@ int main(int argc, char **argv) *node_insert_at++ = &server_node.node.super; /* parse args */ - double delay = 0.1, bw = 1e6, depth = 0.1, start = 0; + double delay = 0.1, bw = 1e6, depth = 0.1, start = 0, random_loss = 0; unsigned length = 100; int ch; - while ((ch = getopt(argc, argv, "n:b:d:s:l:q:h")) != -1) { + while ((ch = getopt(argc, argv, "n:b:d:s:l:q:r:h")) != -1) { switch (ch) { case 'n': { quicly_cc_type_t **cc; @@ -600,6 +635,12 @@ int main(int argc, char **argv) exit(1); } break; + case 'r': + if (sscanf(optarg, "%lf", &random_loss) != 1) { + fprintf(stderr, "invalid random loss rate: %s\n", optarg); + exit(1); + } + break; default: usage(argv[0]); exit(0); @@ -613,6 +654,14 @@ int main(int argc, char **argv) bottleneck_node.next_node = &server_node.node.super; *node_insert_at++ = &bottleneck_node.super; + /* setup random loss */ + if (random_loss != 0) { + net_random_loss_init(&random_loss_node, random_loss); + random_loss_node.next_node = &server_node.node.super; + bottleneck_node.next_node = &random_loss_node.super; + *node_insert_at++ = &random_loss_node.super; + } + while (now < 1000 + length) run_nodes(nodes); From 44fa694871bb3b5ff10d56581af601f4f8236f6e Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 14 Sep 2021 08:48:26 +0900 Subject: [PATCH 165/361] add comment clarifying the logic --- lib/rate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/rate.c b/lib/rate.c index 1b22953f6..1248711d7 100644 --- a/lib/rate.c +++ b/lib/rate.c @@ -76,6 +76,8 @@ void quicly_ratemeter_on_ack(quicly_ratemeter_t *meter, int64_t now, uint64_t by if (meter->current.start.at == INT64_MAX) { start_sampling(meter, now, bytes_acked); } else { + /* Update current sample whenever receiving an ACK, so that the sample can be committed other than when receiving an ACK + * (i.e., when opening a new CWND-limited phase). */ meter->current.sample = (struct st_quicly_rate_sample_t){ .elapsed = (uint32_t)(now - meter->current.start.at), .bytes_acked = (uint32_t)(bytes_acked - meter->current.start.bytes_acked), From c7bf867e47f27926f269acf661fe4c527497b2f5 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 14 Sep 2021 08:49:59 +0900 Subject: [PATCH 166/361] use stdev instead of variance --- include/quicly/rate.h | 2 +- lib/rate.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/quicly/rate.h b/include/quicly/rate.h index f46e73586..fd5460775 100644 --- a/include/quicly/rate.h +++ b/include/quicly/rate.h @@ -83,7 +83,7 @@ typedef struct st_quicly_ratemeter_t { typedef struct st_quicly_rate_t { uint64_t latest; uint64_t smoothed; - uint64_t variance; + uint64_t stdev; } quicly_rate_t; /** diff --git a/lib/rate.c b/lib/rate.c index 1248711d7..6de0986ea 100644 --- a/lib/rate.c +++ b/lib/rate.c @@ -20,6 +20,7 @@ * IN THE SOFTWARE. */ +#include #include "picotls.h" #include "quicly/rate.h" @@ -111,7 +112,7 @@ void quicly_ratemeter_report(quicly_ratemeter_t *meter, quicly_rate_t *rate) if (latest_sample->elapsed == 0) { latest_sample = &meter->current.sample; if (latest_sample->elapsed == 0) { - rate->latest = rate->smoothed = rate->variance = 0; + rate->latest = rate->smoothed = rate->stdev = 0; return; } } @@ -141,7 +142,7 @@ void quicly_ratemeter_report(quicly_ratemeter_t *meter, quicly_rate_t *rate) rate->smoothed = to_speed(total_acked, total_elapsed); } - { /* calculate variance */ + { /* calculate stdev */ uint64_t sum = 0; size_t count = 0; FOREACH_SAMPLE({ @@ -149,7 +150,7 @@ void quicly_ratemeter_report(quicly_ratemeter_t *meter, quicly_rate_t *rate) sum += (sample_speed - rate->smoothed) * (sample_speed - rate->smoothed); ++count; }); - rate->variance = sum / count; + rate->stdev = sqrt(sum / count); } #undef FOREACH_SAMPLE From 6cf938489fe3439a7246c2a9ffa1fe6877858420 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 14 Sep 2021 08:53:49 +0900 Subject: [PATCH 167/361] update tests --- t/rate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/rate.c b/t/rate.c index 796c3b453..dec877e3d 100644 --- a/t/rate.c +++ b/t/rate.c @@ -29,7 +29,7 @@ quicly_ratemeter_report(&meter, &rate); \ ok(rate.latest == el); \ ok(rate.smoothed == es); \ - ok(rate.variance == ev); \ + ok(rate.stdev == ev); \ } while (0) static void test_basic(void) From e4c5a2678e5959fe70ccfbbd05ca22129f6b58d7 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 1 Oct 2021 15:29:49 +0900 Subject: [PATCH 168/361] add `-t` option for logging trace --- t/simulator.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/t/simulator.c b/t/simulator.c index 3709eef25..4217edc3b 100644 --- a/t/simulator.c +++ b/t/simulator.c @@ -35,6 +35,8 @@ #include "quicly/cc.h" #include "quicly/defaults.h" +FILE *quicly_trace_fp; + static double now = 1000; static quicly_address_t new_address(void) @@ -457,6 +459,7 @@ static void usage(const char *cmd) " -q maximum depth of the bottleneck queue, in seconds (default: 0.1)\n" " -r introduce random loss at specified probability (default: 0)\n" " -s delay until the sender is introduced to the simulation (default: 0)\n" + " -t emits trace as well\n" " -h print this help\n" "\n", cmd); @@ -574,7 +577,7 @@ int main(int argc, char **argv) double delay = 0.1, bw = 1e6, depth = 0.1, start = 0, random_loss = 0; unsigned length = 100; int ch; - while ((ch = getopt(argc, argv, "n:b:d:s:l:q:r:h")) != -1) { + while ((ch = getopt(argc, argv, "n:b:d:s:l:q:r:th")) != -1) { switch (ch) { case 'n': { quicly_cc_type_t **cc; @@ -641,6 +644,9 @@ int main(int argc, char **argv) exit(1); } break; + case 't': + quicly_trace_fp = stdout; + break; default: usage(argv[0]); exit(0); @@ -667,5 +673,3 @@ int main(int argc, char **argv) return 0; } - -FILE *quicly_trace_fp; From 749b378ae656c9d1757011a52e13a4c8981c143f Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 4 Oct 2021 18:58:55 +0900 Subject: [PATCH 169/361] fix CID overlap - otherwise it is hard to use trace --- t/simulator.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/t/simulator.c b/t/simulator.c index 4217edc3b..9c58e2754 100644 --- a/t/simulator.c +++ b/t/simulator.c @@ -598,7 +598,8 @@ int main(int argc, char **argv) net_endpoint_init(client_node); client_node->start_at = now + start; int ret = quicly_connect(&client_node->conns[0].quic, &quicctx, "hello.example.com", &server_node.node.addr.sa, - &client_node->addr.sa, NULL, ptls_iovec_init(NULL, 0), NULL, NULL); + &client_node->addr.sa, &next_quic_cid, ptls_iovec_init(NULL, 0), NULL, NULL); + ++next_quic_cid.master_id; assert(ret == 0); quicly_stream_t *stream; ret = quicly_open_stream(client_node->conns[0].quic, &stream, 1); From 3be019a6458d851e32f2266bbd4ae884882b568a Mon Sep 17 00:00:00 2001 From: "Nabil S. Alramli" Date: Mon, 25 Oct 2021 11:51:41 -0400 Subject: [PATCH 170/361] [bug-fix] should_send_max_streams() can access conn->super.ctx after it is freed --- lib/quicly.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 91255a166..5285be302 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1585,9 +1585,8 @@ void quicly_free(quicly_conn_t *conn) QUICLY_PROBE(CONN_STATS, conn, conn->stash.now, &stats, sizeof(stats)); } #endif - update_open_count(conn->super.ctx, -1); - destroy_all_streams(conn, 0, 1); + update_open_count(conn->super.ctx, -1); clear_datagram_frame_payloads(conn); quicly_maxsender_dispose(&conn->ingress.max_data.sender); From fd5a2e9df6550f072a5980b5bb6a892a0d999170 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 26 Oct 2021 14:00:50 +0900 Subject: [PATCH 171/361] update picotls to HEAD --- deps/picotls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/picotls b/deps/picotls index ea3e079d1..9608603a1 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit ea3e079d1616114b81a2d964e78cf7274e5d795b +Subproject commit 9608603a10fd0fa84da33bebf315e407274d6d9b From 89cbfd3a959cfef8f0ebda591261ca002ca1c554 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 1 Nov 2021 16:12:17 +0900 Subject: [PATCH 172/361] [draft-ietf-quic-ack-frequency-02] update TP, frame encoding --- include/quicly/frame.h | 23 ++++++++++++----------- lib/quicly.c | 4 ++-- quicly-probes.d | 2 +- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/include/quicly/frame.h b/include/quicly/frame.h index 42248892b..c057f757a 100644 --- a/include/quicly/frame.h +++ b/include/quicly/frame.h @@ -270,9 +270,14 @@ typedef struct st_quicly_ack_frequency_frame_t { uint64_t sequence; uint64_t packet_tolerance; uint64_t max_ack_delay; - uint8_t ignore_order; + uint8_t ignore_order : 1; + uint8_t ignore_ce : 1; } quicly_ack_frequency_frame_t; +#define QUICLY_ACK_FREQUENCY_IGNORE_ORDER_BIT 1 +#define QUICLY_ACK_FREQUENCY_IGNORE_CE_BIT 2 +#define QUICLY_ACK_FREQUENCY_ALL_BITS (QUICLY_ACK_FREQUENCY_IGNORE_ORDER_BIT | QUICLY_ACK_FREQUENCY_IGNORE_CE_BIT) + static uint8_t *quicly_encode_ack_frequency_frame(uint8_t *dst, uint64_t sequence, uint64_t packet_tolerance, uint64_t max_ack_delay, int ignore_order); static int quicly_decode_ack_frequency_frame(const uint8_t **src, const uint8_t *end, quicly_ack_frequency_frame_t *frame); @@ -795,7 +800,7 @@ inline uint8_t *quicly_encode_ack_frequency_frame(uint8_t *dst, uint64_t sequenc dst = quicly_encodev(dst, sequence); dst = quicly_encodev(dst, packet_tolerance); dst = quicly_encodev(dst, max_ack_delay); - *dst++ = !!ignore_order; + *dst++ = ignore_order ? QUICLY_ACK_FREQUENCY_IGNORE_ORDER_BIT : 0; return dst; } @@ -809,17 +814,13 @@ inline int quicly_decode_ack_frequency_frame(const uint8_t **src, const uint8_t goto Error; if (*src == end) goto Error; - switch (*(*src)++) { - case 0: - frame->ignore_order = 0; - break; - case 1: - frame->ignore_order = 1; - break; - default: + uint8_t flags = *(*src)++; + if ((flags & ~QUICLY_ACK_FREQUENCY_ALL_BITS) != 0) goto Error; - } + frame->ignore_order = (flags & QUICLY_ACK_FREQUENCY_IGNORE_ORDER_BIT) != 0; + frame->ignore_ce = (flags & QUICLY_ACK_FREQUENCY_IGNORE_CE_BIT) != 0; return 0; + Error: return QUICLY_TRANSPORT_ERROR_FRAME_ENCODING; } diff --git a/lib/quicly.c b/lib/quicly.c index 91255a166..38593c7b2 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -62,7 +62,7 @@ #define QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_SOURCE_CONNECTION_ID 15 #define QUICLY_TRANSPORT_PARAMETER_ID_RETRY_SOURCE_CONNECTION_ID 16 #define QUICLY_TRANSPORT_PARAMETER_ID_MAX_DATAGRAM_FRAME_SIZE 0x20 -#define QUICLY_TRANSPORT_PARAMETER_ID_MIN_ACK_DELAY 0xff02de1a +#define QUICLY_TRANSPORT_PARAMETER_ID_MIN_ACK_DELAY 0xff03de1a /** * maximum size of token that quicly accepts @@ -5517,7 +5517,7 @@ static int handle_ack_frequency_frame(quicly_conn_t *conn, struct st_quicly_hand return ret; QUICLY_PROBE(ACK_FREQUENCY_RECEIVE, conn, conn->stash.now, frame.sequence, frame.packet_tolerance, frame.max_ack_delay, - frame.ignore_order); + frame.ignore_order, frame.ignore_ce); /* At the moment, the only value that the remote peer would send is this value, because our TP.min_ack_delay and max_ack_delay * are equal. */ diff --git a/quicly-probes.d b/quicly-probes.d index 8a163f19a..7f6dad49d 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -128,7 +128,7 @@ provider quicly { probe datagram_receive(struct st_quicly_conn_t *conn, int64_t at, const void *payload, size_t payload_len); probe ack_frequency_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t sequence, uint64_t packet_tolerance, - uint64_t max_ack_delay, int ignore_order); + uint64_t max_ack_delay, int ignore_order, int ignore_ce); probe quictrace_send_stream(struct st_quicly_conn_t *conn, int64_t at, struct st_quicly_stream_t *stream, uint64_t off, size_t len, int fin); From fc8cbaa6cbbecf0a795128d299a2ffefe4d3a441 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 1 Nov 2021 16:36:51 +0900 Subject: [PATCH 173/361] use of delayed-ack is declared per each direction, introduce `quicly_context_t::ack_frequency` to tune the frequency --- include/quicly.h | 7 +++++- include/quicly/constants.h | 3 +-- lib/defaults.c | 2 ++ lib/quicly.c | 48 ++++++++++++++++---------------------- src/cli.c | 2 +- 5 files changed, 30 insertions(+), 32 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index 7b63f75d1..2431acf79 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -310,6 +310,11 @@ struct st_quicly_context_t { * (server-only) amplification limit before the peer address is validated */ uint16_t pre_validation_amplification_limit; + /** + * How frequent the endpoint should induce ACKs from the peer, relative to RTT (or CWND) multiplied by 1024. As an example, 128 + * will request the peer to send one ACK every 1/8 RTT (or CWND). 0 disables the use of the delayed-ack extension. + */ + uint16_t ack_frequency; /** * expand client hello so that it does not fit into one datagram */ @@ -1023,7 +1028,7 @@ int quicly_encode_transport_parameter_list(ptls_buffer_t *buf, const quicly_tran */ int quicly_decode_transport_parameter_list(quicly_transport_parameters_t *params, quicly_cid_t *original_dcid, quicly_cid_t *initial_scid, quicly_cid_t *retry_scid, void *stateless_reset_token, - const uint8_t *src, const uint8_t *end, int recognize_delayed_ack); + const uint8_t *src, const uint8_t *end); /** * Initiates a new connection. * @param new_cid the CID to be used for the connection. path_id is ignored. diff --git a/include/quicly/constants.h b/include/quicly/constants.h index d26604262..6328591d8 100644 --- a/include/quicly/constants.h +++ b/include/quicly/constants.h @@ -53,8 +53,7 @@ extern "C" { #define QUICLY_DEFAULT_PACKET_TOLERANCE 2 #define QUICLY_MAX_PACKET_TOLERANCE 100 -#define QUICLY_FIRST_ACK_FREQUENCY_PACKET_NUMBER 1000 -#define QUICLY_ACK_FREQUENCY_CWND_FRACTION 8 +#define QUICLY_FIRST_ACK_FREQUENCY_LOSS_EPISODE 4 #define QUICLY_AEAD_TAG_SIZE 16 diff --git a/lib/defaults.c b/lib/defaults.c index 92c12e053..6b7b3ebbc 100644 --- a/lib/defaults.c +++ b/lib/defaults.c @@ -44,6 +44,7 @@ const quicly_context_t quicly_spec_context = {NULL, DEFAULT_INITCWND_PACKETS, QUICLY_PROTOCOL_VERSION_1, DEFAULT_PRE_VALIDATION_AMPLIFICATION_LIMIT, + 0, /* ack_frequency */ 0, /* enlarge_client_hello */ NULL, NULL, /* on_stream_open */ @@ -71,6 +72,7 @@ const quicly_context_t quicly_performant_context = {NULL, DEFAULT_INITCWND_PACKETS, QUICLY_PROTOCOL_VERSION_1, DEFAULT_PRE_VALIDATION_AMPLIFICATION_LIMIT, + 0, /* ack_frequency */ 0, /* enlarge_client_hello */ NULL, NULL, /* on_stream_open */ diff --git a/lib/quicly.c b/lib/quicly.c index 38593c7b2..5bb9f9c9c 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -601,11 +601,6 @@ static int needs_cid_auth(quicly_conn_t *conn) } } -static int recognize_delayed_ack(quicly_conn_t *conn) -{ - return conn->super.ctx->transport_params.min_ack_delay_usec != UINT64_MAX; -} - static int64_t get_sentmap_expiration_time(quicly_conn_t *conn) { return quicly_loss_get_sentmap_expiration_time(&conn->egress.loss, conn->super.remote.transport_params.max_ack_delay); @@ -1830,7 +1825,7 @@ static const quicly_cid_t _tp_cid_ignore; int quicly_decode_transport_parameter_list(quicly_transport_parameters_t *params, quicly_cid_t *original_dcid, quicly_cid_t *initial_scid, quicly_cid_t *retry_scid, void *stateless_reset_token, - const uint8_t *src, const uint8_t *end, int recognize_delayed_ack) + const uint8_t *src, const uint8_t *end) { /* When non-negative, tp_index contains the literal position within the list of transport parameters recognized by this function. * That index is being used to find duplicates using a 64-bit bitmap (found_bits). When the transport parameter is being processed, @@ -1980,19 +1975,16 @@ int quicly_decode_transport_parameter_list(quicly_transport_parameters_t *params } params->max_ack_delay = (uint16_t)v; }); - /* min_ack_delay is recognized only if the support is enabled on this endpoint */ - if (recognize_delayed_ack) { - DECODE_TP(QUICLY_TRANSPORT_PARAMETER_ID_MIN_ACK_DELAY, { - if ((params->min_ack_delay_usec = ptls_decode_quicint(&src, end)) == UINT64_MAX) { - ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; - goto Exit; - } - if (params->min_ack_delay_usec >= 16777216) { /* "values of 2^24 or greater are invalid" */ - ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; - goto Exit; - } - }); - } + DECODE_TP(QUICLY_TRANSPORT_PARAMETER_ID_MIN_ACK_DELAY, { + if ((params->min_ack_delay_usec = ptls_decode_quicint(&src, end)) == UINT64_MAX) { + ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; + goto Exit; + } + if (params->min_ack_delay_usec >= 16777216) { /* "values of 2^24 or greater are invalid" */ + ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; + goto Exit; + } + }); DECODE_TP(QUICLY_TRANSPORT_PARAMETER_ID_ACTIVE_CONNECTION_ID_LIMIT, { uint64_t v; if ((v = ptls_decode_quicint(&src, end)) == UINT64_MAX) { @@ -2185,8 +2177,7 @@ static int client_collected_extensions(ptls_t *tls, ptls_handshake_properties_t if ((ret = quicly_decode_transport_parameter_list(¶ms, needs_cid_auth(conn) || is_retry(conn) ? &original_dcid : NULL, needs_cid_auth(conn) ? &initial_scid : &tp_cid_ignore, needs_cid_auth(conn) ? is_retry(conn) ? &retry_scid : NULL : &tp_cid_ignore, - remote_cid->stateless_reset_token, src, end, recognize_delayed_ack(conn))) != - 0) + remote_cid->stateless_reset_token, src, end)) != 0) goto Exit; /* validate CIDs */ @@ -2356,10 +2347,10 @@ static int server_collected_extensions(ptls_t *tls, ptls_handshake_properties_t { /* decode transport_parameters extension */ const uint8_t *src = slots[0].data.base, *end = src + slots[0].data.len; - if ((ret = quicly_decode_transport_parameter_list( - &conn->super.remote.transport_params, needs_cid_auth(conn) ? NULL : &tp_cid_ignore, - needs_cid_auth(conn) ? &initial_scid : &tp_cid_ignore, needs_cid_auth(conn) ? NULL : &tp_cid_ignore, NULL, src, - end, recognize_delayed_ack(conn))) != 0) + if ((ret = quicly_decode_transport_parameter_list(&conn->super.remote.transport_params, + needs_cid_auth(conn) ? NULL : &tp_cid_ignore, + needs_cid_auth(conn) ? &initial_scid : &tp_cid_ignore, + needs_cid_auth(conn) ? NULL : &tp_cid_ignore, NULL, src, end)) != 0) goto Exit; if (needs_cid_auth(conn) && !quicly_cid_is_equal(&conn->super.remote.cid_set.cids[0].cid, ptls_iovec_init(initial_scid.cid, initial_scid.len))) { @@ -3284,9 +3275,10 @@ static int do_allocate_frame(quicly_conn_t *conn, quicly_send_context_t *s, size return ret; /* adjust ack-frequency */ if (conn->stash.now >= conn->egress.ack_frequency.update_at) { - if (conn->egress.packet_number >= QUICLY_FIRST_ACK_FREQUENCY_PACKET_NUMBER && conn->initial == NULL && + assert(conn->super.remote.transport_params.min_ack_delay_usec != UINT64_MAX); + if (conn->egress.cc.num_loss_episodes >= QUICLY_FIRST_ACK_FREQUENCY_LOSS_EPISODE && conn->initial == NULL && conn->handshake == NULL) { - uint32_t fraction_of_cwnd = conn->egress.cc.cwnd / QUICLY_ACK_FREQUENCY_CWND_FRACTION; + uint32_t fraction_of_cwnd = (uint32_t)((uint64_t)conn->egress.cc.cwnd * conn->super.ctx->ack_frequency / 1024); if (fraction_of_cwnd >= conn->egress.max_udp_payload_size * 3) { uint32_t packet_tolerance = fraction_of_cwnd / conn->egress.max_udp_payload_size; if (packet_tolerance > QUICLY_MAX_PACKET_TOLERANCE) @@ -5510,7 +5502,7 @@ static int handle_ack_frequency_frame(quicly_conn_t *conn, struct st_quicly_hand int ret; /* recognize the frame only when the support has been advertised */ - if (!recognize_delayed_ack(conn)) + if (conn->super.ctx->transport_params.min_ack_delay_usec == UINT64_MAX) return QUICLY_TRANSPORT_ERROR_FRAME_ENCODING; if ((ret = quicly_decode_ack_frequency_frame(&state->src, state->end, &frame)) != 0) diff --git a/src/cli.c b/src/cli.c index 1c910093a..e44926aa5 100644 --- a/src/cli.c +++ b/src/cli.c @@ -905,7 +905,7 @@ static void load_session(void) src = end; }); ptls_decode_open_block(src, end, 2, { - if ((ret = quicly_decode_transport_parameter_list(&resumed_transport_params, NULL, NULL, NULL, NULL, src, end, 0)) != 0) + if ((ret = quicly_decode_transport_parameter_list(&resumed_transport_params, NULL, NULL, NULL, NULL, src, end)) != 0) goto Exit; src = end; }); From 3386d3da41c64d28bf11e4537fd15fb8c1fc49e1 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 2 Nov 2021 15:08:16 +0900 Subject: [PATCH 174/361] add option for setting ack frequency (default is zero to disable) --- src/cli.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/cli.c b/src/cli.c index e44926aa5..d738156f9 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1020,6 +1020,8 @@ static void usage(const char *cmd) " 29)\n" " -e event-log-file file to log events\n" " -E expand Client Hello (sends multiple client Initials)\n" + " -f fraction increases the induced ack frequency to specified\n" + " fraction of CWND (default: 0)\n" " -G enable UDP generic segmentation offload\n" " -i interval interval to reissue requests (in milliseconds)\n" " -I timeout idle timeout (in milliseconds; default: 600,000)\n" @@ -1092,7 +1094,7 @@ int main(int argc, char **argv) address_token_aead.dec = ptls_aead_new(&ptls_openssl_aes128gcm, &ptls_openssl_sha256, 0, secret, ""); } - while ((ch = getopt(argc, argv, "a:b:B:c:C:Dd:k:Ee:Gi:I:K:l:M:m:NnOp:P:Rr:S:s:u:U:Vvw:W:x:X:y:h")) != -1) { + while ((ch = getopt(argc, argv, "a:b:B:c:C:Dd:k:Ee:f:Gi:I:K:l:M:m:NnOp:P:Rr:S:s:u:U:Vvw:W:x:X:y:h")) != -1) { switch (ch) { case 'a': assert(negotiated_protocols.count < PTLS_ELEMENTSOF(negotiated_protocols.list)); @@ -1154,6 +1156,14 @@ int main(int argc, char **argv) } setvbuf(quicly_trace_fp, NULL, _IONBF, 0); break; + case 'f': { + double fraction; + if (sscanf(optarg, "%lf", &fraction) != 1) { + fprintf(stderr, "failed to parse ack frequency: %s\n", optarg); + exit(1); + } + ctx.ack_frequency = (uint32_t)(fraction * 1024); + } break; case 'i': if (sscanf(optarg, "%" SCNd64, &request_interval) != 1) { fprintf(stderr, "failed to parse request interval: %s\n", optarg); From 74cbd9cfc00ada0d3f9cfd6209f1a27041bffb33 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 2 Nov 2021 17:12:20 +0900 Subject: [PATCH 175/361] set max packet tolerance to 10 (until we implement pacing) --- include/quicly/constants.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/quicly/constants.h b/include/quicly/constants.h index 6328591d8..151af360a 100644 --- a/include/quicly/constants.h +++ b/include/quicly/constants.h @@ -52,7 +52,7 @@ extern "C" { #define QUICLY_LOSS_DEFAULT_PACKET_THRESHOLD 3 #define QUICLY_DEFAULT_PACKET_TOLERANCE 2 -#define QUICLY_MAX_PACKET_TOLERANCE 100 +#define QUICLY_MAX_PACKET_TOLERANCE 10 #define QUICLY_FIRST_ACK_FREQUENCY_LOSS_EPISODE 4 #define QUICLY_AEAD_TAG_SIZE 16 From 35c6e1d72d972791db8d8671cec663fe8faf5ddd Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 2 Nov 2021 17:16:40 +0900 Subject: [PATCH 176/361] update tests --- t/test.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/test.c b/t/test.c index 85520cf07..949ae7b33 100644 --- a/t/test.c +++ b/t/test.c @@ -282,8 +282,8 @@ static void test_transport_parameters(void) 0x07, 0x04, 0x80, 0x10, 0x00, 0x00, 0x04, 0x04, 0x81, 0x00, 0x00, 0x00, 0x01, 0x04, 0x80, 0x00, 0x75, 0x30, 0x08, 0x01, 0x0a, 0x0a, 0x01, 0x0a}; memset(&decoded, 0x55, sizeof(decoded)); - ok(quicly_decode_transport_parameter_list(&decoded, NULL, NULL, NULL, NULL, valid_bytes, valid_bytes + sizeof(valid_bytes), - 1) == 0); + ok(quicly_decode_transport_parameter_list(&decoded, NULL, NULL, NULL, NULL, valid_bytes, valid_bytes + sizeof(valid_bytes)) == + 0); ok(decoded.max_stream_data.bidi_local = 0x100000); ok(decoded.max_stream_data.bidi_remote = 0x100000); ok(decoded.max_stream_data.uni = 0x100000); @@ -297,7 +297,7 @@ static void test_transport_parameters(void) static const uint8_t dup_bytes[] = {0x05, 0x04, 0x80, 0x10, 0x00, 0x00, 0x05, 0x04, 0x80, 0x10, 0x00, 0x00}; memset(&decoded, 0x55, sizeof(decoded)); - ok(quicly_decode_transport_parameter_list(&decoded, NULL, NULL, NULL, NULL, dup_bytes, dup_bytes + sizeof(dup_bytes), 1) == + ok(quicly_decode_transport_parameter_list(&decoded, NULL, NULL, NULL, NULL, dup_bytes, dup_bytes + sizeof(dup_bytes)) == QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER); } From 010812d81e416518db4675b25caa07d2c6c19cc8 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 2 Nov 2021 17:24:44 +0900 Subject: [PATCH 177/361] eBPF cannot handle bit-fields directly --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 5bb9f9c9c..bb3fe2919 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5509,7 +5509,7 @@ static int handle_ack_frequency_frame(quicly_conn_t *conn, struct st_quicly_hand return ret; QUICLY_PROBE(ACK_FREQUENCY_RECEIVE, conn, conn->stash.now, frame.sequence, frame.packet_tolerance, frame.max_ack_delay, - frame.ignore_order, frame.ignore_ce); + (int)frame.ignore_order, (int)frame.ignore_ce); /* At the moment, the only value that the remote peer would send is this value, because our TP.min_ack_delay and max_ack_delay * are equal. */ From a436673e0be9a92ca4cf8ec2c1ddb91ffcb0cb4a Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 3 Nov 2021 16:40:14 +0900 Subject: [PATCH 178/361] make reno and pico completely independent from each other --- lib/cc-pico.c | 8 ++++---- lib/cc-reno.c | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/cc-pico.c b/lib/cc-pico.c index ee21ab277..0a82f1872 100644 --- a/lib/cc-pico.c +++ b/lib/cc-pico.c @@ -52,19 +52,19 @@ static void pico_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t b if (largest_acked < cc->recovery_end) return; - cc->state.reno.stash += bytes; + cc->state.pico.stash += bytes; /* Calculate the amount of bytes required to be acked for incrementing CWND by one MTU. */ uint32_t bytes_per_mtu_increase = calc_bytes_per_mtu_increase(cc->cwnd, cc->ssthresh, loss->rtt.smoothed, max_udp_payload_size); /* Bail out if we do not yet have enough bytes being acked. */ - if (cc->state.reno.stash < bytes_per_mtu_increase) + if (cc->state.pico.stash < bytes_per_mtu_increase) return; /* Update CWND, reducing stash relative to the amount we've adjusted the CWND */ - uint32_t count = cc->state.reno.stash / bytes_per_mtu_increase; + uint32_t count = cc->state.pico.stash / bytes_per_mtu_increase; cc->cwnd += count * max_udp_payload_size; - cc->state.reno.stash -= count * bytes_per_mtu_increase; + cc->state.pico.stash -= count * bytes_per_mtu_increase; if (cc->cwnd_maximum < cc->cwnd) cc->cwnd_maximum = cc->cwnd; diff --git a/lib/cc-reno.c b/lib/cc-reno.c index 059d003d3..720a52699 100644 --- a/lib/cc-reno.c +++ b/lib/cc-reno.c @@ -96,6 +96,7 @@ static int reno_on_switch(quicly_cc_t *cc) return 1; /* nothing to do */ } else if (cc->type == &quicly_cc_type_pico) { cc->type = &quicly_cc_type_reno; + cc->state.reno.stash = cc->state.pico.stash; return 1; } else if (cc->type == &quicly_cc_type_cubic) { /* When in slow start, state can be reused as-is; otherwise, restart. */ From 7de1d620982ac090c7bb966cbab97df925a6a980 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 6 Sep 2021 18:25:59 +0900 Subject: [PATCH 179/361] redesign so that one loss recovery period would be equivalent to that of Cubic --- include/quicly/cc.h | 4 ++++ lib/cc-pico.c | 33 ++++++++++++++++++--------------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/include/quicly/cc.h b/include/quicly/cc.h index 1791f9325..ca0c0f26e 100644 --- a/include/quicly/cc.h +++ b/include/quicly/cc.h @@ -82,6 +82,10 @@ typedef struct st_quicly_cc_t { * Stash of acknowledged bytes, used during congestion avoidance. */ uint32_t stash; + /** + * Number of bytes required to be acked in order to increase CWND by 1 MTU. + */ + uint32_t bytes_per_mtu_increase; } pico; /** * State information for CUBIC congestion control. diff --git a/lib/cc-pico.c b/lib/cc-pico.c index 0a82f1872..7ee4468de 100644 --- a/lib/cc-pico.c +++ b/lib/cc-pico.c @@ -19,27 +19,21 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ +#include #include "quicly/cc.h" #include "quicly.h" /** - * Speed at which the multiplicative increase grows from BETA to 1. Unit is Hz. + * Calculates the increase ratio to be used in congestion avoidance phase. */ -#define QUICLY_PICO_MULT_HZ 1.0 - -static uint32_t calc_bytes_per_mtu_increase(uint32_t cwnd, uint32_t ssthresh, uint32_t rtt, uint32_t mtu) +static uint32_t calc_bytes_per_mtu_increase(uint32_t cwnd, uint32_t rtt, uint32_t mtu) { - /* Increase per byte acked is the sum of 1mtu/cwnd (additive part) and ... */ - double increase_per_byte = (double)mtu / cwnd; - /* ... multiplicative part being 1 during slow start, and the RTT-compensated rate for recovery within ~1/QUICLY_PICO_MULT_HZ - * seconds congestion avoidance. */ - if (cwnd < ssthresh) { - increase_per_byte += 1; - } else { - increase_per_byte += (1 / QUICLY_RENO_BETA - 1) * QUICLY_PICO_MULT_HZ / 1000 * rtt; - } + /* Reno: CWND size after reduction */ + uint32_t reno = cwnd * QUICLY_RENO_BETA; + /* Cubic: Average of `(CWND / RTT) * K / 0.3CWND`, where K and CWND have two modes due to "fast convergence." */ + uint32_t cubic = 1.447 / 0.3 * 1000 * cbrt(0.3 / 0.4 * cwnd / mtu) / rtt * mtu; - return (uint32_t)(mtu / increase_per_byte); + return reno < cubic ? reno : cubic; } /* TODO: Avoid increase if sender was application limited. */ @@ -55,7 +49,12 @@ static void pico_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t b cc->state.pico.stash += bytes; /* Calculate the amount of bytes required to be acked for incrementing CWND by one MTU. */ - uint32_t bytes_per_mtu_increase = calc_bytes_per_mtu_increase(cc->cwnd, cc->ssthresh, loss->rtt.smoothed, max_udp_payload_size); + uint32_t bytes_per_mtu_increase; + if (cc->cwnd < cc->ssthresh) { + bytes_per_mtu_increase = max_udp_payload_size; + } else { + bytes_per_mtu_increase = cc->state.pico.bytes_per_mtu_increase; + } /* Bail out if we do not yet have enough bytes being acked. */ if (cc->state.pico.stash < bytes_per_mtu_increase) @@ -82,6 +81,9 @@ static void pico_on_lost(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t by if (cc->cwnd_exiting_slow_start == 0) cc->cwnd_exiting_slow_start = cc->cwnd; + /* Calculate increase rate. */ + cc->state.pico.bytes_per_mtu_increase = calc_bytes_per_mtu_increase(cc->cwnd, loss->rtt.smoothed, max_udp_payload_size); + /* Reduce congestion window. */ cc->cwnd *= QUICLY_RENO_BETA; if (cc->cwnd < QUICLY_MIN_CWND * max_udp_payload_size) @@ -105,6 +107,7 @@ static void pico_on_sent(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t by static void pico_init_pico_state(quicly_cc_t *cc, uint32_t stash) { cc->state.pico.stash = stash; + cc->state.pico.bytes_per_mtu_increase = cc->cwnd * QUICLY_RENO_BETA; /* use Reno, for simplicity */ } static void pico_reset(quicly_cc_t *cc, uint32_t initcwnd) From 194962347115c45d4868fcc95f5ba18c184246b1 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 5 Nov 2021 09:31:33 +0900 Subject: [PATCH 180/361] do not jump accross variable declarations --- include/quicly/frame.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/quicly/frame.h b/include/quicly/frame.h index c057f757a..04afd0b7c 100644 --- a/include/quicly/frame.h +++ b/include/quicly/frame.h @@ -814,11 +814,11 @@ inline int quicly_decode_ack_frequency_frame(const uint8_t **src, const uint8_t goto Error; if (*src == end) goto Error; - uint8_t flags = *(*src)++; - if ((flags & ~QUICLY_ACK_FREQUENCY_ALL_BITS) != 0) + if ((**src & ~QUICLY_ACK_FREQUENCY_ALL_BITS) != 0) goto Error; - frame->ignore_order = (flags & QUICLY_ACK_FREQUENCY_IGNORE_ORDER_BIT) != 0; - frame->ignore_ce = (flags & QUICLY_ACK_FREQUENCY_IGNORE_CE_BIT) != 0; + frame->ignore_order = (**src & QUICLY_ACK_FREQUENCY_IGNORE_ORDER_BIT) != 0; + frame->ignore_ce = (**src & QUICLY_ACK_FREQUENCY_IGNORE_CE_BIT) != 0; + ++*src; return 0; Error: From 73b3ea5b502ace455e5a2ed896989bbb871a3aa6 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Tue, 9 Nov 2021 04:38:17 +0000 Subject: [PATCH 181/361] fix the CI badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6bfe61b96..d78e47aa3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -quicly [![Build Status](https://travis-ci.org/h2o/quicly.svg?branch=master)](https://travis-ci.org/h2o/quicly) +quicly [![CI](https://github.com/h2o/quicly/actions/workflows/ci.yml/badge.svg)](https://github.com/h2o/quicly/actions/workflows/ci.yml) === Quicly is a QUIC implementation, written from the ground up to be used within the H2O HTTP server. From 771c17b28a78c6e56a735d3281f36dda4673915e Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Tue, 9 Nov 2021 05:54:38 +0000 Subject: [PATCH 182/361] [test] make sure quicly_set_cc() sets the specified one --- t/set_cc.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++ t/test.c | 1 + t/test.h | 1 + 3 files changed, 108 insertions(+) create mode 100644 t/set_cc.c diff --git a/t/set_cc.c b/t/set_cc.c new file mode 100644 index 000000000..f3a4ae756 --- /dev/null +++ b/t/set_cc.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2017 Fastly, Kazuho Oku + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include "quicly.h" +#include "test.h" + +static void test_quicly_set_cc(void) +{ + quicly_conn_t *client, *server; + quicly_address_t dest, src; + struct iovec packets[8]; + uint8_t packetsbuf[PTLS_ELEMENTSOF(packets) * quic_ctx.transport_params.max_udp_payload_size]; + quicly_decoded_packet_t decoded[PTLS_ELEMENTSOF(packets) * 4]; + int ret; + + ret = quicly_connect(&client, &quic_ctx, "example.com", &fake_address.sa, NULL, new_master_id(), ptls_iovec_init(NULL, 0), NULL, + NULL); + ok(ret == 0); + size_t num_packets = PTLS_ELEMENTSOF(packets); + ret = quicly_send(client, &dest, &src, packets, &num_packets, packetsbuf, sizeof(packetsbuf)); + ok(ret == 0); + + size_t num_decoded = decode_packets(decoded, packets, num_packets); + ok(num_decoded == 1); + ret = quicly_accept(&server, &quic_ctx, NULL, &fake_address.sa, decoded, NULL, new_master_id(), NULL); + ok(ret == 0); + + quicly_stats_t stats; + + // init CC with pico + quicly_set_cc(server, &quicly_cc_type_pico); + ret = quicly_get_stats(server, &stats); + ok(ret == 0); + ok(strcmp(stats.cc.type->name, "pico") == 0); + + // pico to pico + quicly_set_cc(server, &quicly_cc_type_pico); + ret = quicly_get_stats(server, &stats); + ok(ret == 0); + ok(strcmp(stats.cc.type->name, "pico") == 0); + + // reno to pico + quicly_set_cc(server, &quicly_cc_type_reno); + quicly_set_cc(server, &quicly_cc_type_pico); + ret = quicly_get_stats(server, &stats); + ok(ret == 0); + ok(strcmp(stats.cc.type->name, "pico") == 0); + + // cubic to pico + quicly_set_cc(server, &quicly_cc_type_cubic); + quicly_set_cc(server, &quicly_cc_type_pico); + ret = quicly_get_stats(server, &stats); + ok(ret == 0); + ok(strcmp(stats.cc.type->name, "pico") == 0); + + // pico to reno + quicly_set_cc(server, &quicly_cc_type_pico); + quicly_set_cc(server, &quicly_cc_type_reno); + ret = quicly_get_stats(server, &stats); + ok(ret == 0); + ok(strcmp(stats.cc.type->name, "reno") == 0); + + // pico to cubic + quicly_set_cc(server, &quicly_cc_type_pico); + quicly_set_cc(server, &quicly_cc_type_cubic); + ret = quicly_get_stats(server, &stats); + ok(ret == 0); + ok(strcmp(stats.cc.type->name, "cubic") == 0); + + // reno to cubic + quicly_set_cc(server, &quicly_cc_type_reno); + quicly_set_cc(server, &quicly_cc_type_cubic); + ret = quicly_get_stats(server, &stats); + ok(ret == 0); + ok(strcmp(stats.cc.type->name, "cubic") == 0); + + // cubic to reno + quicly_set_cc(server, &quicly_cc_type_cubic); + quicly_set_cc(server, &quicly_cc_type_reno); + ret = quicly_get_stats(server, &stats); + ok(ret == 0); + ok(strcmp(stats.cc.type->name, "reno") == 0); +} + +void test_set_cc(void) +{ + subtest("quicly_set_cc", test_quicly_set_cc); +} diff --git a/t/test.c b/t/test.c index 85520cf07..a03700288 100644 --- a/t/test.c +++ b/t/test.c @@ -642,6 +642,7 @@ int main(int argc, char **argv) subtest("stream-concurrency", test_stream_concurrency); subtest("lossy", test_lossy); subtest("test-nondecryptable-initial", test_nondecryptable_initial); + subtest("set_cc", test_set_cc); return done_testing(); } diff --git a/t/test.h b/t/test.h index 6ffc482d5..c3eae755b 100644 --- a/t/test.h +++ b/t/test.h @@ -60,5 +60,6 @@ void test_stream_concurrency(void); void test_received_cid(void); void test_local_cid(void); void test_retire_cid(void); +void test_set_cc(void); #endif From cc78ce341a1374ebd038abff5fdd008fc840cad6 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Tue, 9 Nov 2021 05:55:56 +0000 Subject: [PATCH 183/361] add tests to make sure quicly_set_cc() sets the specified one --- CMakeLists.txt | 1 + t/set_cc.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8390e0fac..93b931d5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,7 @@ SET(UNITTEST_SOURCE_FILES t/sentmap.c t/simple.c t/stream-concurrency.c + t/set_cc.c t/test.c) IF (WITH_DTRACE) diff --git a/t/set_cc.c b/t/set_cc.c index f3a4ae756..706eb7367 100644 --- a/t/set_cc.c +++ b/t/set_cc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Fastly, Kazuho Oku + * Copyright (c) 2021 Fastly, Kazuho Oku, Goro Fuji. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to From aea0e2887c1d4d90edaa05124b065b8b22140e82 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Tue, 9 Nov 2021 05:56:19 +0000 Subject: [PATCH 184/361] fix pico_on_switch to set pico as CC --- lib/cc-pico.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cc-pico.c b/lib/cc-pico.c index 0a82f1872..c8b726644 100644 --- a/lib/cc-pico.c +++ b/lib/cc-pico.c @@ -125,13 +125,13 @@ static int pico_on_switch(quicly_cc_t *cc) if (cc->type == &quicly_cc_type_pico) { return 1; /* nothing to do */ } else if (cc->type == &quicly_cc_type_reno) { - cc->type = &quicly_cc_type_reno; + cc->type = &quicly_cc_type_pico; pico_init_pico_state(cc, cc->state.reno.stash); return 1; } else if (cc->type == &quicly_cc_type_cubic) { /* When in slow start, state can be reused as-is; otherwise, restart. */ if (cc->cwnd_exiting_slow_start == 0) { - cc->type = &quicly_cc_type_reno; + cc->type = &quicly_cc_type_pico; pico_init_pico_state(cc, 0); } else { pico_reset(cc, cc->cwnd_initial); From 748d0c4381d3459ac9e88cac2446960adcf4e5a2 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Wed, 10 Nov 2021 00:22:37 +0000 Subject: [PATCH 185/361] simplify the tests for quicly_set_cc --- t/set_cc.c | 60 ++++++++++++++++++++++-------------------------------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/t/set_cc.c b/t/set_cc.c index 706eb7367..681d9841c 100644 --- a/t/set_cc.c +++ b/t/set_cc.c @@ -24,78 +24,66 @@ static void test_quicly_set_cc(void) { - quicly_conn_t *client, *server; - quicly_address_t dest, src; - struct iovec packets[8]; - uint8_t packetsbuf[PTLS_ELEMENTSOF(packets) * quic_ctx.transport_params.max_udp_payload_size]; - quicly_decoded_packet_t decoded[PTLS_ELEMENTSOF(packets) * 4]; + quicly_conn_t *conn; int ret; - ret = quicly_connect(&client, &quic_ctx, "example.com", &fake_address.sa, NULL, new_master_id(), ptls_iovec_init(NULL, 0), NULL, + ret = quicly_connect(&conn, &quic_ctx, "example.com", &fake_address.sa, NULL, new_master_id(), ptls_iovec_init(NULL, 0), NULL, NULL); ok(ret == 0); - size_t num_packets = PTLS_ELEMENTSOF(packets); - ret = quicly_send(client, &dest, &src, packets, &num_packets, packetsbuf, sizeof(packetsbuf)); - ok(ret == 0); - - size_t num_decoded = decode_packets(decoded, packets, num_packets); - ok(num_decoded == 1); - ret = quicly_accept(&server, &quic_ctx, NULL, &fake_address.sa, decoded, NULL, new_master_id(), NULL); - ok(ret == 0); quicly_stats_t stats; // init CC with pico - quicly_set_cc(server, &quicly_cc_type_pico); - ret = quicly_get_stats(server, &stats); + quicly_set_cc(conn, &quicly_cc_type_pico); + ret = quicly_get_stats(conn, &stats); ok(ret == 0); ok(strcmp(stats.cc.type->name, "pico") == 0); // pico to pico - quicly_set_cc(server, &quicly_cc_type_pico); - ret = quicly_get_stats(server, &stats); + quicly_set_cc(conn, &quicly_cc_type_pico); + ret = quicly_get_stats(conn, &stats); ok(ret == 0); ok(strcmp(stats.cc.type->name, "pico") == 0); // reno to pico - quicly_set_cc(server, &quicly_cc_type_reno); - quicly_set_cc(server, &quicly_cc_type_pico); - ret = quicly_get_stats(server, &stats); + quicly_set_cc(conn, &quicly_cc_type_reno); + quicly_set_cc(conn, &quicly_cc_type_pico); + ret = quicly_get_stats(conn, &stats); ok(ret == 0); ok(strcmp(stats.cc.type->name, "pico") == 0); // cubic to pico - quicly_set_cc(server, &quicly_cc_type_cubic); - quicly_set_cc(server, &quicly_cc_type_pico); - ret = quicly_get_stats(server, &stats); + quicly_set_cc(conn, &quicly_cc_type_cubic); + quicly_set_cc(conn, &quicly_cc_type_pico); + ret = quicly_get_stats(conn, &stats); ok(ret == 0); ok(strcmp(stats.cc.type->name, "pico") == 0); // pico to reno - quicly_set_cc(server, &quicly_cc_type_pico); - quicly_set_cc(server, &quicly_cc_type_reno); - ret = quicly_get_stats(server, &stats); + quicly_set_cc(conn, &quicly_cc_type_pico); + quicly_set_cc(conn, &quicly_cc_type_reno); + ret = quicly_get_stats(conn, &stats); ok(ret == 0); ok(strcmp(stats.cc.type->name, "reno") == 0); // pico to cubic - quicly_set_cc(server, &quicly_cc_type_pico); - quicly_set_cc(server, &quicly_cc_type_cubic); - ret = quicly_get_stats(server, &stats); + quicly_set_cc(conn, &quicly_cc_type_pico); + quicly_set_cc(conn, &quicly_cc_type_cubic); + ret = quicly_get_stats(conn, &stats); ok(ret == 0); ok(strcmp(stats.cc.type->name, "cubic") == 0); // reno to cubic - quicly_set_cc(server, &quicly_cc_type_reno); - quicly_set_cc(server, &quicly_cc_type_cubic); - ret = quicly_get_stats(server, &stats); + quicly_set_cc(conn, &quicly_cc_type_reno); + quicly_set_cc(conn, &quicly_cc_type_cubic); + ret = quicly_get_stats(conn, &stats); ok(ret == 0); ok(strcmp(stats.cc.type->name, "cubic") == 0); // cubic to reno - quicly_set_cc(server, &quicly_cc_type_cubic); - quicly_set_cc(server, &quicly_cc_type_reno); - ret = quicly_get_stats(server, &stats); + quicly_set_cc(conn, &quicly_cc_type_cubic); + quicly_set_cc(conn, &quicly_cc_type_reno); + ret = quicly_get_stats(conn, &stats); ok(ret == 0); ok(strcmp(stats.cc.type->name, "reno") == 0); } From 7e56c9ebfe8aadf8f4eeff75c00ce8572ae59999 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Wed, 10 Nov 2021 00:27:09 +0000 Subject: [PATCH 186/361] move test_quicly_set_cc to test.c since it's a small feature testing --- CMakeLists.txt | 1 - t/set_cc.c | 94 -------------------------------------------------- t/test.c | 69 +++++++++++++++++++++++++++++++++++- t/test.h | 1 - 4 files changed, 68 insertions(+), 97 deletions(-) delete mode 100644 t/set_cc.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 93b931d5a..8390e0fac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,7 +80,6 @@ SET(UNITTEST_SOURCE_FILES t/sentmap.c t/simple.c t/stream-concurrency.c - t/set_cc.c t/test.c) IF (WITH_DTRACE) diff --git a/t/set_cc.c b/t/set_cc.c deleted file mode 100644 index 681d9841c..000000000 --- a/t/set_cc.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2021 Fastly, Kazuho Oku, Goro Fuji. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#include "quicly.h" -#include "test.h" - -static void test_quicly_set_cc(void) -{ - quicly_conn_t *conn; - int ret; - - ret = quicly_connect(&conn, &quic_ctx, "example.com", &fake_address.sa, NULL, new_master_id(), ptls_iovec_init(NULL, 0), NULL, - NULL); - ok(ret == 0); - - quicly_stats_t stats; - - // init CC with pico - quicly_set_cc(conn, &quicly_cc_type_pico); - ret = quicly_get_stats(conn, &stats); - ok(ret == 0); - ok(strcmp(stats.cc.type->name, "pico") == 0); - - // pico to pico - quicly_set_cc(conn, &quicly_cc_type_pico); - ret = quicly_get_stats(conn, &stats); - ok(ret == 0); - ok(strcmp(stats.cc.type->name, "pico") == 0); - - // reno to pico - quicly_set_cc(conn, &quicly_cc_type_reno); - quicly_set_cc(conn, &quicly_cc_type_pico); - ret = quicly_get_stats(conn, &stats); - ok(ret == 0); - ok(strcmp(stats.cc.type->name, "pico") == 0); - - // cubic to pico - quicly_set_cc(conn, &quicly_cc_type_cubic); - quicly_set_cc(conn, &quicly_cc_type_pico); - ret = quicly_get_stats(conn, &stats); - ok(ret == 0); - ok(strcmp(stats.cc.type->name, "pico") == 0); - - // pico to reno - quicly_set_cc(conn, &quicly_cc_type_pico); - quicly_set_cc(conn, &quicly_cc_type_reno); - ret = quicly_get_stats(conn, &stats); - ok(ret == 0); - ok(strcmp(stats.cc.type->name, "reno") == 0); - - // pico to cubic - quicly_set_cc(conn, &quicly_cc_type_pico); - quicly_set_cc(conn, &quicly_cc_type_cubic); - ret = quicly_get_stats(conn, &stats); - ok(ret == 0); - ok(strcmp(stats.cc.type->name, "cubic") == 0); - - // reno to cubic - quicly_set_cc(conn, &quicly_cc_type_reno); - quicly_set_cc(conn, &quicly_cc_type_cubic); - ret = quicly_get_stats(conn, &stats); - ok(ret == 0); - ok(strcmp(stats.cc.type->name, "cubic") == 0); - - // cubic to reno - quicly_set_cc(conn, &quicly_cc_type_cubic); - quicly_set_cc(conn, &quicly_cc_type_reno); - ret = quicly_get_stats(conn, &stats); - ok(ret == 0); - ok(strcmp(stats.cc.type->name, "reno") == 0); -} - -void test_set_cc(void) -{ - subtest("quicly_set_cc", test_quicly_set_cc); -} diff --git a/t/test.c b/t/test.c index a03700288..bca8f7244 100644 --- a/t/test.c +++ b/t/test.c @@ -569,6 +569,73 @@ static void test_nondecryptable_initial(void) #undef LEN_LOW } +static void test_quicly_set_cc(void) +{ + quicly_conn_t *conn; + int ret; + + ret = quicly_connect(&conn, &quic_ctx, "example.com", &fake_address.sa, NULL, new_master_id(), ptls_iovec_init(NULL, 0), NULL, + NULL); + ok(ret == 0); + + quicly_stats_t stats; + + // init CC with pico + quicly_set_cc(conn, &quicly_cc_type_pico); + ret = quicly_get_stats(conn, &stats); + ok(ret == 0); + ok(strcmp(stats.cc.type->name, "pico") == 0); + + // pico to pico + quicly_set_cc(conn, &quicly_cc_type_pico); + ret = quicly_get_stats(conn, &stats); + ok(ret == 0); + ok(strcmp(stats.cc.type->name, "pico") == 0); + + // reno to pico + quicly_set_cc(conn, &quicly_cc_type_reno); + quicly_set_cc(conn, &quicly_cc_type_pico); + ret = quicly_get_stats(conn, &stats); + ok(ret == 0); + ok(strcmp(stats.cc.type->name, "pico") == 0); + + // cubic to pico + quicly_set_cc(conn, &quicly_cc_type_cubic); + quicly_set_cc(conn, &quicly_cc_type_pico); + ret = quicly_get_stats(conn, &stats); + ok(ret == 0); + ok(strcmp(stats.cc.type->name, "pico") == 0); + + // pico to reno + quicly_set_cc(conn, &quicly_cc_type_pico); + quicly_set_cc(conn, &quicly_cc_type_reno); + ret = quicly_get_stats(conn, &stats); + ok(ret == 0); + ok(strcmp(stats.cc.type->name, "reno") == 0); + + // pico to cubic + quicly_set_cc(conn, &quicly_cc_type_pico); + quicly_set_cc(conn, &quicly_cc_type_cubic); + ret = quicly_get_stats(conn, &stats); + ok(ret == 0); + ok(strcmp(stats.cc.type->name, "cubic") == 0); + + // reno to cubic + quicly_set_cc(conn, &quicly_cc_type_reno); + quicly_set_cc(conn, &quicly_cc_type_cubic); + ret = quicly_get_stats(conn, &stats); + ok(ret == 0); + ok(strcmp(stats.cc.type->name, "cubic") == 0); + + // cubic to reno + quicly_set_cc(conn, &quicly_cc_type_cubic); + quicly_set_cc(conn, &quicly_cc_type_reno); + ret = quicly_get_stats(conn, &stats); + ok(ret == 0); + ok(strcmp(stats.cc.type->name, "reno") == 0); +} + + int main(int argc, char **argv) { static ptls_iovec_t cert; @@ -642,7 +709,7 @@ int main(int argc, char **argv) subtest("stream-concurrency", test_stream_concurrency); subtest("lossy", test_lossy); subtest("test-nondecryptable-initial", test_nondecryptable_initial); - subtest("set_cc", test_set_cc); + subtest("set_cc", test_quicly_set_cc); return done_testing(); } diff --git a/t/test.h b/t/test.h index c3eae755b..6ffc482d5 100644 --- a/t/test.h +++ b/t/test.h @@ -60,6 +60,5 @@ void test_stream_concurrency(void); void test_received_cid(void); void test_local_cid(void); void test_retire_cid(void); -void test_set_cc(void); #endif From b54b38dd5fb5536bc3d0bdb944686cccec8e126a Mon Sep 17 00:00:00 2001 From: FUJI Goro Date: Wed, 10 Nov 2021 10:06:17 +0900 Subject: [PATCH 187/361] Update t/test.c Co-authored-by: Kazuho Oku --- t/test.c | 1 - 1 file changed, 1 deletion(-) diff --git a/t/test.c b/t/test.c index bca8f7244..2aab6b9c2 100644 --- a/t/test.c +++ b/t/test.c @@ -635,7 +635,6 @@ static void test_quicly_set_cc(void) ok(strcmp(stats.cc.type->name, "reno") == 0); } - int main(int argc, char **argv) { static ptls_iovec_t cert; From c2450d904027e05c8ab58baf83d935931b3def7e Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Wed, 10 Nov 2021 01:07:29 +0000 Subject: [PATCH 188/361] s/test_quicly_set_cc/test_set_cc/ --- t/test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/test.c b/t/test.c index 2aab6b9c2..d5de329bc 100644 --- a/t/test.c +++ b/t/test.c @@ -569,7 +569,7 @@ static void test_nondecryptable_initial(void) #undef LEN_LOW } -static void test_quicly_set_cc(void) +static void test_set_cc(void) { quicly_conn_t *conn; int ret; @@ -708,7 +708,7 @@ int main(int argc, char **argv) subtest("stream-concurrency", test_stream_concurrency); subtest("lossy", test_lossy); subtest("test-nondecryptable-initial", test_nondecryptable_initial); - subtest("set_cc", test_quicly_set_cc); + subtest("set_cc", test_set_cc); return done_testing(); } From 8baa04f8b10b944f7062f4a579d119eacd01949b Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Tue, 30 Nov 2021 07:48:46 +0000 Subject: [PATCH 189/361] [ci] add "asan" scenario to test the project with ASan & UBSan --- .github/workflows/ci.yml | 2 ++ misc/docker-ci.mk | 11 ++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 66054df1b..fb751363f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,8 @@ jobs: include: - name: default command: make -f misc/docker-ci.mk + - name: asan + command: make -f misc/docker-ci.mk CMAKE_ENVS='CC=clang CXX=clang++ CFLAGS="-fsanitize=address,undefined" CXXFLAGS="-fsanitize=address,undefined" LDFLAGS="-fsanitize=address,undefined"' CHECK_ENVS="ASAN_OPTIONS=detect_leaks=0" timeout-minutes: 10 steps: diff --git a/misc/docker-ci.mk b/misc/docker-ci.mk index bfa116af1..cadb1ee85 100644 --- a/misc/docker-ci.mk +++ b/misc/docker-ci.mk @@ -2,12 +2,13 @@ CONTAINER_NAME=h2oserver/h2o-ci:ubuntu2004 SRC_DIR=/quicly CI_MK=$(SRC_DIR)/misc/docker-ci.mk CMAKE_ARGS= +CMAKE_ENVS= DOCKER_RUN_OPTS=--privileged \ -v `pwd`:$(SRC_DIR) \ -it ALL: - docker run $(DOCKER_RUN_OPTS) $(CONTAINER_NAME) make -f $(CI_MK) _check + docker run $(DOCKER_RUN_OPTS) $(CONTAINER_NAME) make -f $(CI_MK) _check CMAKE_ARGS='$(CMAKE_ARGS)' CMAKE_ENVS='$(CMAKE_ENVS)' CHECK_ENVS='$(CHECK_ENVS)' _check: uname -a @@ -15,9 +16,9 @@ _check: sudo mount -t tmpfs tmpfs build -o size=3G sudo chown -R ci:ci build sudo chmod 0755 build - $(MAKE) -f $(CI_MK) -C build _do-check CMAKE_ARGS=$(CMAKE_ARGS) + $(MAKE) -f $(CI_MK) -C build _do-check CMAKE_ARGS='$(CMAKE_ARGS)' CMAKE_ENVS='$(CMAKE_ENVS)' CHECK_ENVS='$(CHECK_ENVS)' _do-check: - cmake $(CMAKE_ARGS) -H$(SRC_DIR) -B. - make all - make check + env $(CMAKE_ENVS) cmake $(CMAKE_ARGS) -H$(SRC_DIR) -B. + make all VERBOSE=1 + $(CHECK_ENVS) make check From 8d85004cb5834407c5d7ff5fdedfd60433c68ddf Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Wed, 1 Dec 2021 05:20:11 +0000 Subject: [PATCH 190/361] use -DCMAKE_ params instead of env vars --- .github/workflows/ci.yml | 2 +- misc/docker-ci.mk | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb751363f..65c116c0d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: - name: default command: make -f misc/docker-ci.mk - name: asan - command: make -f misc/docker-ci.mk CMAKE_ENVS='CC=clang CXX=clang++ CFLAGS="-fsanitize=address,undefined" CXXFLAGS="-fsanitize=address,undefined" LDFLAGS="-fsanitize=address,undefined"' CHECK_ENVS="ASAN_OPTIONS=detect_leaks=0" + command: make -f misc/docker-ci.mk CMAKE_ARGS='"-DCMAKE_C_COMPILER=clang;-fsanitize=address,undefined" "-DCMAKE_CXX_COMPILER=clang++;-fsanitize=address,undefined"' CHECK_ENVS="ASAN_OPTIONS=detect_leaks=0" timeout-minutes: 10 steps: diff --git a/misc/docker-ci.mk b/misc/docker-ci.mk index cadb1ee85..1a903e3db 100644 --- a/misc/docker-ci.mk +++ b/misc/docker-ci.mk @@ -2,13 +2,12 @@ CONTAINER_NAME=h2oserver/h2o-ci:ubuntu2004 SRC_DIR=/quicly CI_MK=$(SRC_DIR)/misc/docker-ci.mk CMAKE_ARGS= -CMAKE_ENVS= DOCKER_RUN_OPTS=--privileged \ -v `pwd`:$(SRC_DIR) \ -it ALL: - docker run $(DOCKER_RUN_OPTS) $(CONTAINER_NAME) make -f $(CI_MK) _check CMAKE_ARGS='$(CMAKE_ARGS)' CMAKE_ENVS='$(CMAKE_ENVS)' CHECK_ENVS='$(CHECK_ENVS)' + docker run $(DOCKER_RUN_OPTS) $(CONTAINER_NAME) make -f $(CI_MK) _check CMAKE_ARGS='$(CMAKE_ARGS)' CHECK_ENVS='$(CHECK_ENVS)' _check: uname -a @@ -16,9 +15,9 @@ _check: sudo mount -t tmpfs tmpfs build -o size=3G sudo chown -R ci:ci build sudo chmod 0755 build - $(MAKE) -f $(CI_MK) -C build _do-check CMAKE_ARGS='$(CMAKE_ARGS)' CMAKE_ENVS='$(CMAKE_ENVS)' CHECK_ENVS='$(CHECK_ENVS)' + $(MAKE) -f $(CI_MK) -C build _do-check CMAKE_ARGS='$(CMAKE_ARGS)' CHECK_ENVS='$(CHECK_ENVS)' _do-check: - env $(CMAKE_ENVS) cmake $(CMAKE_ARGS) -H$(SRC_DIR) -B. - make all VERBOSE=1 - $(CHECK_ENVS) make check + cmake $(CMAKE_ARGS) "-H$(SRC_DIR)" -B. + $(MAKE) all VERBOSE=1 + env $(CHECK_ENVS) $(MAKE) check From b54bb24272986d6aa9fa8b68488cf25315ffaf97 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 1 Dec 2021 17:28:19 +0900 Subject: [PATCH 191/361] Request Max Ack Delay above TP.max_ack_delay is valid --- lib/quicly.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index f6d9d086b..085b74c4c 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5510,9 +5510,8 @@ static int handle_ack_frequency_frame(quicly_conn_t *conn, struct st_quicly_hand QUICLY_PROBE(ACK_FREQUENCY_RECEIVE, conn, conn->stash.now, frame.sequence, frame.packet_tolerance, frame.max_ack_delay, (int)frame.ignore_order, (int)frame.ignore_ce); - /* At the moment, the only value that the remote peer would send is this value, because our TP.min_ack_delay and max_ack_delay - * are equal. */ - if (frame.max_ack_delay != QUICLY_LOCAL_MAX_ACK_DELAY * 1000) + /* Reject Request Max Ack Delay below our TP.min_ack_delay (which is at the memoment equal to LOCAL_MAX_ACK_DELAY). */ + if (frame.max_ack_delay < QUICLY_LOCAL_MAX_ACK_DELAY * 1000) return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; if (frame.sequence >= conn->ingress.ack_frequency.next_sequence) { From 1706efc70307514b8d9fe48e1b7c8ff5d81d8a42 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Thu, 2 Dec 2021 06:49:47 +0000 Subject: [PATCH 192/361] update picotls --- deps/picotls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/picotls b/deps/picotls index 9608603a1..14ab2a977 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit 9608603a10fd0fa84da33bebf315e407274d6d9b +Subproject commit 14ab2a97722223671b0d00f29748b28c1f699271 From 2bdc5e478fbce4f75036cb12add59afa5dd722cd Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Thu, 2 Dec 2021 06:49:55 +0000 Subject: [PATCH 193/361] run with only ASan --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 65c116c0d..d30e88e40 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: - name: default command: make -f misc/docker-ci.mk - name: asan - command: make -f misc/docker-ci.mk CMAKE_ARGS='"-DCMAKE_C_COMPILER=clang;-fsanitize=address,undefined" "-DCMAKE_CXX_COMPILER=clang++;-fsanitize=address,undefined"' CHECK_ENVS="ASAN_OPTIONS=detect_leaks=0" + command: make -f misc/docker-ci.mk CMAKE_ARGS='"-DCMAKE_C_COMPILER=clang;-fsanitize=address" "-DCMAKE_CXX_COMPILER=clang++;-fsanitize=address"' CHECK_ENVS="ASAN_OPTIONS=detect_leaks=0" timeout-minutes: 10 steps: From 407979e9e340a6e6b9e313c3715738cd4896c4a4 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Thu, 2 Dec 2021 07:52:02 +0000 Subject: [PATCH 194/361] use less quotes in workflow files --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d30e88e40..467afa5be 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: - name: default command: make -f misc/docker-ci.mk - name: asan - command: make -f misc/docker-ci.mk CMAKE_ARGS='"-DCMAKE_C_COMPILER=clang;-fsanitize=address" "-DCMAKE_CXX_COMPILER=clang++;-fsanitize=address"' CHECK_ENVS="ASAN_OPTIONS=detect_leaks=0" + command: make -f misc/docker-ci.mk CMAKE_ARGS='-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_FLAGS=-fsanitize=address -DCMAKE_CXX_FLAGS=-fsanitize=address' CHECK_ENVS='ASAN_OPTIONS=detect_leaks=0' timeout-minutes: 10 steps: From 8b5b64a57b65acd26ba12c1ca9af203cdbd197ce Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Thu, 2 Dec 2021 07:52:34 +0000 Subject: [PATCH 195/361] declare vars in the makefile --- misc/docker-ci.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/misc/docker-ci.mk b/misc/docker-ci.mk index 1a903e3db..04166c8a4 100644 --- a/misc/docker-ci.mk +++ b/misc/docker-ci.mk @@ -2,6 +2,7 @@ CONTAINER_NAME=h2oserver/h2o-ci:ubuntu2004 SRC_DIR=/quicly CI_MK=$(SRC_DIR)/misc/docker-ci.mk CMAKE_ARGS= +CHECK_ENVS= DOCKER_RUN_OPTS=--privileged \ -v `pwd`:$(SRC_DIR) \ -it From 1f2f341dc6670486edc878ccba88dbc3114adf34 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 3 Dec 2021 16:40:03 +0900 Subject: [PATCH 196/361] explain the logic --- lib/cc-pico.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/cc-pico.c b/lib/cc-pico.c index 7ee4468de..629037068 100644 --- a/lib/cc-pico.c +++ b/lib/cc-pico.c @@ -30,7 +30,30 @@ static uint32_t calc_bytes_per_mtu_increase(uint32_t cwnd, uint32_t rtt, uint32_ { /* Reno: CWND size after reduction */ uint32_t reno = cwnd * QUICLY_RENO_BETA; - /* Cubic: Average of `(CWND / RTT) * K / 0.3CWND`, where K and CWND have two modes due to "fast convergence." */ + + /* Cubic: Cubic reaches original CWND (i.e., Wmax) in K seconds, therefore: + * amount_to_increase = 0.3 * Wmax + * amount_to_be_acked = K * Wmax / RTT_at_Wmax + * where + * K = (0.3 / 0.4 * Wmax / MTU)^(1/3) + * + * Hence: + * bytes_per_mtu_increase = amount_to_be_acked / amount_to_increase * MTU + * = (K * Wmax / RTT_at_Wmax) / (0.3 * Wmax) * MTU + * = K * MTU / (0.3 * RTT_at_Wmax) + * + * In addition, we have to adjust the value to take fast convergence into account. On a path with stable capacity, 50% of + * congestion events adjust Wmax to 0.85x of before calculating K. If that happens, the modified K (K') is: + * + * K' = (0.3 / 0.4 * 0.85 * Wmax / MTU)^(1/3) = 0.85^(1/3) * K + * + * where K' represents the time to reach 0.85 * Wmax. As the cubic curve is point symmetric at the point where this curve + * reaches 0.85 * Wmax, it would take 2 * K' seconds to reach Wmax. + * + * Therefore, by amortizing the two modes, the congestion period of Cubic with fast convergence is calculated as: + * + * bytes_per_mtu_increase = ((1 + 0.85^(1/3) * 2) / 2) * K * MTU / (0.3 * RTT_at_Wmax) + */ uint32_t cubic = 1.447 / 0.3 * 1000 * cbrt(0.3 / 0.4 * cwnd / mtu) / rtt * mtu; return reno < cubic ? reno : cubic; From 71ff82ec6d9074c95ad58507023b885b82cd6a82 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 3 Dec 2021 19:54:34 +0900 Subject: [PATCH 197/361] typo --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 085b74c4c..4a1178229 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5510,7 +5510,7 @@ static int handle_ack_frequency_frame(quicly_conn_t *conn, struct st_quicly_hand QUICLY_PROBE(ACK_FREQUENCY_RECEIVE, conn, conn->stash.now, frame.sequence, frame.packet_tolerance, frame.max_ack_delay, (int)frame.ignore_order, (int)frame.ignore_ce); - /* Reject Request Max Ack Delay below our TP.min_ack_delay (which is at the memoment equal to LOCAL_MAX_ACK_DELAY). */ + /* Reject Request Max Ack Delay below our TP.min_ack_delay (which is at the moment equal to LOCAL_MAX_ACK_DELAY). */ if (frame.max_ack_delay < QUICLY_LOCAL_MAX_ACK_DELAY * 1000) return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; From 7817893ddbba10f38ef7b5fc4db1ebe3e06a5a3c Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sat, 4 Dec 2021 19:32:06 +0900 Subject: [PATCH 198/361] [refactor] reduce the number of variables --- lib/quicly.c | 57 +++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 4a1178229..715ea7096 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3543,22 +3543,22 @@ int quicly_can_send_data(quicly_conn_t *conn, quicly_send_context_t *s) int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) { - uint64_t off = stream->sendstate.pending.ranges[0].start, end_off; + uint64_t off = stream->sendstate.pending.ranges[0].start; quicly_sent_t *sent; uint8_t *frame_type_at; - size_t capacity, len; + size_t len; int ret, wrote_all, is_fin; - /* write frame type, stream_id and offset, calculate capacity */ + /* write frame type, stream_id and offset, calculate capacity (and store that in `len`) */ if (stream->stream_id < 0) { if ((ret = allocate_ack_eliciting_frame(stream->conn, s, - 1 + quicly_encodev_capacity(off) + 2 /* type + len + offset + 1-byte payload */, + 1 + quicly_encodev_capacity(off) + 2 /* type + offset + len + 1-byte payload */, &sent, on_ack_stream)) != 0) return ret; frame_type_at = NULL; *s->dst++ = QUICLY_FRAME_TYPE_CRYPTO; s->dst = quicly_encodev(s->dst, off); - capacity = s->dst_end - s->dst; + len = s->dst_end - s->dst; } else { uint8_t header[18], *hp = header + 1; hp = quicly_encodev(hp, stream->stream_id); @@ -3579,7 +3579,7 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) } memcpy(s->dst, header, hp - header); s->dst += hp - header; - end_off = off; + len = 0; wrote_all = 1; is_fin = 1; goto UpdateState; @@ -3589,33 +3589,32 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) frame_type_at = s->dst; memcpy(s->dst, header, hp - header); s->dst += hp - header; - capacity = s->dst_end - s->dst; + len = s->dst_end - s->dst; /* cap by max_stream_data */ - if (off + capacity > stream->_send_aux.max_stream_data) - capacity = stream->_send_aux.max_stream_data - off; + if (off + len > stream->_send_aux.max_stream_data) + len = stream->_send_aux.max_stream_data - off; /* cap by max_data */ - if (off + capacity > stream->sendstate.size_inflight) { - uint64_t new_bytes = off + capacity - stream->sendstate.size_inflight; + if (off + len > stream->sendstate.size_inflight) { + uint64_t new_bytes = off + len - stream->sendstate.size_inflight; if (new_bytes > stream->conn->egress.max_data.permitted - stream->conn->egress.max_data.sent) { size_t max_stream_data = stream->sendstate.size_inflight + stream->conn->egress.max_data.permitted - stream->conn->egress.max_data.sent; - capacity = max_stream_data - off; + len = max_stream_data - off; } } } - { /* cap the capacity to the current range */ + { /* cap len to the current range */ uint64_t range_capacity = stream->sendstate.pending.ranges[0].end - off; if (!quicly_sendstate_is_open(&stream->sendstate) && off + range_capacity > stream->sendstate.final_size) { assert(range_capacity > 1); /* see the special case above */ range_capacity -= 1; } - if (capacity > range_capacity) - capacity = range_capacity; + if (len > range_capacity) + len = range_capacity; } - /* write payload */ - assert(capacity != 0); - len = capacity; + /* write payload, adjusting len to actual size */ + assert(len != 0); size_t emit_off = (size_t)(off - stream->sendstate.acked.ranges[0].end); QUICLY_PROBE(STREAM_ON_SEND_EMIT, stream->conn, stream->conn->stash.now, stream, emit_off, len); stream->callbacks->on_send_emit(stream, emit_off, s->dst, &len, &wrote_all); @@ -3624,7 +3623,6 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) } else if (stream->_send_aux.reset_stream.sender_state != QUICLY_SENDER_STATE_NONE) { return 0; } - assert(len <= capacity); assert(len != 0); /* update s->dst, insert length if necessary */ @@ -3640,10 +3638,9 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) s->dst = quicly_encodev(s->dst, len); } s->dst += len; - end_off = off + len; /* determine if the frame incorporates FIN */ - if (!quicly_sendstate_is_open(&stream->sendstate) && end_off == stream->sendstate.final_size) { + if (!quicly_sendstate_is_open(&stream->sendstate) && off + len == stream->sendstate.final_size) { assert(frame_type_at != NULL); is_fin = 1; *frame_type_at |= QUICLY_FRAME_TYPE_STREAM_BIT_FIN; @@ -3657,19 +3654,19 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) } else { ++stream->conn->super.stats.num_frames_sent.stream; } - stream->conn->super.stats.num_bytes.stream_data_sent += end_off - off; + stream->conn->super.stats.num_bytes.stream_data_sent += len; if (off < stream->sendstate.size_inflight) stream->conn->super.stats.num_bytes.stream_data_resent += - (stream->sendstate.size_inflight < end_off ? stream->sendstate.size_inflight : end_off) - off; - QUICLY_PROBE(STREAM_SEND, stream->conn, stream->conn->stash.now, stream, off, end_off - off, is_fin); - QUICLY_PROBE(QUICTRACE_SEND_STREAM, stream->conn, stream->conn->stash.now, stream, off, end_off - off, is_fin); + (stream->sendstate.size_inflight < off + len ? stream->sendstate.size_inflight : off + len) - off; + QUICLY_PROBE(STREAM_SEND, stream->conn, stream->conn->stash.now, stream, off, len, is_fin); + QUICLY_PROBE(QUICTRACE_SEND_STREAM, stream->conn, stream->conn->stash.now, stream, off, len, is_fin); /* update sendstate (and also MAX_DATA counter) */ - if (stream->sendstate.size_inflight < end_off) { + if (stream->sendstate.size_inflight < off + len) { if (stream->stream_id >= 0) - stream->conn->egress.max_data.sent += end_off - stream->sendstate.size_inflight; - stream->sendstate.size_inflight = end_off; + stream->conn->egress.max_data.sent += off + len - stream->sendstate.size_inflight; + stream->sendstate.size_inflight = off + len; } - if ((ret = quicly_ranges_subtract(&stream->sendstate.pending, off, end_off + is_fin)) != 0) + if ((ret = quicly_ranges_subtract(&stream->sendstate.pending, off, off + len + is_fin)) != 0) return ret; if (wrote_all) { if ((ret = quicly_ranges_subtract(&stream->sendstate.pending, stream->sendstate.size_inflight, UINT64_MAX)) != 0) @@ -3679,7 +3676,7 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) /* setup sentmap */ sent->data.stream.stream_id = stream->stream_id; sent->data.stream.args.start = off; - sent->data.stream.args.end = end_off + is_fin; + sent->data.stream.args.end = off + len + is_fin; return 0; } From 64f61bc06ac4078a76eadaa16b11abad95a71607 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sun, 5 Dec 2021 13:39:34 +0900 Subject: [PATCH 199/361] prepend PADDINGs if STREAM cannot be converted to length form, rather than shortning it --- lib/quicly.c | 52 ++++++++++++++++++++++++++++++----------- t/test.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 13 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 715ea7096..9acab9840 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3541,6 +3541,44 @@ int quicly_can_send_data(quicly_conn_t *conn, quicly_send_context_t *s) return s->num_datagrams < s->max_datagrams; } +/** + * If necessary, changes the frame representation from one without length field to one that has if necessary. Or, as an alternaive, + * prepends PADDING frames. Upon return, `dst` points to the end of the frame being built. `*len`, `*wrote_all`, `*frame_type_at` + * are also updated reflecting their values post-adjustment. + */ +static inline void adjust_stream_frame_layout(uint8_t **dst, uint8_t *const dst_end, size_t *len, int *wrote_all, + uint8_t **frame_type_at) +{ + size_t space_left = (dst_end - *dst) - *len, len_of_len = quicly_encodev_capacity(*len); + + if (*frame_type_at != NULL) { + /* STREAM frame: insert length if space can be left for more frames. Otherwise, retain STREAM frame header omitting the + * lengh field, prepending PADDING if necessary. */ + if (space_left <= len_of_len) { + if (space_left != 0) { + memmove(*frame_type_at + space_left, *frame_type_at, *dst + *len - *frame_type_at); + memset(*frame_type_at, QUICLY_FRAME_TYPE_PADDING, space_left); + *dst += space_left; + *frame_type_at += space_left; + } + *dst += *len; + return; + } + **frame_type_at |= QUICLY_FRAME_TYPE_STREAM_BIT_LEN; + } else { + /* CRYPTO frame: adjust payload length to make space for the length field, if necessary. */ + if (space_left < len_of_len) { + *len = dst_end - *dst - len_of_len; + *wrote_all = 0; + } + } + + /* insert length before payload of `*len` bytes */ + memmove(*dst + len_of_len, *dst, *len); + *dst = quicly_encodev(*dst, *len); + *dst += *len; +} + int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) { uint64_t off = stream->sendstate.pending.ranges[0].start; @@ -3625,19 +3663,7 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) } assert(len != 0); - /* update s->dst, insert length if necessary */ - if (frame_type_at == NULL || len < s->dst_end - s->dst) { - if (frame_type_at != NULL) - *frame_type_at |= QUICLY_FRAME_TYPE_STREAM_BIT_LEN; - size_t len_of_len = quicly_encodev_capacity(len); - if (len_of_len + len > s->dst_end - s->dst) { - len = s->dst_end - s->dst - len_of_len; - wrote_all = 0; - } - memmove(s->dst + len_of_len, s->dst, len); - s->dst = quicly_encodev(s->dst, len); - } - s->dst += len; + adjust_stream_frame_layout(&s->dst, s->dst_end, &len, &wrote_all, &frame_type_at); /* determine if the frame incorporates FIN */ if (!quicly_sendstate_is_open(&stream->sendstate) && off + len == stream->sendstate.final_size) { diff --git a/t/test.c b/t/test.c index 6afa14052..4467f1ddf 100644 --- a/t/test.c +++ b/t/test.c @@ -98,6 +98,70 @@ quicly_stream_callbacks_t stream_callbacks = { on_destroy, quicly_streambuf_egress_shift, quicly_streambuf_egress_emit, on_egress_stop, on_ingress_receive, on_ingress_reset}; size_t on_destroy_callcnt; +static void test_adjust_stream_frame_layout(void) +{ +#define TEST(_is_crypto, _capacity, check) \ + do { \ + uint8_t buf[] = {0xff, 0x04, 'h', 'e', 'l', 'l', 'o', 0, 0, 0}; \ + uint8_t *dst = buf + 2, *const dst_end = buf + _capacity, *frame_type_at = _is_crypto ? NULL : buf; \ + size_t len = 5; \ + int wrote_all = 1; \ + buf[0] = _is_crypto ? 0x06 : 0x08; \ + adjust_stream_frame_layout(&dst, dst_end, &len, &wrote_all, &frame_type_at); \ + do { \ + check \ + } while (0); \ + } while (0); + + /* test CRYPTO frames that fit and don't when length is inserted */ + TEST(1, 10, { + ok(dst == buf + 8); + ok(len == 5); + ok(wrote_all); + ok(frame_type_at == NULL); + ok(memcmp(buf, "\x06\x04\x05hello", 8) == 0); + }); + TEST(1, 8, { + ok(dst == buf + 8); + ok(len == 5); + ok(wrote_all); + ok(frame_type_at == NULL); + ok(memcmp(buf, "\x06\x04\x05hello", 8) == 0); + }); + TEST(1, 7, { + ok(dst == buf + 7); + ok(len == 4); + ok(!wrote_all); + ok(frame_type_at == NULL); + ok(memcmp(buf, "\x06\x04\x04hell", 7) == 0); + }); + + /* test STREAM frames */ + TEST(0, 9, { + ok(dst == buf + 8); + ok(len == 5); + ok(wrote_all); + ok(frame_type_at == buf); + ok(memcmp(buf, "\x0a\x04\x05hello", 8) == 0); + }); + TEST(0, 8, { + ok(dst == buf + 8); + ok(len == 5); + ok(wrote_all); + ok(frame_type_at == buf + 1); + ok(memcmp(buf, "\x00\x08\x04hello", 8) == 0); + }); + TEST(0, 7, { + ok(dst == buf + 7); + ok(len == 5); + ok(wrote_all); + ok(frame_type_at == buf); + ok(memcmp(buf, "\x08\x04hello", 7) == 0); + }); + +#undef TEST +} + static int64_t get_now_cb(quicly_now_t *self) { return quic_now; @@ -700,6 +764,7 @@ int main(int argc, char **argv) subtest("maxsender", test_maxsender); subtest("sentmap", test_sentmap); subtest("loss", test_loss); + subtest("adjust-stream-frame-layout", test_adjust_stream_frame_layout); subtest("test-vector", test_vector); subtest("test-retry-aead", test_retry_aead); subtest("transport-parameters", test_transport_parameters); From 1273f394a9e9ae882a66b230e91d44dfa8e8de3e Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sun, 5 Dec 2021 14:08:07 +0900 Subject: [PATCH 200/361] convert verbose checks to asserts; final_size is guaranteed to be greater than any other uint64_t value while the stream is open --- lib/quicly.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 9acab9840..f9e639285 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3606,7 +3606,8 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) } else { header[0] = QUICLY_FRAME_TYPE_STREAM_BASE; } - if (!quicly_sendstate_is_open(&stream->sendstate) && off == stream->sendstate.final_size) { + if (off == stream->sendstate.final_size) { + assert(!quicly_sendstate_is_open(&stream->sendstate)); /* special case for emitting FIN only */ header[0] |= QUICLY_FRAME_TYPE_STREAM_BIT_FIN; if ((ret = allocate_ack_eliciting_frame(stream->conn, s, hp - header, &sent, on_ack_stream)) != 0) @@ -3643,7 +3644,8 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) } { /* cap len to the current range */ uint64_t range_capacity = stream->sendstate.pending.ranges[0].end - off; - if (!quicly_sendstate_is_open(&stream->sendstate) && off + range_capacity > stream->sendstate.final_size) { + if (off + range_capacity > stream->sendstate.final_size) { + assert(!quicly_sendstate_is_open(&stream->sendstate)); assert(range_capacity > 1); /* see the special case above */ range_capacity -= 1; } @@ -3666,7 +3668,8 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) adjust_stream_frame_layout(&s->dst, s->dst_end, &len, &wrote_all, &frame_type_at); /* determine if the frame incorporates FIN */ - if (!quicly_sendstate_is_open(&stream->sendstate) && off + len == stream->sendstate.final_size) { + if (off + len == stream->sendstate.final_size) { + assert(!quicly_sendstate_is_open(&stream->sendstate)); assert(frame_type_at != NULL); is_fin = 1; *frame_type_at |= QUICLY_FRAME_TYPE_STREAM_BIT_FIN; From de43fa3ecb9967db54238beb06103e90c715af9c Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 6 Dec 2021 15:26:14 +0900 Subject: [PATCH 201/361] do not send corrupt STREAM frame when application fails in `on_send_emit` --- lib/quicly.c | 58 +++++++++++++++++++++++++++++----------------------- t/test.c | 16 +++++++-------- 2 files changed, 40 insertions(+), 34 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index f9e639285..188afa73e 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3547,30 +3547,30 @@ int quicly_can_send_data(quicly_conn_t *conn, quicly_send_context_t *s) * are also updated reflecting their values post-adjustment. */ static inline void adjust_stream_frame_layout(uint8_t **dst, uint8_t *const dst_end, size_t *len, int *wrote_all, - uint8_t **frame_type_at) + uint8_t **frame_at) { size_t space_left = (dst_end - *dst) - *len, len_of_len = quicly_encodev_capacity(*len); - if (*frame_type_at != NULL) { + if (**frame_at == QUICLY_FRAME_TYPE_CRYPTO) { + /* CRYPTO frame: adjust payload length to make space for the length field, if necessary. */ + if (space_left < len_of_len) { + *len = dst_end - *dst - len_of_len; + *wrote_all = 0; + } + } else { /* STREAM frame: insert length if space can be left for more frames. Otherwise, retain STREAM frame header omitting the * lengh field, prepending PADDING if necessary. */ if (space_left <= len_of_len) { if (space_left != 0) { - memmove(*frame_type_at + space_left, *frame_type_at, *dst + *len - *frame_type_at); - memset(*frame_type_at, QUICLY_FRAME_TYPE_PADDING, space_left); + memmove(*frame_at + space_left, *frame_at, *dst + *len - *frame_at); + memset(*frame_at, QUICLY_FRAME_TYPE_PADDING, space_left); *dst += space_left; - *frame_type_at += space_left; + *frame_at += space_left; } *dst += *len; return; } - **frame_type_at |= QUICLY_FRAME_TYPE_STREAM_BIT_LEN; - } else { - /* CRYPTO frame: adjust payload length to make space for the length field, if necessary. */ - if (space_left < len_of_len) { - *len = dst_end - *dst - len_of_len; - *wrote_all = 0; - } + **frame_at |= QUICLY_FRAME_TYPE_STREAM_BIT_LEN; } /* insert length before payload of `*len` bytes */ @@ -3583,7 +3583,8 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) { uint64_t off = stream->sendstate.pending.ranges[0].start; quicly_sent_t *sent; - uint8_t *frame_type_at; + uint8_t *dst; /* points to the current write position within the frame being built, while `s->dst` points to the beginning of + * the frame. */ size_t len; int ret, wrote_all, is_fin; @@ -3593,10 +3594,10 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) 1 + quicly_encodev_capacity(off) + 2 /* type + offset + len + 1-byte payload */, &sent, on_ack_stream)) != 0) return ret; - frame_type_at = NULL; - *s->dst++ = QUICLY_FRAME_TYPE_CRYPTO; - s->dst = quicly_encodev(s->dst, off); - len = s->dst_end - s->dst; + dst = s->dst; + *dst++ = QUICLY_FRAME_TYPE_CRYPTO; + dst = quicly_encodev(dst, off); + len = s->dst_end - dst; } else { uint8_t header[18], *hp = header + 1; hp = quicly_encodev(hp, stream->stream_id); @@ -3625,10 +3626,10 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) } if ((ret = allocate_ack_eliciting_frame(stream->conn, s, hp - header + 1, &sent, on_ack_stream)) != 0) return ret; - frame_type_at = s->dst; - memcpy(s->dst, header, hp - header); - s->dst += hp - header; - len = s->dst_end - s->dst; + dst = s->dst; + memcpy(dst, header, hp - header); + dst += hp - header; + len = s->dst_end - dst; /* cap by max_stream_data */ if (off + len > stream->_send_aux.max_stream_data) len = stream->_send_aux.max_stream_data - off; @@ -3653,11 +3654,13 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) len = range_capacity; } - /* write payload, adjusting len to actual size */ + /* Write payload, adjusting len to actual size. Note that `on_send_emit` might fail (e.g., when underlying pread(2) fails), in + * which case the application will either close the connection immediately or reset the stream. If that happens, we return + * immediately without updating state. */ assert(len != 0); size_t emit_off = (size_t)(off - stream->sendstate.acked.ranges[0].end); QUICLY_PROBE(STREAM_ON_SEND_EMIT, stream->conn, stream->conn->stash.now, stream, emit_off, len); - stream->callbacks->on_send_emit(stream, emit_off, s->dst, &len, &wrote_all); + stream->callbacks->on_send_emit(stream, emit_off, dst, &len, &wrote_all); if (stream->conn->super.state >= QUICLY_STATE_CLOSING) { return QUICLY_ERROR_IS_CLOSING; } else if (stream->_send_aux.reset_stream.sender_state != QUICLY_SENDER_STATE_NONE) { @@ -3665,18 +3668,21 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) } assert(len != 0); - adjust_stream_frame_layout(&s->dst, s->dst_end, &len, &wrote_all, &frame_type_at); + adjust_stream_frame_layout(&dst, s->dst_end, &len, &wrote_all, &s->dst); /* determine if the frame incorporates FIN */ if (off + len == stream->sendstate.final_size) { assert(!quicly_sendstate_is_open(&stream->sendstate)); - assert(frame_type_at != NULL); + assert(s->dst != NULL); is_fin = 1; - *frame_type_at |= QUICLY_FRAME_TYPE_STREAM_BIT_FIN; + *s->dst |= QUICLY_FRAME_TYPE_STREAM_BIT_FIN; } else { is_fin = 0; } + /* update s->dst now that frame construction is complete */ + s->dst = dst; + UpdateState: if (stream->stream_id < 0) { ++stream->conn->super.stats.num_frames_sent.crypto; diff --git a/t/test.c b/t/test.c index 4467f1ddf..9340665a5 100644 --- a/t/test.c +++ b/t/test.c @@ -103,11 +103,11 @@ static void test_adjust_stream_frame_layout(void) #define TEST(_is_crypto, _capacity, check) \ do { \ uint8_t buf[] = {0xff, 0x04, 'h', 'e', 'l', 'l', 'o', 0, 0, 0}; \ - uint8_t *dst = buf + 2, *const dst_end = buf + _capacity, *frame_type_at = _is_crypto ? NULL : buf; \ + uint8_t *dst = buf + 2, *const dst_end = buf + _capacity, *frame_at = buf; \ size_t len = 5; \ int wrote_all = 1; \ buf[0] = _is_crypto ? 0x06 : 0x08; \ - adjust_stream_frame_layout(&dst, dst_end, &len, &wrote_all, &frame_type_at); \ + adjust_stream_frame_layout(&dst, dst_end, &len, &wrote_all, &frame_at); \ do { \ check \ } while (0); \ @@ -118,21 +118,21 @@ static void test_adjust_stream_frame_layout(void) ok(dst == buf + 8); ok(len == 5); ok(wrote_all); - ok(frame_type_at == NULL); + ok(frame_at == buf); ok(memcmp(buf, "\x06\x04\x05hello", 8) == 0); }); TEST(1, 8, { ok(dst == buf + 8); ok(len == 5); ok(wrote_all); - ok(frame_type_at == NULL); + ok(frame_at == buf); ok(memcmp(buf, "\x06\x04\x05hello", 8) == 0); }); TEST(1, 7, { ok(dst == buf + 7); ok(len == 4); ok(!wrote_all); - ok(frame_type_at == NULL); + ok(frame_at == buf); ok(memcmp(buf, "\x06\x04\x04hell", 7) == 0); }); @@ -141,21 +141,21 @@ static void test_adjust_stream_frame_layout(void) ok(dst == buf + 8); ok(len == 5); ok(wrote_all); - ok(frame_type_at == buf); + ok(frame_at == buf); ok(memcmp(buf, "\x0a\x04\x05hello", 8) == 0); }); TEST(0, 8, { ok(dst == buf + 8); ok(len == 5); ok(wrote_all); - ok(frame_type_at == buf + 1); + ok(frame_at == buf + 1); ok(memcmp(buf, "\x00\x08\x04hello", 8) == 0); }); TEST(0, 7, { ok(dst == buf + 7); ok(len == 5); ok(wrote_all); - ok(frame_type_at == buf); + ok(frame_at == buf); ok(memcmp(buf, "\x08\x04hello", 7) == 0); }); From 728155d592d2a81d7bfd9da2deae78c03930214f Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 6 Dec 2021 15:30:26 +0900 Subject: [PATCH 202/361] editorial --- lib/quicly.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 188afa73e..13113aa88 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3583,8 +3583,8 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) { uint64_t off = stream->sendstate.pending.ranges[0].start; quicly_sent_t *sent; - uint8_t *dst; /* points to the current write position within the frame being built, while `s->dst` points to the beginning of - * the frame. */ + uint8_t *dst; /* this pointer points to the current write position within the frame being built, while `s->dst` points to the + * beginning of the frame. */ size_t len; int ret, wrote_all, is_fin; From 2153643cadc731831708ae0b84d3266d88622a1f Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 13 Dec 2021 10:40:34 +0900 Subject: [PATCH 203/361] remove excess `*` from doc-comment --- include/quicly.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index 2431acf79..ef6253cdd 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -277,8 +277,8 @@ struct st_quicly_context_t { ptls_context_t *tls; /** * Maximum size of packets that we are willing to send when path-specific information is unavailable. As a path-specific - * * optimization, quicly acting as a server expands this value to `min(local.tp.max_udp_payload_size, - * * remote.tp.max_udp_payload_size, max_size_of_incoming_datagrams)` when it receives the Transport Parameters from the client. + * optimization, quicly acting as a server expands this value to `min(local.tp.max_udp_payload_size, + * remote.tp.max_udp_payload_size, max_size_of_incoming_datagrams)` when it receives the Transport Parameters from the client. */ uint16_t initial_egress_max_udp_payload_size; /** From 62bc21e7048a605e57a2df19a4e9db64e0317844 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 13 Dec 2021 16:36:36 +0900 Subject: [PATCH 204/361] update min CMake version to 2.8.12 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8390e0fac..2b6379588 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12) CMAKE_POLICY(SET CMP0003 NEW) PROJECT(quicly) From 32b506080de1ed4f2726a8793f3b08a1976a7361 Mon Sep 17 00:00:00 2001 From: Emmanuel Thompson Date: Mon, 20 Dec 2021 11:31:58 -0500 Subject: [PATCH 205/361] remove QUICLY_DEBUG blocks These are no longer in use --- include/quicly.h | 4 ---- lib/defaults.c | 7 ------- lib/quicly.c | 12 ------------ 3 files changed, 23 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index ef6253cdd..0cf41ed2e 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -46,10 +46,6 @@ extern "C" { #include "quicly/cid.h" #include "quicly/remote_cid.h" -#ifndef QUICLY_DEBUG -#define QUICLY_DEBUG 0 -#endif - /* invariants! */ #define QUICLY_LONG_HEADER_BIT 0x80 #define QUICLY_QUIC_BIT 0x40 diff --git a/lib/defaults.c b/lib/defaults.c index 6b7b3ebbc..fdf754bc1 100644 --- a/lib/defaults.c +++ b/lib/defaults.c @@ -398,13 +398,6 @@ static int default_setup_cipher(quicly_crypto_engine_t *engine, quicly_conn_t *c ret = PTLS_ERROR_NO_MEMORY; goto Exit; } - if (QUICLY_DEBUG) { - char *secret_hex = quicly_hexdump(secret, hash->digest_size, SIZE_MAX), - *hpkey_hex = quicly_hexdump(hpkey, aead->ctr_cipher->key_size, SIZE_MAX); - fprintf(stderr, "%s:\n aead-secret: %s\n hp-key: %s\n", __FUNCTION__, secret_hex, hpkey_hex); - free(secret_hex); - free(hpkey_hex); - } ret = 0; Exit: diff --git a/lib/quicly.c b/lib/quicly.c index 13113aa88..a0a952c7d 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -2490,8 +2490,6 @@ static int do_decrypt_packet(ptls_cipher_context_t *header_protection, /* AEAD decryption */ if ((ret = (*aead_cb)(aead_ctx, *pn, packet, aead_off, &ptlen)) != 0) { - if (QUICLY_DEBUG) - fprintf(stderr, "%s: aead decryption failure (pn: %" PRIu64 ",code:%d)\n", __FUNCTION__, *pn, ret); return ret; } if (*next_expected_pn <= *pn) @@ -2529,22 +2527,12 @@ static int decrypt_packet(ptls_cipher_context_t *header_protection, if ((packet->octets.base[0] & (QUICLY_PACKET_IS_LONG_HEADER(packet->octets.base[0]) ? QUICLY_LONG_HEADER_RESERVED_BITS : QUICLY_SHORT_HEADER_RESERVED_BITS)) != 0) { - if (QUICLY_DEBUG) - fprintf(stderr, "%s: non-zero reserved bits (pn: %" PRIu64 ")\n", __FUNCTION__, *pn); return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; } if (payload->len == 0) { - if (QUICLY_DEBUG) - fprintf(stderr, "%s: payload length is zero (pn: %" PRIu64 ")\n", __FUNCTION__, *pn); return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; } - if (QUICLY_DEBUG) { - char *payload_hex = quicly_hexdump(payload->base, payload->len, 4); - fprintf(stderr, "%s: AEAD payload:\n%s", __FUNCTION__, payload_hex); - free(payload_hex); - } - return 0; } From 54600fdd6c75638b245b39383d33112e995dcd54 Mon Sep 17 00:00:00 2001 From: Emmanuel Thompson Date: Mon, 28 Feb 2022 11:07:26 -0500 Subject: [PATCH 206/361] change alpn from hq-29 to hq-interop --- misc/quic-interop-runner/run_endpoint.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/misc/quic-interop-runner/run_endpoint.sh b/misc/quic-interop-runner/run_endpoint.sh index 2c8af397f..e92c012a5 100755 --- a/misc/quic-interop-runner/run_endpoint.sh +++ b/misc/quic-interop-runner/run_endpoint.sh @@ -36,25 +36,25 @@ if [ "$ROLE" == "client" ]; then # Client needs to be run twice. First, with one request. FILE=`echo $FILES | cut -f1 -d" "` echo "/quicly/cli -P /$FILE $SERVER 443" - /quicly/cli -P "/"$FILE $TEST_PARAMS -a "hq-29" -x x25519 -x secp256r1 -e /logs/$TESTCASE.out $SERVER 443 + /quicly/cli -P "/"$FILE $TEST_PARAMS -a "hq-interop" -x x25519 -x secp256r1 -e /logs/$TESTCASE.out $SERVER 443 # Second time, with rest of the requests. CLI_LIST=`echo $CLI_LIST | cut -f3- -d" "` echo "/quicly/cli $CLI_LIST $SERVER 443" - /quicly/cli $CLI_LIST $TEST_PARAMS -a "hq-29" -x x25519 -x secp256r1 -e /logs/$TESTCASE.out $SERVER 443 + /quicly/cli $CLI_LIST $TEST_PARAMS -a "hq-interop" -x x25519 -x secp256r1 -e /logs/$TESTCASE.out $SERVER 443 rm -f previous_sessions.bin elif [ "$TESTCASE" == "multiconnect" ]; then # Client needs to be run once per file. for FILE in $FILES; do echo "/quicly/cli /$FILE $SERVER 443" - /quicly/cli -P "/"$FILE $TEST_PARAMS -a "hq-29" -x x25519 -x secp256r1 -e /logs/$TESTCASE.out $SERVER 443 + /quicly/cli -P "/"$FILE $TEST_PARAMS -a "hq-interop" -x x25519 -x secp256r1 -e /logs/$TESTCASE.out $SERVER 443 done else # Client is run once for all files. echo "/quicly/cli $CLI_LIST $SERVER 443" - /quicly/cli $CLI_LIST $TEST_PARAMS -a "hq-29" -x x25519 -x secp256r1 -e /logs/$TESTCASE.out $SERVER 443 + /quicly/cli $CLI_LIST $TEST_PARAMS -a "hq-interop" -x x25519 -x secp256r1 -e /logs/$TESTCASE.out $SERVER 443 fi # Cleanup. @@ -75,5 +75,5 @@ elif [ "$ROLE" == "server" ]; then echo "Starting quicly server ..." echo "SERVER_PARAMS:" $SERVER_PARAMS "TEST_PARAMS:" $TEST_PARAMS echo "/quicly/cli $SERVER_PARAMS $TEST_PARAMS -k /certs/priv.key -c /certs/cert.pem -e /logs/$TESTCASE.out 0.0.0.0 443" - /quicly/cli $SERVER_PARAMS $TEST_PARAMS -k /certs/priv.key -c /certs/cert.pem -x x25519 -x secp256r1 -a "hq-29" -e /logs/$TESTCASE.out 0.0.0.0 443 + /quicly/cli $SERVER_PARAMS $TEST_PARAMS -k /certs/priv.key -c /certs/cert.pem -x x25519 -x secp256r1 -a "hq-interop" -e /logs/$TESTCASE.out 0.0.0.0 443 fi From f4be523d6c35f920ed41c9ca3d0033db4dd3a17f Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Fri, 18 Mar 2022 18:15:28 +0000 Subject: [PATCH 207/361] qlog-adapter: accept stdin It would be natural for this type of tool to be used like ``` cmd-emits-h2olog | qlog-adapter.py > qlog-file ``` This patch modifies qlog-adapter's behavior so that if an input file name is omitted, it reads input from stdin. --- misc/qlog-adapter.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index dbcd4cf5f..da45f0b4f 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -328,22 +328,32 @@ def render_ack_frame(ranges): def usage(): print(r""" Usage: - python qlog-adapter.py inTrace.jsonl + python qlog-adapter.py [inTrace.jsonl] + + If the argument is omitted, inTrace will be read from stdin. """.strip()) def load_quicly_events(infile): events = [] - with open(infile, "r") as fh: - for line in fh: - events.append(json.loads(line)) + for line in infile: + events.append(json.loads(line)) return events def main(): - if len(sys.argv) != 2: + if len(sys.argv) > 2: usage() sys.exit(1) - (_, infile) = sys.argv + if len(sys.argv) == 1: + infile = sys.stdin + else: + (_, fn) = sys.argv + try: + infile = open(fn, "r") + except OSError as e: + print("Failed to open %s: %s" % (fn, e.strerror)) + sys.exit(1) + source_events = load_quicly_events(infile) print(json.dumps({ "qlog_format": "NDJSON", From 987b29df6841338c8d27eb85273e4bfa104cee35 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Fri, 18 Mar 2022 18:21:42 +0000 Subject: [PATCH 208/361] qlog-adapter: Python 3 is required to run this code --- misc/qlog-adapter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index da45f0b4f..2b4898ffb 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -328,7 +328,7 @@ def render_ack_frame(ranges): def usage(): print(r""" Usage: - python qlog-adapter.py [inTrace.jsonl] + python3 qlog-adapter.py [inTrace.jsonl] If the argument is omitted, inTrace will be read from stdin. """.strip()) From f02366e00cd2c0717aa4a0ab46b4c603de4e5dc9 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Fri, 18 Mar 2022 18:25:01 +0000 Subject: [PATCH 209/361] qlog-adapter: start reading from idx == 0 This fixes an issue that qlog-adapter ignored the first event (idx == 0) when gathering sent frame information. --- misc/qlog-adapter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index dbcd4cf5f..622bf28e7 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -73,7 +73,7 @@ def handle_packet_received(events, idx): def handle_packet_sent(events, idx): frames = [] i = idx-1 - while i > 0 and events[i]["type"] != "packet-prepare": + while i >= 0 and events[i]["type"] != "packet-prepare": handler = FRAME_EVENT_HANDLERS.get(events[i]["type"]) if handler: frames.append(handler(events[i])) From 28e12a5404e29de005c4a80d6416ebdfacfdc283 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Fri, 18 Mar 2022 17:12:47 -0400 Subject: [PATCH 210/361] qlog-adapter: Add length to packet send/recv event --- misc/qlog-adapter.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index dbcd4cf5f..187342fbc 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -58,7 +58,7 @@ def handle_packet_received(events, idx): if handler: frames.append(handler(ev)) - return { + ret = { "time": events[idx]["time"], "name": "transport:packet_received", "data": { @@ -70,6 +70,16 @@ def handle_packet_received(events, idx): } } + # draft-ietf-quic-qlog-quic-events A.8: + # ; only if packet_type === "initial" || "handshake" || "0RTT" + # ; Signifies length of the packet_number plus the payload + # + # packet-type == 3: 1-RTT + if events[idx]["packet-type"] != 3: + ret["length"] = events[idx]["decrypted-len"] + + return ret + def handle_packet_sent(events, idx): frames = [] i = idx-1 @@ -79,7 +89,7 @@ def handle_packet_sent(events, idx): frames.append(handler(events[i])) i -= 1 - return { + ret = { "time": events[idx]["time"], "name": "transport:packet_sent", "data": { @@ -91,6 +101,11 @@ def handle_packet_sent(events, idx): } } + if events[idx]["packet-type"] != 3: + ret["length"] = events[idx]["len"] + + return ret + def handle_ack_send(event): return render_ack_frame([[event["largest-acked"]]]) From adb3d6584fe28efe982daa5e91d225d43931e3b6 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Tue, 22 Mar 2022 00:50:37 +0000 Subject: [PATCH 211/361] qlog-adapter: Add handler for `max_streams_receive` The `receive` handler is missing while the `send` version exists. I assume this is due to an error. --- misc/qlog-adapter.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index dbcd4cf5f..b27475601 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -137,6 +137,17 @@ def handle_max_streams_send(event): "maximum": event["maximum"] } +def handle_max_streams_receive(event): + if event["is-unidirectional"]: + stream_type = "unidirectional" + else: + stream_type = "bidirectional" + return { + "frame_type": "max_streams", + "stream_type": stream_type, + "maximum": event["maximum"] + } + def handle_max_stream_data_receive(event): return { "frame_type": "max_stream_data", @@ -304,6 +315,7 @@ def render_ack_frame(ranges): "max-data-receive": handle_max_data_receive, "max-data-send": handle_max_data_send, "max-streams-send": handle_max_streams_send, + "max-streams-receive": handle_max_streams_receive, "max-stream-data-receive": handle_max_stream_data_receive, "max-stream-data-send": handle_max_stream_data_send, "new-connection-id-receive": handle_new_connection_id_receive, From 16ea6dabf885dea05267f9329e30c612d0d77de9 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Tue, 22 Mar 2022 04:16:57 -0500 Subject: [PATCH 212/361] Drop `python3` from the usage line Co-authored-by: FUJI Goro --- misc/qlog-adapter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 2b4898ffb..f279c9100 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -328,7 +328,7 @@ def render_ack_frame(ranges): def usage(): print(r""" Usage: - python3 qlog-adapter.py [inTrace.jsonl] + ./misc/qlog-adapter.py [inTrace.jsonl] If the argument is omitted, inTrace will be read from stdin. """.strip()) From eaae916f290222d43e66ee5a303a8b2244471923 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Tue, 22 Mar 2022 09:20:05 +0000 Subject: [PATCH 213/361] Pass error message to sys.exit for conciseness --- misc/qlog-adapter.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index f279c9100..c26ad2d04 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -351,8 +351,7 @@ def main(): try: infile = open(fn, "r") except OSError as e: - print("Failed to open %s: %s" % (fn, e.strerror)) - sys.exit(1) + sys.exit("Failed to open %s: %s" % (fn, e.strerror)) source_events = load_quicly_events(infile) print(json.dumps({ From 5040fdbce7d0201fa00c82be35abb78f1c5f9c6a Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 23 Mar 2022 09:50:46 +0900 Subject: [PATCH 214/361] notify receipt of late acks to the loss detection module --- include/quicly/loss.h | 17 ++++++++++++++--- lib/quicly.c | 8 ++++++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/include/quicly/loss.h b/include/quicly/loss.h index e2af4a609..e5f5efd36 100644 --- a/include/quicly/loss.h +++ b/include/quicly/loss.h @@ -146,6 +146,12 @@ typedef struct quicly_loss_t { typedef void (*quicly_loss_on_detect_cb)(quicly_loss_t *loss, const quicly_sent_packet_t *lost_packet, int is_time_threshold); +typedef enum quicly_loss_ack_received_kind_t { + QUICLY_LOSS_ACK_RECEIVED_KIND_NON_ACK_ELICITING = 0, + QUICLY_LOSS_ACK_RECEIVED_KIND_ACK_ELICITING, + QUICLY_LOSS_ACK_RECEIVED_KIND_ACK_ELICITING_LATE_ACK, +} quicly_loss_ack_received_kind_t; + static void quicly_loss_init(quicly_loss_t *r, const quicly_loss_conf_t *conf, uint32_t initial_rtt, const uint16_t *max_ack_delay, const uint8_t *ack_delay_exponent); static void quicly_loss_dispose(quicly_loss_t *r); @@ -156,7 +162,7 @@ static void quicly_loss_update_alarm(quicly_loss_t *r, int64_t now, int64_t last * called when an ACK is received */ static void quicly_loss_on_ack_received(quicly_loss_t *r, uint64_t largest_newly_acked, size_t epoch, int64_t now, int64_t sent_at, - uint64_t ack_delay_encoded, int ack_eliciting); + uint64_t ack_delay_encoded, quicly_loss_ack_received_kind_t kind); /* This function updates the loss detection timer and indicates to the caller how many packets should be sent. * After calling this function, app should: * * send min_packets_to_send number of packets immmediately. min_packets_to_send should never be 0. @@ -315,7 +321,7 @@ inline void quicly_loss_update_alarm(quicly_loss_t *r, int64_t now, int64_t last } inline void quicly_loss_on_ack_received(quicly_loss_t *r, uint64_t largest_newly_acked, size_t epoch, int64_t now, int64_t sent_at, - uint64_t ack_delay_encoded, int ack_eliciting) + uint64_t ack_delay_encoded, quicly_loss_ack_received_kind_t kind) { /* Reset PTO count if anything is newly acked, and if sender is not speculatively probing at a tail */ if (largest_newly_acked != UINT64_MAX && r->pto_count > 0) @@ -327,7 +333,7 @@ inline void quicly_loss_on_ack_received(quicly_loss_t *r, uint64_t largest_newly r->largest_acked_packet_plus1[epoch] = largest_newly_acked + 1; /* If ack does not acknowledge any ack-eliciting packet, skip RTT sample */ - if (!ack_eliciting) + if (kind == QUICLY_LOSS_ACK_RECEIVED_KIND_NON_ACK_ELICITING) return; /* Decode ack delay */ @@ -337,6 +343,11 @@ inline void quicly_loss_on_ack_received(quicly_loss_t *r, uint64_t largest_newly if (ack_delay_millisecs > *r->max_ack_delay) ack_delay_millisecs = *r->max_ack_delay; quicly_rtt_update(&r->rtt, (uint32_t)(now - sent_at), ack_delay_millisecs); + + /* Adjust loss detection thresholds when receiving a late ack. */ + if (kind == QUICLY_LOSS_ACK_RECEIVED_KIND_ACK_ELICITING_LATE_ACK) { + /* FIXME */ + } } inline int quicly_loss_on_alarm(quicly_loss_t *r, int64_t now, uint32_t max_ack_delay, int is_1rtt_only, diff --git a/lib/quicly.c b/lib/quicly.c index a0a952c7d..6f952306e 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -4900,7 +4900,7 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload int64_t sent_at; } largest_newly_acked = {UINT64_MAX, INT64_MAX}; size_t bytes_acked = 0; - int includes_ack_eliciting = 0, ret; + int includes_ack_eliciting = 0, includes_late_ack = 0, ret; if ((ret = quicly_decode_ack_frame(&state->src, state->end, &frame, state->frame_type == QUICLY_FRAME_TYPE_ACK_ECN)) != 0) return ret; @@ -4951,6 +4951,7 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload includes_ack_eliciting = 1; if (sent->cc_bytes_in_flight == 0) { is_late_ack = 1; + includes_late_ack = 1; ++conn->super.stats.num_packets.late_acked; } } @@ -4991,7 +4992,10 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload /* Update loss detection engine on ack. The function uses ack_delay only when the largest_newly_acked is also the largest acked * so far. So, it does not matter if the ack_delay being passed in does not apply to the largest_newly_acked. */ quicly_loss_on_ack_received(&conn->egress.loss, largest_newly_acked.pn, state->epoch, conn->stash.now, - largest_newly_acked.sent_at, frame.ack_delay, includes_ack_eliciting); + largest_newly_acked.sent_at, frame.ack_delay, + includes_ack_eliciting ? includes_late_ack ? QUICLY_LOSS_ACK_RECEIVED_KIND_ACK_ELICITING_LATE_ACK + : QUICLY_LOSS_ACK_RECEIVED_KIND_ACK_ELICITING + : QUICLY_LOSS_ACK_RECEIVED_KIND_NON_ACK_ELICITING); /* OnPacketAcked and OnPacketAckedCC */ if (bytes_acked > 0) { From b8b86052dc73df418c4bf9dd7d39fa4a3def8531 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 23 Mar 2022 10:07:07 +0900 Subject: [PATCH 215/361] add knob for controlling loss thresholds dynamically --- include/quicly/loss.h | 14 ++++++++++++++ lib/loss.c | 20 ++++++++++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/include/quicly/loss.h b/include/quicly/loss.h index e5f5efd36..c7312c94e 100644 --- a/include/quicly/loss.h +++ b/include/quicly/loss.h @@ -110,6 +110,19 @@ typedef struct quicly_loss_t { * pointer to transport parameter containing the remote peer's ack exponent */ const uint8_t *ack_delay_exponent; + /** + * Controls loss thresholds. + */ + struct { + /** + * boolean + */ + uint8_t use_packet_based; + /** + * time threshold percentile, relative to RTT (i.e., 1024 is one RTT) + */ + uint16_t time_based_percentile; + } loss_thresholds; /** * The number of consecutive PTOs (PTOs that have fired without receiving an ack). */ @@ -236,6 +249,7 @@ inline void quicly_loss_init(quicly_loss_t *r, const quicly_loss_conf_t *conf, u .max_ack_delay = max_ack_delay, .ack_delay_exponent = ack_delay_exponent, .pto_count = 0, + .loss_thresholds = {.use_packet_based = 1, .time_based_percentile = 1024 / 8 /* start from 1/8 RTT */}, .time_of_last_packet_sent = 0, .largest_acked_packet_plus1 = {0}, .total_bytes_sent = 0, diff --git a/lib/loss.c b/lib/loss.c index 6655b2e11..b63c64888 100644 --- a/lib/loss.c +++ b/lib/loss.c @@ -48,11 +48,19 @@ int quicly_loss_detect_loss(quicly_loss_t *loss, int64_t now, uint32_t max_ack_d /* This function ensures that the value returned in loss_time is when the next application timer should be set for loss * detection. if no timer is required, loss_time is set to INT64_MAX. */ - const uint32_t delay_until_lost = ((loss->rtt.latest > loss->rtt.smoothed ? loss->rtt.latest : loss->rtt.smoothed) * 9 + 7) / 8; + const uint32_t delay_until_lost = ((loss->rtt.latest > loss->rtt.smoothed ? loss->rtt.latest : loss->rtt.smoothed) * + (1024 + loss->loss_thresholds.time_based_percentile) + + 1023) / + 1024; quicly_sentmap_iter_t iter; const quicly_sent_packet_t *sent; int ret; +#define CHECK_TIME_THRESHOLD(sent) ((sent)->sent_at <= now - delay_until_lost) +#define CHECK_PACKET_THRESHOLD(sent) \ + (loss->loss_thresholds.use_packet_based && \ + (int64_t)(sent)->packet_number <= largest_acked_signed - QUICLY_LOSS_DEFAULT_PACKET_THRESHOLD) + loss->loss_time = INT64_MAX; if ((ret = quicly_loss_init_sentmap_iter(loss, &iter, now, max_ack_delay, 0)) != 0) @@ -62,12 +70,9 @@ int quicly_loss_detect_loss(quicly_loss_t *loss, int64_t now, uint32_t max_ack_d * windows. Once marked as lost, cc_bytes_in_flight becomes zero. */ while ((sent = quicly_sentmap_get(&iter))->packet_number != UINT64_MAX) { int64_t largest_acked_signed = loss->largest_acked_packet_plus1[sent->ack_epoch] - 1; - if ((int64_t)sent->packet_number < largest_acked_signed && - (sent->sent_at <= now - delay_until_lost || /* time threshold */ - (int64_t)sent->packet_number <= largest_acked_signed - QUICLY_LOSS_DEFAULT_PACKET_THRESHOLD)) { /* packet threshold */ + if ((int64_t)sent->packet_number < largest_acked_signed && (CHECK_TIME_THRESHOLD(sent) || CHECK_PACKET_THRESHOLD(sent))) { if (sent->cc_bytes_in_flight != 0) { - on_loss_detected(loss, sent, - (int64_t)sent->packet_number > largest_acked_signed - QUICLY_LOSS_DEFAULT_PACKET_THRESHOLD); + on_loss_detected(loss, sent, !CHECK_PACKET_THRESHOLD(sent)); if ((ret = quicly_sentmap_update(&loss->sentmap, &iter, QUICLY_SENTMAP_EVENT_LOST)) != 0) return ret; } else { @@ -82,6 +87,9 @@ int quicly_loss_detect_loss(quicly_loss_t *loss, int64_t now, uint32_t max_ack_d } } +#undef CHECK_TIME_THRESHOLD +#undef CHECK_PACKET_THRESHOLD + if (!is_1rtt_only) { if ((ret = quicly_loss_init_sentmap_iter(loss, &iter, now, max_ack_delay, 0)) != 0) return ret; From 41a46b8e5ee24728e2ff6e23c97c35c6434d21fb Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 23 Mar 2022 11:02:01 +0900 Subject: [PATCH 216/361] simplest and dumbest: exponentially increase time-based threshold --- include/quicly/loss.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/quicly/loss.h b/include/quicly/loss.h index c7312c94e..2c8bce7c7 100644 --- a/include/quicly/loss.h +++ b/include/quicly/loss.h @@ -358,9 +358,15 @@ inline void quicly_loss_on_ack_received(quicly_loss_t *r, uint64_t largest_newly ack_delay_millisecs = *r->max_ack_delay; quicly_rtt_update(&r->rtt, (uint32_t)(now - sent_at), ack_delay_millisecs); - /* Adjust loss detection thresholds when receiving a late ack. */ + /* Adjust loss detection thresholds when receiving a late ack. The strategy is, for each ACK carrying a late ack, first disable + * packet-based detection, then double the time-based threshold until it reaches 1 RTT. */ if (kind == QUICLY_LOSS_ACK_RECEIVED_KIND_ACK_ELICITING_LATE_ACK) { - /* FIXME */ + if (r->loss_thresholds.use_packet_based) { + r->loss_thresholds.use_packet_based = 0; + } else { + if ((r->loss_thresholds.time_based_percentile *= 2) > 1024) + r->loss_thresholds.time_based_percentile = 1024; + } } } From 9ed77f430d5ba64d47528f6c897b020c10779bf4 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 23 Mar 2022 11:09:55 +0900 Subject: [PATCH 217/361] editorial --- include/quicly/loss.h | 32 +++++++++++++++++--------------- lib/loss.c | 2 +- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/include/quicly/loss.h b/include/quicly/loss.h index 2c8bce7c7..2fac428f3 100644 --- a/include/quicly/loss.h +++ b/include/quicly/loss.h @@ -97,6 +97,17 @@ static void quicly_rtt_init(quicly_rtt_t *rtt, const quicly_loss_conf_t *conf, u static void quicly_rtt_update(quicly_rtt_t *rtt, uint32_t latest_rtt, uint32_t ack_delay); static uint32_t quicly_rtt_get_pto(quicly_rtt_t *rtt, uint32_t max_ack_delay, uint32_t min_pto); +typedef struct quicly_loss_thresholds_t { + /** + * boolean + */ + uint8_t use_packet_based; + /** + * time threshold percentile, relative to RTT (i.e., 1024 is one RTT) + */ + uint16_t time_based_percentile; +} quicly_loss_thresholds_t; + typedef struct quicly_loss_t { /** * configuration @@ -113,16 +124,7 @@ typedef struct quicly_loss_t { /** * Controls loss thresholds. */ - struct { - /** - * boolean - */ - uint8_t use_packet_based; - /** - * time threshold percentile, relative to RTT (i.e., 1024 is one RTT) - */ - uint16_t time_based_percentile; - } loss_thresholds; + quicly_loss_thresholds_t thresholds; /** * The number of consecutive PTOs (PTOs that have fired without receiving an ack). */ @@ -249,7 +251,7 @@ inline void quicly_loss_init(quicly_loss_t *r, const quicly_loss_conf_t *conf, u .max_ack_delay = max_ack_delay, .ack_delay_exponent = ack_delay_exponent, .pto_count = 0, - .loss_thresholds = {.use_packet_based = 1, .time_based_percentile = 1024 / 8 /* start from 1/8 RTT */}, + .thresholds = {.use_packet_based = 1, .time_based_percentile = 1024 / 8 /* start from 1/8 RTT */}, .time_of_last_packet_sent = 0, .largest_acked_packet_plus1 = {0}, .total_bytes_sent = 0, @@ -361,11 +363,11 @@ inline void quicly_loss_on_ack_received(quicly_loss_t *r, uint64_t largest_newly /* Adjust loss detection thresholds when receiving a late ack. The strategy is, for each ACK carrying a late ack, first disable * packet-based detection, then double the time-based threshold until it reaches 1 RTT. */ if (kind == QUICLY_LOSS_ACK_RECEIVED_KIND_ACK_ELICITING_LATE_ACK) { - if (r->loss_thresholds.use_packet_based) { - r->loss_thresholds.use_packet_based = 0; + if (r->thresholds.use_packet_based) { + r->thresholds.use_packet_based = 0; } else { - if ((r->loss_thresholds.time_based_percentile *= 2) > 1024) - r->loss_thresholds.time_based_percentile = 1024; + if ((r->thresholds.time_based_percentile *= 2) > 1024) + r->thresholds.time_based_percentile = 1024; } } } diff --git a/lib/loss.c b/lib/loss.c index b63c64888..c17cf6967 100644 --- a/lib/loss.c +++ b/lib/loss.c @@ -49,7 +49,7 @@ int quicly_loss_detect_loss(quicly_loss_t *loss, int64_t now, uint32_t max_ack_d * detection. if no timer is required, loss_time is set to INT64_MAX. */ const uint32_t delay_until_lost = ((loss->rtt.latest > loss->rtt.smoothed ? loss->rtt.latest : loss->rtt.smoothed) * - (1024 + loss->loss_thresholds.time_based_percentile) + + (1024 + loss->thresholds.time_based_percentile) + 1023) / 1024; quicly_sentmap_iter_t iter; From 85f169799b2e63fef6e966e51e681786a4003fac Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 23 Mar 2022 11:10:21 +0900 Subject: [PATCH 218/361] add to stats the loss thresholds in use --- include/quicly.h | 4 ++++ lib/quicly.c | 1 + 2 files changed, 5 insertions(+) diff --git a/include/quicly.h b/include/quicly.h index 0cf41ed2e..0b758858c 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -477,6 +477,10 @@ typedef struct st_quicly_stats_t { * RTT stats. */ quicly_rtt_t rtt; + /** + * Loss thresholds. + */ + quicly_loss_thresholds_t loss_thresholds; /** * Congestion control stats (experimental; TODO cherry-pick what can be exposed as part of a stable API). */ diff --git a/lib/quicly.c b/lib/quicly.c index 6f952306e..c0f27ca0a 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1207,6 +1207,7 @@ int quicly_get_stats(quicly_conn_t *conn, quicly_stats_t *stats) /* set or generate the non-pre-built stats fields here */ stats->rtt = conn->egress.loss.rtt; + stats->loss_thresholds = conn->egress.loss.thresholds; stats->cc = conn->egress.cc; quicly_ratemeter_report(&conn->egress.ratemeter, &stats->delivery_rate); From 79e89899b6cdf7841af92f8023b6b92d295f21cc Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 23 Mar 2022 11:16:58 +0900 Subject: [PATCH 219/361] oops --- lib/loss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/loss.c b/lib/loss.c index c17cf6967..bb98330f8 100644 --- a/lib/loss.c +++ b/lib/loss.c @@ -58,7 +58,7 @@ int quicly_loss_detect_loss(quicly_loss_t *loss, int64_t now, uint32_t max_ack_d #define CHECK_TIME_THRESHOLD(sent) ((sent)->sent_at <= now - delay_until_lost) #define CHECK_PACKET_THRESHOLD(sent) \ - (loss->loss_thresholds.use_packet_based && \ + (loss->thresholds.use_packet_based && \ (int64_t)(sent)->packet_number <= largest_acked_signed - QUICLY_LOSS_DEFAULT_PACKET_THRESHOLD) loss->loss_time = INT64_MAX; From a933e964a39498afeba0d8b9c7d6f7561be6891a Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 11 May 2022 22:13:33 +0900 Subject: [PATCH 220/361] adopt https://github.com/h2o/picotls/pull/384 --- CMakeLists.txt | 11 ++++++----- deps/picotls | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b6379588..5b8936846 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,10 +16,11 @@ IF (WITH_DTRACE) MESSAGE(STATUS "Enabling USDT support") ENDIF () -IF ((CMAKE_SIZEOF_VOID_P EQUAL 8) AND - (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") OR - (CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64") OR - (CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64")) +CMAKE_PUSH_CHECK_STATE() +SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -mavx2 -maes -mpclmul -mvaes -mvpclmulqdq") +CHECK_C_SOURCE_COMPILES("int main(void) {}" CC_HAS_AESNI256) +CMAKE_POP_CHECK_STATE() +IF (CC_HAS_AESNI256) SET(WITH_FUSION_DEFAULT "ON") ELSE () SET(WITH_FUSION_DEFAULT "OFF") @@ -114,7 +115,7 @@ SET(CLI_FILES ${PICOTLS_OPENSSL_FILES} ${QUICLY_LIBRARY_FILES} src/cli.c embedde SET(CLI_COMPILE_FLAGS "-DQUICLY_USE_EMBEDDED_PROBES=1") IF (WITH_FUSION) LIST(APPEND CLI_FILES deps/picotls/lib/fusion.c) - SET(CLI_COMPILE_FLAGS "-mavx2 -maes -mpclmul -DQUICLY_HAVE_FUSION=1 ${CLI_COMPILE_FLAGS}") + SET(CLI_COMPILE_FLAGS "-mavx2 -maes -mpclmul -mvaes -mvpclmulqdq -DQUICLY_HAVE_FUSION=1 ${CLI_COMPILE_FLAGS}") ENDIF () ADD_EXECUTABLE(cli ${CLI_FILES}) SET_TARGET_PROPERTIES(cli PROPERTIES COMPILE_FLAGS ${CLI_COMPILE_FLAGS}) diff --git a/deps/picotls b/deps/picotls index 14ab2a977..688d70cf0 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit 14ab2a97722223671b0d00f29748b28c1f699271 +Subproject commit 688d70cf0b16a522dd3a7d274868601b4e9d9414 From 671c8bac7166567d92a9d41cc4e491c24e5d23e2 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 11 May 2022 22:18:21 +0900 Subject: [PATCH 221/361] oops, add includes --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b8936846..fe05fe682 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,8 @@ CMAKE_POLICY(SET CMP0003 NEW) PROJECT(quicly) +INCLUDE(CMakePushCheckState) +INCLUDE(CheckCSourceCompiles) INCLUDE(deps/picotls/cmake/dtrace-utils.cmake) FIND_PACKAGE(OpenSSL REQUIRED) From 3a1e954c7362c2228c73e1d68fcc66c021c4dbd6 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Fri, 11 Feb 2022 19:47:24 +0000 Subject: [PATCH 222/361] quicly: Record max number of packets in sentmap --- include/quicly.h | 4 ++++ include/quicly/sentmap.h | 6 ++++++ lib/quicly.c | 1 + 3 files changed, 11 insertions(+) diff --git a/include/quicly.h b/include/quicly.h index 0cf41ed2e..90cb1df22 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -485,6 +485,10 @@ typedef struct st_quicly_stats_t { * Estimated delivery rate, in bytes/second. */ quicly_rate_t delivery_rate; + /** + * maximum number of packets contained in the sentmap + */ + size_t num_sentmap_packets_max; } quicly_stats_t; /** diff --git a/include/quicly/sentmap.h b/include/quicly/sentmap.h index 2aea9cb84..c3cb967e2 100644 --- a/include/quicly/sentmap.h +++ b/include/quicly/sentmap.h @@ -210,6 +210,10 @@ struct st_quicly_sentmap_t { * number of packets contained */ size_t num_packets; + /** + * maximum number recorded for num_packets + */ + size_t num_packets_max; /** * bytes in-flight */ @@ -299,6 +303,8 @@ inline void quicly_sentmap_commit(quicly_sentmap_t *map, uint16_t bytes_in_fligh map->_pending_packet = NULL; ++map->num_packets; + if (map->num_packets > map->num_packets_max) + map->num_packets_max = map->num_packets; } inline quicly_sent_t *quicly_sentmap_allocate(quicly_sentmap_t *map, quicly_sent_acked_cb acked) diff --git a/lib/quicly.c b/lib/quicly.c index a0a952c7d..78a36d25c 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1209,6 +1209,7 @@ int quicly_get_stats(quicly_conn_t *conn, quicly_stats_t *stats) stats->rtt = conn->egress.loss.rtt; stats->cc = conn->egress.cc; quicly_ratemeter_report(&conn->egress.ratemeter, &stats->delivery_rate); + stats->num_sentmap_packets_max = conn->egress.loss.sentmap.num_packets_max; return 0; } From 530c64cab0a0318a61baa7c466bab006073be35c Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Fri, 8 Apr 2022 15:56:27 +0000 Subject: [PATCH 223/361] quicly: add `handshake_msec` stat This new metric will be used to understand how long a connection spends in the handshake phase. --- include/quicly.h | 6 +++++- lib/quicly.c | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/quicly.h b/include/quicly.h index 90cb1df22..14ffcafd1 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -466,7 +466,11 @@ struct st_quicly_conn_streamgroup_state_t { /** \ * Total number of PTOs observed during the connection. \ */ \ - uint64_t num_ptos + uint64_t num_ptos; \ + /** \ + * Time spent during handshake. UINT64_MAX if still in handshake. \ + */ \ + uint64_t handshake_msec typedef struct st_quicly_stats_t { /** diff --git a/lib/quicly.c b/lib/quicly.c index 78a36d25c..fdbb7eebf 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -387,6 +387,10 @@ struct st_quicly_conn_t { */ uint8_t should_rearm_on_send : 1; } idle_timeout; + /** + * records the time when this connection was created + */ + int64_t created_at; /** * structure to hold various data used internally */ @@ -1474,6 +1478,10 @@ static int discard_handshake_context(quicly_conn_t *conn, size_t epoch) if ((ret = discard_sentmap_by_epoch(conn, 1u << epoch)) != 0) return ret; destroy_handshake_flow(conn, epoch); + if (epoch == QUICLY_EPOCH_HANDSHAKE) { + assert(conn->stash.now != 0); + conn->super.stats.handshake_msec = conn->stash.now - conn->created_at; + } free_handshake_space(epoch == QUICLY_EPOCH_INITIAL ? &conn->initial : &conn->handshake); return 0; @@ -2085,6 +2093,8 @@ static quicly_conn_t *create_connection(quicly_context_t *ctx, uint32_t protocol memset(conn, 0, sizeof(*conn)); conn->super.ctx = ctx; lock_now(conn, 0); + conn->created_at = conn->stash.now; + conn->super.stats.handshake_msec = UINT64_MAX; set_address(&conn->super.local.address, local_addr); set_address(&conn->super.remote.address, remote_addr); quicly_local_cid_init_set(&conn->super.local.cid_set, ctx->cid_encryptor, local_cid); From 36da0c486173f9cf5d457f5e63fecd19a36fd49a Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Fri, 8 Apr 2022 16:14:46 +0000 Subject: [PATCH 224/361] quicly: Add counter for Initial and Handshake packets --- include/quicly.h | 4 ++++ lib/quicly.c | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/include/quicly.h b/include/quicly.h index 14ffcafd1..f5d989d50 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -427,6 +427,10 @@ struct st_quicly_conn_streamgroup_state_t { * Total number of packets for which acknowledgements were received after being marked lost. \ */ \ uint64_t late_acked; \ + /** \ + * Total number of Initial and Handshake packets sent. \ + */ \ + uint64_t initial_handshake_sent; \ } num_packets; \ struct { \ /** \ diff --git a/lib/quicly.c b/lib/quicly.c index fdbb7eebf..f33a5ba01 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3088,6 +3088,12 @@ static int commit_send_packet(quicly_conn_t *conn, quicly_send_context_t *s, int /* length is always 2 bytes, see _do_prepare_packet */ length |= 0x4000; quicly_encode16(s->dst_payload_from - QUICLY_SEND_PN_SIZE - 2, length); + switch (*s->target.first_byte_at & QUICLY_PACKET_TYPE_BITMASK) { + case QUICLY_PACKET_TYPE_INITIAL: + case QUICLY_PACKET_TYPE_HANDSHAKE: + conn->super.stats.num_packets.initial_handshake_sent++; + break; + } } else { if (conn->egress.packet_number >= conn->application->cipher.egress.key_update_pn.next) { int ret; From d570ded14482d61dc20817731db084e5ba8a8369 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Wed, 20 Apr 2022 17:58:48 +0000 Subject: [PATCH 225/361] quicly: Expire as many sentmap entries as possible In `quicly_loss_init_sentmap_iter`, we used to stop scanning the sentmap once we find an entry with `cc_bytes_in_flight` != 0. With this change, we try to retire as many entries as possible by scanning towards the end of the map, to keep the map small. --- lib/loss.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/loss.c b/lib/loss.c index 6655b2e11..4a9734c53 100644 --- a/lib/loss.c +++ b/lib/loss.c @@ -32,14 +32,23 @@ int quicly_loss_init_sentmap_iter(quicly_loss_t *loss, quicly_sentmap_iter_t *it * below 32 packets. This exception (the threshold of 32) exists to be capable of recognizing excessively late-ACKs when under * heavy loss; in such case, 32 is more than enough, yet small enough that the memory footprint does not matter. */ const quicly_sent_packet_t *sent; - while ((sent = quicly_sentmap_get(iter))->sent_at <= retire_before && sent->cc_bytes_in_flight == 0) { - int ret; + int ret = 0; + while ((sent = quicly_sentmap_get(iter))->sent_at <= retire_before) { if (!is_closing && loss->sentmap.num_packets < 32) break; + if (sent->cc_bytes_in_flight != 0) { + /* cannot retire packets with cc_bytes_in_flight, but we may find retirable ones later in the map */ + quicly_sentmap_skip(iter); + continue; + } if ((ret = quicly_sentmap_update(&loss->sentmap, iter, QUICLY_SENTMAP_EVENT_EXPIRED)) != 0) - return ret; + break; } - return 0; + + /* rewind iter to the head of the sentmap, before returning it to the caller */ + quicly_sentmap_init_iter(&loss->sentmap, iter); + + return ret; } int quicly_loss_detect_loss(quicly_loss_t *loss, int64_t now, uint32_t max_ack_delay, int is_1rtt_only, From b506330e79977fac34b51d64a72eae5f6becaaa9 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Thu, 21 Apr 2022 16:23:22 +0000 Subject: [PATCH 226/361] quicly: Introduce handshake timeout This patch introduces a new kind of timeout which is triggered when a connection stays too long in the handshake phase and does not make further progress. This prevents erroneous/malicious clients from locking up server-side resources for indefinite amount of time. --- include/quicly.h | 10 +++++++++- lib/defaults.c | 3 +++ lib/quicly.c | 17 ++++++++++++++--- quicly-probes.d | 1 + 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index f5d989d50..014995f78 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -311,6 +311,10 @@ struct st_quicly_context_t { * will request the peer to send one ACK every 1/8 RTT (or CWND). 0 disables the use of the delayed-ack extension. */ uint16_t ack_frequency; + /** + * if the handshake does not complete within this value * RTT, close connection + */ + uint32_t handshake_timeout_rtt_multiplier; /** * expand client hello so that it does not fit into one datagram */ @@ -474,7 +478,11 @@ struct st_quicly_conn_streamgroup_state_t { /** \ * Time spent during handshake. UINT64_MAX if still in handshake. \ */ \ - uint64_t handshake_msec + uint64_t handshake_msec; \ + /** \ + * number of timeouts occurred during handshake due to no progress being made (see `handshake_timeout_rtt_multiplier`) \ + */ \ + uint64_t num_handshake_timeouts typedef struct st_quicly_stats_t { /** diff --git a/lib/defaults.c b/lib/defaults.c index fdf754bc1..68af22d37 100644 --- a/lib/defaults.c +++ b/lib/defaults.c @@ -28,6 +28,7 @@ #define DEFAULT_MAX_CRYPTO_BYTES 65536 #define DEFAULT_INITCWND_PACKETS 10 #define DEFAULT_PRE_VALIDATION_AMPLIFICATION_LIMIT 3 +#define DEFAULT_HANDSHAKE_TIMEOUT_RTT_MULTIPLIER 400 /* profile that employs IETF specified values */ const quicly_context_t quicly_spec_context = {NULL, /* tls */ @@ -45,6 +46,7 @@ const quicly_context_t quicly_spec_context = {NULL, QUICLY_PROTOCOL_VERSION_1, DEFAULT_PRE_VALIDATION_AMPLIFICATION_LIMIT, 0, /* ack_frequency */ + DEFAULT_HANDSHAKE_TIMEOUT_RTT_MULTIPLIER, 0, /* enlarge_client_hello */ NULL, NULL, /* on_stream_open */ @@ -73,6 +75,7 @@ const quicly_context_t quicly_performant_context = {NULL, QUICLY_PROTOCOL_VERSION_1, DEFAULT_PRE_VALIDATION_AMPLIFICATION_LIMIT, 0, /* ack_frequency */ + DEFAULT_HANDSHAKE_TIMEOUT_RTT_MULTIPLIER, 0, /* enlarge_client_hello */ NULL, NULL, /* on_stream_open */ diff --git a/lib/quicly.c b/lib/quicly.c index f33a5ba01..d078e280b 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -4350,9 +4350,15 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) /* handle timeouts */ if (conn->idle_timeout.at <= conn->stash.now) { QUICLY_PROBE(IDLE_TIMEOUT, conn, conn->stash.now); - conn->super.state = QUICLY_STATE_DRAINING; - destroy_all_streams(conn, 0, 0); - return QUICLY_ERROR_FREE_CONNECTION; + goto CloseNow; + } + /* handle handshake timeouts */ + if ((conn->initial != NULL || conn->handshake != NULL) && + conn->created_at + (uint64_t)conn->super.ctx->handshake_timeout_rtt_multiplier * conn->egress.loss.rtt.smoothed <= + conn->stash.now) { + QUICLY_PROBE(HANDSHAKE_TIMEOUT, conn, conn->stash.now); + conn->super.stats.num_handshake_timeouts++; + goto CloseNow; } if (conn->egress.loss.alarm_at <= conn->stash.now) { if ((ret = quicly_loss_on_alarm(&conn->egress.loss, conn->stash.now, conn->super.remote.transport_params.max_ack_delay, @@ -4563,6 +4569,11 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) update_idle_timeout(conn, 0); } return ret; + +CloseNow: + conn->super.state = QUICLY_STATE_DRAINING; + destroy_all_streams(conn, 0, 0); + return QUICLY_ERROR_FREE_CONNECTION; } void quicly_send_datagram_frames(quicly_conn_t *conn, ptls_iovec_t *datagrams, size_t num_datagrams) diff --git a/quicly-probes.d b/quicly-probes.d index 7f6dad49d..34a541158 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -46,6 +46,7 @@ provider quicly { probe receive(struct st_quicly_conn_t *conn, int64_t at, const char *dcid, const void *bytes, size_t bytes_len); probe version_switch(struct st_quicly_conn_t *conn, int64_t at, uint32_t new_version); probe idle_timeout(struct st_quicly_conn_t *conn, int64_t at); + probe handshake_timeout(struct st_quicly_conn_t *conn, int64_t at); probe stateless_reset_receive(struct st_quicly_conn_t *conn, int64_t at); probe crypto_handshake(struct st_quicly_conn_t *conn, int64_t at, int ret); From 66e3ec6e0cc68e109adffad9c5ee61363f98f00d Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Fri, 22 Apr 2022 15:28:50 +0000 Subject: [PATCH 227/361] quicly: Cap number of Initial/Handshake packets This is one of the mechanisms to protect against erroneous/malicious clients which stay in the handshake phase forever and do not make progress. --- include/quicly.h | 11 ++++++++++- lib/defaults.c | 3 +++ lib/quicly.c | 5 +++++ quicly-probes.d | 1 + 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/include/quicly.h b/include/quicly.h index 014995f78..81d56bed6 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -315,6 +315,11 @@ struct st_quicly_context_t { * if the handshake does not complete within this value * RTT, close connection */ uint32_t handshake_timeout_rtt_multiplier; + /** + * if the number of Initial/Handshake packets sent during the handshake phase exceeds this limit, treat it as an error and close + * the connection. + */ + uint64_t max_initial_handshake_packets; /** * expand client hello so that it does not fit into one datagram */ @@ -482,7 +487,11 @@ struct st_quicly_conn_streamgroup_state_t { /** \ * number of timeouts occurred during handshake due to no progress being made (see `handshake_timeout_rtt_multiplier`) \ */ \ - uint64_t num_handshake_timeouts + uint64_t num_handshake_timeouts; \ + /** \ + * Total number of events where `initial_handshake_sent` exceeds limit. \ + */ \ + uint64_t num_initial_handshake_exceeded typedef struct st_quicly_stats_t { /** diff --git a/lib/defaults.c b/lib/defaults.c index 68af22d37..1d0691251 100644 --- a/lib/defaults.c +++ b/lib/defaults.c @@ -29,6 +29,7 @@ #define DEFAULT_INITCWND_PACKETS 10 #define DEFAULT_PRE_VALIDATION_AMPLIFICATION_LIMIT 3 #define DEFAULT_HANDSHAKE_TIMEOUT_RTT_MULTIPLIER 400 +#define DEFAULT_MAX_INITIAL_HANDSHAKE_PACKETS 1000 /* profile that employs IETF specified values */ const quicly_context_t quicly_spec_context = {NULL, /* tls */ @@ -47,6 +48,7 @@ const quicly_context_t quicly_spec_context = {NULL, DEFAULT_PRE_VALIDATION_AMPLIFICATION_LIMIT, 0, /* ack_frequency */ DEFAULT_HANDSHAKE_TIMEOUT_RTT_MULTIPLIER, + DEFAULT_MAX_INITIAL_HANDSHAKE_PACKETS, 0, /* enlarge_client_hello */ NULL, NULL, /* on_stream_open */ @@ -76,6 +78,7 @@ const quicly_context_t quicly_performant_context = {NULL, DEFAULT_PRE_VALIDATION_AMPLIFICATION_LIMIT, 0, /* ack_frequency */ DEFAULT_HANDSHAKE_TIMEOUT_RTT_MULTIPLIER, + DEFAULT_MAX_INITIAL_HANDSHAKE_PACKETS, 0, /* enlarge_client_hello */ NULL, NULL, /* on_stream_open */ diff --git a/lib/quicly.c b/lib/quicly.c index d078e280b..4d96db124 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -4360,6 +4360,11 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) conn->super.stats.num_handshake_timeouts++; goto CloseNow; } + if (conn->super.stats.num_packets.initial_handshake_sent >= conn->super.ctx->max_initial_handshake_packets) { + QUICLY_PROBE(INITIAL_HANDSHAKE_PACKET_EXCEED, conn, conn->stash.now); + conn->super.stats.num_initial_handshake_exceeded++; + goto CloseNow; + } if (conn->egress.loss.alarm_at <= conn->stash.now) { if ((ret = quicly_loss_on_alarm(&conn->egress.loss, conn->stash.now, conn->super.remote.transport_params.max_ack_delay, conn->initial == NULL && conn->handshake == NULL, &min_packets_to_send, &restrict_sending, diff --git a/quicly-probes.d b/quicly-probes.d index 34a541158..7bd6b6a65 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -47,6 +47,7 @@ provider quicly { probe version_switch(struct st_quicly_conn_t *conn, int64_t at, uint32_t new_version); probe idle_timeout(struct st_quicly_conn_t *conn, int64_t at); probe handshake_timeout(struct st_quicly_conn_t *conn, int64_t at); + probe initial_handshake_packet_exceed(struct st_quicly_conn_t *conn, int64_t at); probe stateless_reset_receive(struct st_quicly_conn_t *conn, int64_t at); probe crypto_handshake(struct st_quicly_conn_t *conn, int64_t at, int ret); From 686487017ddfba7c863a19d9e76ab3d636038ce5 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Fri, 27 May 2022 20:43:38 +0000 Subject: [PATCH 228/361] Add variables to probes on handshake failures for easier debugging --- lib/quicly.c | 4 ++-- quicly-probes.d | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 4d96db124..38fad4334 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -4356,12 +4356,12 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) if ((conn->initial != NULL || conn->handshake != NULL) && conn->created_at + (uint64_t)conn->super.ctx->handshake_timeout_rtt_multiplier * conn->egress.loss.rtt.smoothed <= conn->stash.now) { - QUICLY_PROBE(HANDSHAKE_TIMEOUT, conn, conn->stash.now); + QUICLY_PROBE(HANDSHAKE_TIMEOUT, conn, conn->stash.now, conn->stash.now - conn->created_at, conn->egress.loss.rtt.smoothed); conn->super.stats.num_handshake_timeouts++; goto CloseNow; } if (conn->super.stats.num_packets.initial_handshake_sent >= conn->super.ctx->max_initial_handshake_packets) { - QUICLY_PROBE(INITIAL_HANDSHAKE_PACKET_EXCEED, conn, conn->stash.now); + QUICLY_PROBE(INITIAL_HANDSHAKE_PACKET_EXCEED, conn, conn->stash.now, conn->super.stats.num_packets.initial_handshake_sent); conn->super.stats.num_initial_handshake_exceeded++; goto CloseNow; } diff --git a/quicly-probes.d b/quicly-probes.d index 7bd6b6a65..b9629e714 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -46,8 +46,8 @@ provider quicly { probe receive(struct st_quicly_conn_t *conn, int64_t at, const char *dcid, const void *bytes, size_t bytes_len); probe version_switch(struct st_quicly_conn_t *conn, int64_t at, uint32_t new_version); probe idle_timeout(struct st_quicly_conn_t *conn, int64_t at); - probe handshake_timeout(struct st_quicly_conn_t *conn, int64_t at); - probe initial_handshake_packet_exceed(struct st_quicly_conn_t *conn, int64_t at); + probe handshake_timeout(struct st_quicly_conn_t *conn, int64_t at, int64_t elapsed, uint32_t rtt_smoothed); + probe initial_handshake_packet_exceed(struct st_quicly_conn_t *conn, int64_t at, uint64_t num_packets); probe stateless_reset_receive(struct st_quicly_conn_t *conn, int64_t at); probe crypto_handshake(struct st_quicly_conn_t *conn, int64_t at, int ret); From 9f13a808361b7293a690946a8d3e27269765eb82 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Fri, 27 May 2022 20:58:01 +0000 Subject: [PATCH 229/361] Disable handshake timeouts on lossy tests --- t/lossy.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/t/lossy.c b/t/lossy.c index 14cc3ab6f..012c36b92 100644 --- a/t/lossy.c +++ b/t/lossy.c @@ -536,6 +536,10 @@ static void test_bidirectional(void) void test_lossy(void) { + uint64_t handshake_timeout_backup = quic_ctx.handshake_timeout_rtt_multiplier; + /* loss tests tend to incur gigantic (and artificial) latencies, which easily trigger handshake timeout. + * for this test, we totally disable handshake timeout so we can focus on the loss test */ + quic_ctx.handshake_timeout_rtt_multiplier = UINT32_MAX; subtest("even", test_even); uint64_t idle_timeout_backup = quic_ctx.transport_params.max_idle_timeout; @@ -544,4 +548,5 @@ void test_lossy(void) quic_ctx.transport_params.max_idle_timeout = (uint64_t)600 * 1000; /* 600 seconds */ subtest("bidirectional", test_bidirectional); quic_ctx.transport_params.max_idle_timeout = idle_timeout_backup; + quic_ctx.handshake_timeout_rtt_multiplier = handshake_timeout_backup; } From ea9eb74e3c977120f33cd3b479cfa9f715f0aec3 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Fri, 10 Jun 2022 19:54:27 +0000 Subject: [PATCH 230/361] Do not rewind sentmap iter when sentmap_update fails When `quicly_sentmap_update` returns non-zero, the sentmap could be in a non-canonical state i.e. first non-NULL entry may not be a packet header (`iter->p->acked != quicly_sentmap__type_packet`). This breaks the assumption in `quicly_sentmap_init_iter`. This patch fixes the issue by rolling back the exit logic when `quicly_sentmap_update` returns non-zero code. Now the code around there is identical to what it looked like before d570ded14482d61dc20817731db084e5ba8a8369. --- lib/loss.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/loss.c b/lib/loss.c index 4a9734c53..88e367791 100644 --- a/lib/loss.c +++ b/lib/loss.c @@ -32,8 +32,8 @@ int quicly_loss_init_sentmap_iter(quicly_loss_t *loss, quicly_sentmap_iter_t *it * below 32 packets. This exception (the threshold of 32) exists to be capable of recognizing excessively late-ACKs when under * heavy loss; in such case, 32 is more than enough, yet small enough that the memory footprint does not matter. */ const quicly_sent_packet_t *sent; - int ret = 0; while ((sent = quicly_sentmap_get(iter))->sent_at <= retire_before) { + int ret; if (!is_closing && loss->sentmap.num_packets < 32) break; if (sent->cc_bytes_in_flight != 0) { @@ -42,13 +42,13 @@ int quicly_loss_init_sentmap_iter(quicly_loss_t *loss, quicly_sentmap_iter_t *it continue; } if ((ret = quicly_sentmap_update(&loss->sentmap, iter, QUICLY_SENTMAP_EVENT_EXPIRED)) != 0) - break; + return ret; } /* rewind iter to the head of the sentmap, before returning it to the caller */ quicly_sentmap_init_iter(&loss->sentmap, iter); - return ret; + return 0; } int quicly_loss_detect_loss(quicly_loss_t *loss, int64_t now, uint32_t max_ack_delay, int is_1rtt_only, From 2d5b6c9fd5bed994556c139053c83221750287ac Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Fri, 10 Jun 2022 19:58:34 +0000 Subject: [PATCH 231/361] Check result of `init_acks_iter` `init_acks_iter` could fail, and if it happens, `iter` may not be initialized as expected. For instance, `iter` may not be pointing to a first sentmap element of a packet in case of failure. This breaks an assumption that many functions that take `iter` have. --- lib/quicly.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 38fad4334..16345ac26 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -4623,7 +4623,8 @@ int quicly_send(quicly_conn_t *conn, quicly_address_t *dest, quicly_address_t *s if (conn->super.state >= QUICLY_STATE_CLOSING) { quicly_sentmap_iter_t iter; - init_acks_iter(conn, &iter); + if ((ret = init_acks_iter(conn, &iter)) != 0) + goto Exit; /* check if the connection can be closed now (after 3 pto) */ if (conn->super.state == QUICLY_STATE_DRAINING || conn->super.stats.num_frames_sent.transport_close + conn->super.stats.num_frames_sent.application_close != 0) { @@ -4950,7 +4951,8 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload break; } - init_acks_iter(conn, &iter); + if ((ret = init_acks_iter(conn, &iter)) != 0) + return ret; /* TODO log PNs being ACKed too late */ From ac74a14979aea46544a65586e15e3cb463549dd9 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 6 Jul 2022 12:56:45 +0900 Subject: [PATCH 232/361] reset sender state correctly when receiving MAX_DATA --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index c0f27ca0a..5a54fdbcd 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5201,7 +5201,7 @@ static int handle_max_data_frame(quicly_conn_t *conn, struct st_quicly_handle_pa if (frame.max_data <= conn->egress.max_data.permitted) return 0; conn->egress.max_data.permitted = frame.max_data; - conn->egress.data_blocked = QUICLY_SENDER_STATE_UNACKED; /* DATA_BLOCKED has not been sent for the new limit */ + conn->egress.data_blocked = QUICLY_SENDER_STATE_NONE; /* DATA_BLOCKED has not been sent for the new limit */ return 0; } From 17d49db3574a5510ca318d7b1b105587d1b6b653 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Sun, 10 Jul 2022 21:23:19 -0500 Subject: [PATCH 233/361] Clarify handshake timeout Co-authored-by: Kazuho Oku --- include/quicly.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/quicly.h b/include/quicly.h index 81d56bed6..f52ae742d 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -312,7 +312,8 @@ struct st_quicly_context_t { */ uint16_t ack_frequency; /** - * if the handshake does not complete within this value * RTT, close connection + * If the handshake does not complete within this value * RTT, close connection. + * When RTT is not observed, timeout is calculated relative to initial RTT (333ms by default). */ uint32_t handshake_timeout_rtt_multiplier; /** From 88a5568616ce132a4d976afb8c5283dc882bba97 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Sun, 10 Jul 2022 21:54:18 -0500 Subject: [PATCH 234/361] Values including `max` shall be allowed Co-authored-by: Kazuho Oku --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 16345ac26..647f6de6f 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -4360,7 +4360,7 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) conn->super.stats.num_handshake_timeouts++; goto CloseNow; } - if (conn->super.stats.num_packets.initial_handshake_sent >= conn->super.ctx->max_initial_handshake_packets) { + if (conn->super.stats.num_packets.initial_handshake_sent > conn->super.ctx->max_initial_handshake_packets) { QUICLY_PROBE(INITIAL_HANDSHAKE_PACKET_EXCEED, conn, conn->stash.now, conn->super.stats.num_packets.initial_handshake_sent); conn->super.stats.num_initial_handshake_exceeded++; goto CloseNow; From 383825edbac4f59d9e3c6799ca024cf5ff2d601e Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Mon, 11 Jul 2022 02:20:31 +0000 Subject: [PATCH 235/361] Rename *_packets_max to *_packets_largest It is more common to use `*_largest` for a maximum value actually observed. --- include/quicly.h | 4 ++-- include/quicly/sentmap.h | 8 ++++---- lib/quicly.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index f52ae742d..ab29414e6 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -512,9 +512,9 @@ typedef struct st_quicly_stats_t { */ quicly_rate_t delivery_rate; /** - * maximum number of packets contained in the sentmap + * largest number of packets contained in the sentmap */ - size_t num_sentmap_packets_max; + size_t num_sentmap_packets_largest; } quicly_stats_t; /** diff --git a/include/quicly/sentmap.h b/include/quicly/sentmap.h index c3cb967e2..407bdbd67 100644 --- a/include/quicly/sentmap.h +++ b/include/quicly/sentmap.h @@ -211,9 +211,9 @@ struct st_quicly_sentmap_t { */ size_t num_packets; /** - * maximum number recorded for num_packets + * largest number recorded for num_packets */ - size_t num_packets_max; + size_t num_packets_largest; /** * bytes in-flight */ @@ -303,8 +303,8 @@ inline void quicly_sentmap_commit(quicly_sentmap_t *map, uint16_t bytes_in_fligh map->_pending_packet = NULL; ++map->num_packets; - if (map->num_packets > map->num_packets_max) - map->num_packets_max = map->num_packets; + if (map->num_packets > map->num_packets_largest) + map->num_packets_largest = map->num_packets; } inline quicly_sent_t *quicly_sentmap_allocate(quicly_sentmap_t *map, quicly_sent_acked_cb acked) diff --git a/lib/quicly.c b/lib/quicly.c index 647f6de6f..7ceefff00 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1213,7 +1213,7 @@ int quicly_get_stats(quicly_conn_t *conn, quicly_stats_t *stats) stats->rtt = conn->egress.loss.rtt; stats->cc = conn->egress.cc; quicly_ratemeter_report(&conn->egress.ratemeter, &stats->delivery_rate); - stats->num_sentmap_packets_max = conn->egress.loss.sentmap.num_packets_max; + stats->num_sentmap_packets_largest = conn->egress.loss.sentmap.num_packets_largest; return 0; } From 9732764abcf587f0602cc4c496abb28a8b7810cb Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Mon, 11 Jul 2022 02:41:21 +0000 Subject: [PATCH 236/361] Rename handshake_msec to handshake_confirmed_msec --- include/quicly.h | 4 ++-- lib/quicly.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index ab29414e6..013695df8 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -482,9 +482,9 @@ struct st_quicly_conn_streamgroup_state_t { */ \ uint64_t num_ptos; \ /** \ - * Time spent during handshake. UINT64_MAX if still in handshake. \ + * Time took until handshake is confirmed. UINT64_MAX if handshake is not confirmed yet. \ */ \ - uint64_t handshake_msec; \ + uint64_t handshake_confirmed_msec; \ /** \ * number of timeouts occurred during handshake due to no progress being made (see `handshake_timeout_rtt_multiplier`) \ */ \ diff --git a/lib/quicly.c b/lib/quicly.c index 7ceefff00..6e499ac53 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1480,7 +1480,7 @@ static int discard_handshake_context(quicly_conn_t *conn, size_t epoch) destroy_handshake_flow(conn, epoch); if (epoch == QUICLY_EPOCH_HANDSHAKE) { assert(conn->stash.now != 0); - conn->super.stats.handshake_msec = conn->stash.now - conn->created_at; + conn->super.stats.handshake_confirmed_msec = conn->stash.now - conn->created_at; } free_handshake_space(epoch == QUICLY_EPOCH_INITIAL ? &conn->initial : &conn->handshake); @@ -2094,7 +2094,7 @@ static quicly_conn_t *create_connection(quicly_context_t *ctx, uint32_t protocol conn->super.ctx = ctx; lock_now(conn, 0); conn->created_at = conn->stash.now; - conn->super.stats.handshake_msec = UINT64_MAX; + conn->super.stats.handshake_confirmed_msec = UINT64_MAX; set_address(&conn->super.local.address, local_addr); set_address(&conn->super.remote.address, remote_addr); quicly_local_cid_init_set(&conn->super.local.cid_set, ctx->cid_encryptor, local_cid); From 42f29bf0ee4c14bdcd156d0530c537fd12c0e875 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Mon, 11 Jul 2022 07:35:19 +0000 Subject: [PATCH 237/361] Rename PREBUILT_FIELDS to PREBUILT_COUNTERS There has been an implicit assumption that fields in PREBUILT_FIELDS are also aggregatable counters. This patch renames the macro to clarify this assumption as well. --- include/quicly.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index 013695df8..48eb71a76 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -404,10 +404,10 @@ struct st_quicly_conn_streamgroup_state_t { }; /** - * Values that do not need to be gathered upon the invocation of `quicly_get_stats`. We use typedef to define the same fields in - * the same order for quicly_stats_t and `struct st_quicly_conn_public_t::stats`. + * Aggregatable counters that do not need to be gathered upon the invocation of `quicly_get_stats`. We use typedef to define the + * same fields in the same order for quicly_stats_t and `struct st_quicly_conn_public_t::stats`. */ -#define QUICLY_STATS_PREBUILT_FIELDS \ +#define QUICLY_STATS_PREBUILT_COUNTERS \ struct { \ /** \ * Total number of packets received. \ @@ -481,10 +481,6 @@ struct st_quicly_conn_streamgroup_state_t { * Total number of PTOs observed during the connection. \ */ \ uint64_t num_ptos; \ - /** \ - * Time took until handshake is confirmed. UINT64_MAX if handshake is not confirmed yet. \ - */ \ - uint64_t handshake_confirmed_msec; \ /** \ * number of timeouts occurred during handshake due to no progress being made (see `handshake_timeout_rtt_multiplier`) \ */ \ @@ -498,7 +494,7 @@ typedef struct st_quicly_stats_t { /** * The pre-built fields. This MUST be the first member of `quicly_stats_t` so that we can use `memcpy`. */ - QUICLY_STATS_PREBUILT_FIELDS; + QUICLY_STATS_PREBUILT_COUNTERS; /** * RTT stats. */ @@ -583,7 +579,11 @@ struct _st_quicly_conn_public_t { quicly_cid_t original_dcid; struct st_quicly_default_scheduler_state_t _default_scheduler; struct { - QUICLY_STATS_PREBUILT_FIELDS; + QUICLY_STATS_PREBUILT_COUNTERS; + /** + * Time took until handshake is confirmed. UINT64_MAX if handshake is not confirmed yet. + */ + uint64_t handshake_confirmed_msec; } stats; uint32_t version; void *data; From 121f2425937993958f34ba7e76b580d2fb9b4fe1 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Thu, 21 Jul 2022 06:50:47 +0000 Subject: [PATCH 238/361] apply clang-format --- lib/quicly.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 874de0254..353b19f13 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -88,7 +88,7 @@ KHASH_MAP_INIT_INT64(quicly_stream_t, quicly_stream_t *) quicly_conn_t *_conn = (conn); \ if (PTLS_UNLIKELY(QUICLY_##label##_ENABLED()) && !ptls_skip_tracing(_conn->crypto.tls)) \ QUICLY_##label(_conn, __VA_ARGS__); \ - QUICLY_TRACER(label, _conn, __VA_ARGS__); \ + QUICLY_TRACER(label, _conn, __VA_ARGS__); \ } while (0) #else #define QUICLY_PROBE(label, conn, ...) QUICLY_TRACER(label, conn, __VA_ARGS__) @@ -3111,11 +3111,10 @@ static int commit_send_packet(quicly_conn_t *conn, quicly_send_context_t *s, int datagram_size = s->dst - s->payload_buf.datagram; assert(datagram_size <= conn->egress.max_udp_payload_size); - conn->super.ctx->crypto_engine->encrypt_packet(conn->super.ctx->crypto_engine, conn, s->target.cipher->header_protection, - s->target.cipher->aead, ptls_iovec_init(s->payload_buf.datagram, datagram_size), - s->target.first_byte_at - s->payload_buf.datagram, - s->dst_payload_from - s->payload_buf.datagram, conn->egress.packet_number, - coalesced); + conn->super.ctx->crypto_engine->encrypt_packet( + conn->super.ctx->crypto_engine, conn, s->target.cipher->header_protection, s->target.cipher->aead, + ptls_iovec_init(s->payload_buf.datagram, datagram_size), s->target.first_byte_at - s->payload_buf.datagram, + s->dst_payload_from - s->payload_buf.datagram, conn->egress.packet_number, coalesced); /* update CC, commit sentmap */ if (s->target.ack_eliciting) { From ab8c2c65204e906d1a66c2744c113237371aded0 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Tue, 26 Jul 2022 20:31:57 +0000 Subject: [PATCH 239/361] Export handshake_confirmed_msec through stats --- include/quicly.h | 4 ++++ lib/quicly.c | 1 + 2 files changed, 5 insertions(+) diff --git a/include/quicly.h b/include/quicly.h index 48eb71a76..fc883506a 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -511,6 +511,10 @@ typedef struct st_quicly_stats_t { * largest number of packets contained in the sentmap */ size_t num_sentmap_packets_largest; + /** + * Time took until handshake is confirmed. UINT64_MAX if handshake is not confirmed yet. + */ + uint64_t handshake_confirmed_msec; } quicly_stats_t; /** diff --git a/lib/quicly.c b/lib/quicly.c index 6e499ac53..9569f912e 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1214,6 +1214,7 @@ int quicly_get_stats(quicly_conn_t *conn, quicly_stats_t *stats) stats->cc = conn->egress.cc; quicly_ratemeter_report(&conn->egress.ratemeter, &stats->delivery_rate); stats->num_sentmap_packets_largest = conn->egress.loss.sentmap.num_packets_largest; + stats->handshake_confirmed_msec = conn->super.stats.handshake_confirmed_msec; return 0; } From 6c8591dc6bc7f35e433a0c1be9bbfc23579054df Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 27 Jul 2022 16:48:11 +0900 Subject: [PATCH 240/361] update picotls --- deps/picotls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/picotls b/deps/picotls index 688d70cf0..7970614ad 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit 688d70cf0b16a522dd3a7d274868601b4e9d9414 +Subproject commit 7970614ad049d194fe1691bdf0cc66c6930a3a2f From 9fe79a7b8fe3de8afcfaf9e6d4e666379670b92a Mon Sep 17 00:00:00 2001 From: Karthikdasari0423 <92445174+Karthikdasari0423@users.noreply.github.com> Date: Mon, 8 Aug 2022 13:02:49 +0530 Subject: [PATCH 241/361] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d78e47aa3..5b18d4d7d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ quicly [![CI](https://github.com/h2o/quicly/actions/workflows/ci.yml/badge.svg)](https://github.com/h2o/quicly/actions/workflows/ci.yml) === -Quicly is a QUIC implementation, written from the ground up to be used within the H2O HTTP server. +Quicly is a IETF [QUIC](https://quicwg.github.io/) Protocol implementation, written from the ground up to be used within the H2O HTTP server. The software is licensed under the MIT License. From 1c828fb2857b7b6f17e6dcaa50f09cf840c7783c Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 8 Aug 2022 23:41:37 +0900 Subject: [PATCH 242/361] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b18d4d7d..d58eaf06b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ quicly [![CI](https://github.com/h2o/quicly/actions/workflows/ci.yml/badge.svg)](https://github.com/h2o/quicly/actions/workflows/ci.yml) === -Quicly is a IETF [QUIC](https://quicwg.github.io/) Protocol implementation, written from the ground up to be used within the H2O HTTP server. +Quicly is an IETF [QUIC](https://quicwg.github.io/) protocol implementation, written from the ground up to be used within the H2O HTTP server. The software is licensed under the MIT License. From 46110287eb20e0780cf41bd30fc4715907ccf400 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 8 Aug 2022 23:42:18 +0900 Subject: [PATCH 243/361] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d58eaf06b..d6fb5f67a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ quicly [![CI](https://github.com/h2o/quicly/actions/workflows/ci.yml/badge.svg)](https://github.com/h2o/quicly/actions/workflows/ci.yml) === -Quicly is an IETF [QUIC](https://quicwg.github.io/) protocol implementation, written from the ground up to be used within the H2O HTTP server. +Quicly is an IETF [QUIC](https://quicwg.github.io/) protocol implementation, written from the ground up to be used primarily within the H2O HTTP server. The software is licensed under the MIT License. From b7be54d0bb55984005f51a490d3894a3d4ac687e Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Tue, 26 Jul 2022 00:46:25 +0000 Subject: [PATCH 244/361] update picotls --- deps/picotls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/picotls b/deps/picotls index 14ab2a977..c94915e8e 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit 14ab2a97722223671b0d00f29748b28c1f699271 +Subproject commit c94915e8e1bfd8243225fa01530735ef31c126d7 From 33de9e40523d0bdd539858f6d3890840bd08b7e7 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Tue, 26 Jul 2022 00:46:37 +0000 Subject: [PATCH 245/361] add -j=file and PTLSLOG env param to quicly CLI --- src/cli.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/cli.c b/src/cli.c index d738156f9..423e474db 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1067,6 +1067,23 @@ static void push_req(const char *path, int to_file) memset(reqs + i + 1, 0, sizeof(*reqs)); } +static void setup_ptlslog(const char *fn) +{ + int fd; + if ((fd = open(fn, O_WRONLY | O_CREAT | O_APPEND, 0666)) == -1) { + fprintf(stderr, "failed to open file:%s:%s\n", fn, strerror(errno)); + exit(1); + } + ptlslog_fd = fd; +} + +static void setup_ptlslog_from_env(void) +{ + const char *fn = getenv("PTLSLOG"); + if (fn) + setup_ptlslog(fn); +} + int main(int argc, char **argv) { const char *cert_file = NULL, *raw_pubkey_file = NULL, *host, *port, *cid_key = NULL; @@ -1086,6 +1103,7 @@ int main(int argc, char **argv) setup_session_cache(ctx.tls); quicly_amend_ptls_context(ctx.tls); + setup_ptlslog_from_env(); { uint8_t secret[PTLS_MAX_DIGEST_SIZE]; @@ -1094,7 +1112,7 @@ int main(int argc, char **argv) address_token_aead.dec = ptls_aead_new(&ptls_openssl_aes128gcm, &ptls_openssl_sha256, 0, secret, ""); } - while ((ch = getopt(argc, argv, "a:b:B:c:C:Dd:k:Ee:f:Gi:I:K:l:M:m:NnOp:P:Rr:S:s:u:U:Vvw:W:x:X:y:h")) != -1) { + while ((ch = getopt(argc, argv, "a:b:B:c:C:Dd:k:Ee:f:Gi:I:j:K:l:M:m:NnOp:P:Rr:S:s:u:U:Vvw:W:x:X:y:h")) != -1) { switch (ch) { case 'a': assert(negotiated_protocols.count < PTLS_ELEMENTSOF(negotiated_protocols.list)); @@ -1175,6 +1193,9 @@ int main(int argc, char **argv) fprintf(stderr, "failed to parse idle timeout: %s\n", optarg); exit(1); } + case 'j': + setup_ptlslog(optarg); + break; case 'K': if (sscanf(optarg, "%" SCNu64, &ctx.max_packets_per_key) != 1) { fprintf(stderr, "failed to parse key update interval: %s\n", optarg); From 5592d493e4e69dec95275414ad5b513c2d7e86e5 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Tue, 26 Jul 2022 00:46:57 +0000 Subject: [PATCH 246/361] add QUICLY_LOG / QUICLY_LOG_CONN macros to use ptlslog --- include/quicly.h | 14 ++++++++++++ lib/quicly.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/include/quicly.h b/include/quicly.h index 48eb71a76..f70025216 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -1236,6 +1236,20 @@ void quicly_stream_noop_on_receive_reset(quicly_stream_t *stream, int err); extern const quicly_stream_callbacks_t quicly_stream_noop_callbacks; +#define QUICLY_LOG(type, block) PTLSLOG(quicly, type, block) + +#define QUICLY_LOG_CONN(type, conn, block) \ + do { \ + quicly_conn_t *_conn = (conn); \ + if (!ptls_skip_tracing(_conn->crypto.tls)) \ + QUICLY_LOG(type, { \ + PTLSLOG_ELEMENT_PTR(conn, _conn); \ + do { \ + block \ + } while (0); \ + }); \ + } while (0) + /* inline definitions */ inline int quicly_is_supported_version(uint32_t version) diff --git a/lib/quicly.c b/lib/quicly.c index 6e499ac53..a1b44dabf 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -981,6 +981,10 @@ void crypto_stream_receive(quicly_stream_t *stream, size_t off, const void *src, &conn->crypto.handshake_properties); quicly_streambuf_ingress_shift(stream, input.len); QUICLY_PROBE(CRYPTO_HANDSHAKE, conn, conn->stash.now, handshake_result); + QUICLY_LOG_CONN(crypto_handshake, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(ret, handshake_result); + }); switch (handshake_result) { case 0: case PTLS_ERROR_IN_PROGRESS: @@ -1130,6 +1134,11 @@ static void destroy_stream(quicly_stream_t *stream, int err) quicly_conn_t *conn = stream->conn; QUICLY_PROBE(STREAM_ON_DESTROY, conn, conn->stash.now, stream, err); + QUICLY_LOG_CONN(stream_on_destroy, conn, { + PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_PTR(stream, stream); + PTLSLOG_ELEMENT_SIGNED(err, err); + }); if (stream->callbacks != NULL) stream->callbacks->on_destroy(stream, err); @@ -1547,6 +1556,11 @@ static int update_1rtt_egress_key(quicly_conn_t *conn) QUICLY_PROBE(CRYPTO_SEND_KEY_UPDATE, conn, conn->stash.now, space->cipher.egress.key_phase, QUICLY_PROBE_HEXDUMP(space->cipher.egress.secret, cipher->hash->digest_size)); + QUICLY_LOG_CONN(crypto_send_key_update, conn, { + PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(phase, space->cipher.egress.key_phase); + // TODO: handle secret + }); return 0; } @@ -1562,6 +1576,11 @@ static int received_key_update(quicly_conn_t *conn, uint64_t newly_decrypted_key QUICLY_PROBE(CRYPTO_RECEIVE_KEY_UPDATE, conn, conn->stash.now, space->cipher.ingress.key_phase.decrypted, QUICLY_PROBE_HEXDUMP(space->cipher.ingress.secret, ptls_get_cipher(conn->crypto.tls)->hash->digest_size)); + QUICLY_LOG_CONN(crypto_receive_key_update, conn, { + PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(phase, space->cipher.ingress.key_phase.decrypted); + // TODO: handle secret + }); if (space->cipher.egress.key_phase < space->cipher.ingress.key_phase.decrypted) { return update_1rtt_egress_key(conn); @@ -1581,12 +1600,16 @@ void quicly_free(quicly_conn_t *conn) lock_now(conn, 0); QUICLY_PROBE(FREE, conn, conn->stash.now); + QUICLY_LOG_CONN(free, conn, { + PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); + }); #if QUICLY_USE_EMBEDDED_PROBES || QUICLY_USE_DTRACE if (QUICLY_CONN_STATS_ENABLED()) { quicly_stats_t stats; quicly_get_stats(conn, &stats); QUICLY_PROBE(CONN_STATS, conn, conn->stash.now, &stats, sizeof(stats)); + // TODO: emit stats } #endif destroy_all_streams(conn, 0, 1); @@ -1696,6 +1719,12 @@ static int apply_stream_frame(quicly_stream_t *stream, quicly_stream_frame_t *fr int ret; QUICLY_PROBE(STREAM_RECEIVE, stream->conn, stream->conn->stash.now, stream, frame->offset, frame->data.len); + QUICLY_LOG_CONN(stream_receive, stream->conn, { + PTLSLOG_ELEMENT_UNSIGNED(time, stream->conn->stash.now); + PTLSLOG_ELEMENT_PTR(stream, stream); + PTLSLOG_ELEMENT_UNSIGNED(off, frame->offset); + PTLSLOG_ELEMENT_UNSIGNED(len, frame->data.len); + }); if (quicly_recvstate_transfer_complete(&stream->recvstate)) return 0; @@ -1731,6 +1760,13 @@ static int apply_stream_frame(quicly_stream_t *stream, quicly_stream_frame_t *fr uint64_t buf_offset = frame->offset + frame->data.len - apply_len - stream->recvstate.data_off; const void *apply_src = frame->data.base + frame->data.len - apply_len; QUICLY_PROBE(STREAM_ON_RECEIVE, stream->conn, stream->conn->stash.now, stream, (size_t)buf_offset, apply_src, apply_len); + QUICLY_LOG_CONN(stream_on_receive, stream->conn, { + PTLSLOG_ELEMENT_UNSIGNED(time, stream->conn->stash.now); + PTLSLOG_ELEMENT_PTR(stream, stream); + PTLSLOG_ELEMENT_UNSIGNED(off, buf_offset); + // TODO: handle src + PTLSLOG_ELEMENT_UNSIGNED(src_len, apply_len); + }); stream->callbacks->on_receive(stream, (size_t)buf_offset, apply_src, apply_len); if (stream->conn->super.state >= QUICLY_STATE_CLOSING) return QUICLY_ERROR_IS_CLOSING; @@ -2278,6 +2314,10 @@ int quicly_connect(quicly_conn_t **_conn, quicly_context_t *ctx, const char *ser conn->super.original_dcid = *server_cid; QUICLY_PROBE(CONNECT, conn, conn->stash.now, conn->super.version); + QUICLY_LOG_CONN(connect, conn, { + PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(version, conn->super.version); + }); if ((ret = setup_handshake_space_and_flow(conn, QUICLY_EPOCH_INITIAL)) != 0) goto Exit; @@ -2445,6 +2485,11 @@ static int aead_decrypt_1rtt(void *ctx, uint64_t pn, quicly_decoded_packet_t *pa ++space->cipher.ingress.key_phase.prepared; QUICLY_PROBE(CRYPTO_RECEIVE_KEY_UPDATE_PREPARE, conn, conn->stash.now, space->cipher.ingress.key_phase.prepared, QUICLY_PROBE_HEXDUMP(space->cipher.ingress.secret, cipher->hash->digest_size)); + QUICLY_LOG_CONN(crypto_receive_key_update_prepare, conn, { + PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(phase, space->cipher.ingress.key_phase.prepared); + // TODO: hande secret + }); } } @@ -2627,6 +2672,11 @@ static int on_ack_stream_ack_one(quicly_conn_t *conn, quicly_stream_id_t stream_ if (bytes_to_shift != 0) { QUICLY_PROBE(STREAM_ON_SEND_SHIFT, stream->conn, stream->conn->stash.now, stream, bytes_to_shift); stream->callbacks->on_send_shift(stream, bytes_to_shift); + QUICLY_LOG_CONN(stream_on_send_shift, stream->conn, { + PTLSLOG_ELEMENT_UNSIGNED(time, stream->conn->stash.now); + PTLSLOG_ELEMENT_PTR(stream, stream); + PTLSLOG_ELEMENT_UNSIGNED(delta, bytes_to_shift); + }); } if (stream_is_destroyable(stream)) { destroy_stream(stream, 0); @@ -3129,6 +3179,13 @@ static int commit_send_packet(quicly_conn_t *conn, quicly_send_context_t *s, int conn->egress.cc.type->cc_on_sent(&conn->egress.cc, &conn->egress.loss, (uint32_t)packet_bytes_in_flight, conn->stash.now); QUICLY_PROBE(PACKET_SENT, conn, conn->stash.now, conn->egress.packet_number, s->dst - s->target.first_byte_at, get_epoch(*s->target.first_byte_at), !s->target.ack_eliciting); + QUICLY_LOG_CONN(packet_sent, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(pn, conn->egress.packet_number); + PTLSLOG_ELEMENT_UNSIGNED(len, s->dst - s->target.first_byte_at); + PTLSLOG_ELEMENT_UNSIGNED(type, get_epoch(*s->target.first_byte_at)); + PTLSLOG_ELEMENT_SIGNED(ack_only, !s->target.ack_eliciting); + }); ++conn->egress.packet_number; ++conn->super.stats.num_packets.sent; From fe98e245d2b0eb3d9c0fb533c1b79f707ae2eaa1 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Tue, 26 Jul 2022 02:56:22 +0000 Subject: [PATCH 247/361] avoid use of the same identifier as an element name in the macro --- include/quicly.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index f70025216..fcbc91bb6 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -1238,12 +1238,12 @@ extern const quicly_stream_callbacks_t quicly_stream_noop_callbacks; #define QUICLY_LOG(type, block) PTLSLOG(quicly, type, block) -#define QUICLY_LOG_CONN(type, conn, block) \ +#define QUICLY_LOG_CONN(type, _conn, block) \ do { \ - quicly_conn_t *_conn = (conn); \ - if (!ptls_skip_tracing(_conn->crypto.tls)) \ + quicly_conn_t *__conn = (_conn); \ + if (!ptls_skip_tracing(__conn->crypto.tls)) \ QUICLY_LOG(type, { \ - PTLSLOG_ELEMENT_PTR(conn, _conn); \ + PTLSLOG_ELEMENT_PTR(conn, __conn); \ do { \ block \ } while (0); \ From 5b9e8999e392889f0d6c40648363bd281a45c8f0 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Tue, 26 Jul 2022 02:57:05 +0000 Subject: [PATCH 248/361] use PTLS_HEXDUMP macro --- deps/picotls | 2 +- lib/quicly.c | 32 ++++++++++++++++++++++++-------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/deps/picotls b/deps/picotls index c94915e8e..4ce36f14b 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit c94915e8e1bfd8243225fa01530735ef31c126d7 +Subproject commit 4ce36f14b4c39c2be58cfeb153708b01d8028e76 diff --git a/lib/quicly.c b/lib/quicly.c index a1b44dabf..e231cdb30 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -93,11 +93,7 @@ KHASH_MAP_INIT_INT64(quicly_stream_t, quicly_stream_t *) #else #define QUICLY_PROBE(label, conn, ...) QUICLY_TRACER(label, conn, __VA_ARGS__) #endif -#define QUICLY_PROBE_HEXDUMP(s, l) \ - ({ \ - size_t _l = (l); \ - ptls_hexdump(alloca(_l * 2 + 1), (s), _l); \ - }) +#define QUICLY_PROBE_HEXDUMP(s, l) PTLS_HEXDUMP((s), (l)) #define QUICLY_PROBE_ESCAPE_UNSAFE_STRING(s, l) \ ({ \ size_t _l = (l); \ @@ -1600,9 +1596,7 @@ void quicly_free(quicly_conn_t *conn) lock_now(conn, 0); QUICLY_PROBE(FREE, conn, conn->stash.now); - QUICLY_LOG_CONN(free, conn, { - PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); - }); + QUICLY_LOG_CONN(free, conn, { PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); }); #if QUICLY_USE_EMBEDDED_PROBES || QUICLY_USE_DTRACE if (QUICLY_CONN_STATS_ENABLED()) { @@ -2708,6 +2702,12 @@ static int on_ack_stream(quicly_sentmap_t *map, const quicly_sent_packet_t *pack QUICLY_PROBE(STREAM_ACKED, conn, conn->stash.now, sent->data.stream.stream_id, sent->data.stream.args.start, sent->data.stream.args.end - sent->data.stream.args.start); + QUICLY_LOG_CONN(stream_acked, conn, { + PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(stream_id, sent->data.stream.stream_id); + PTLSLOG_ELEMENT_UNSIGNED(off, sent->data.stream.args.start); + PTLSLOG_ELEMENT_UNSIGNED(len, sent->data.stream.args.end - sent->data.stream.args.start); + }); if (packet->frames_in_flight && conn->stash.on_ack_stream.active_acked_cache.stream_id == sent->data.stream.stream_id && conn->stash.on_ack_stream.active_acked_cache.args.end == sent->data.stream.args.start) { @@ -2731,6 +2731,12 @@ static int on_ack_stream(quicly_sentmap_t *map, const quicly_sent_packet_t *pack QUICLY_PROBE(STREAM_LOST, conn, conn->stash.now, sent->data.stream.stream_id, sent->data.stream.args.start, sent->data.stream.args.end - sent->data.stream.args.start); + QUICLY_LOG_CONN(stream_lost, conn, { + PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(stream_id, sent->data.stream.stream_id); + PTLSLOG_ELEMENT_UNSIGNED(off, sent->data.stream.args.start); + PTLSLOG_ELEMENT_UNSIGNED(len, sent->data.stream.args.end - sent->data.stream.args.start); + }); quicly_stream_t *stream; if ((stream = quicly_get_stream(conn, sent->data.stream.stream_id)) == NULL) @@ -2898,6 +2904,10 @@ static int on_ack_new_token(quicly_sentmap_t *map, const quicly_sent_packet_t *p } if (acked) { QUICLY_PROBE(NEW_TOKEN_ACKED, conn, conn->stash.now, sent->data.new_token.generation); + QUICLY_LOG_CONN(new_token_acked, conn, { + PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(generation, sent->data.new_token.generation); + }); if (conn->egress.new_token.max_acked < sent->data.new_token.generation) conn->egress.new_token.max_acked = sent->data.new_token.generation; } @@ -3296,6 +3306,12 @@ static int do_allocate_frame(quicly_conn_t *conn, quicly_send_context_t *s, size QUICLY_PROBE(PACKET_PREPARE, conn, conn->stash.now, s->current.first_byte, QUICLY_PROBE_HEXDUMP(conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len)); + QUICLY_LOG_CONN(packet_prepare, conn, { + PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(first_octet, s->current.first_byte); + PTLSLOG_ELEMENT_SAFESTR( + dcid, PTLS_HEXDUMP(conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len)); + }); /* emit header */ s->target.first_byte_at = s->dst; From 792280d4ef39c7e46e88d5e052eed8562382471d Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Wed, 27 Jul 2022 07:14:16 +0000 Subject: [PATCH 249/361] add QUICLY_LOG per USDT probe --- deps/picotls | 2 +- lib/quicly.c | 311 +++++++++++++++++++++++++++++++++++++++++++++--- quicly-probes.d | 8 +- 3 files changed, 298 insertions(+), 23 deletions(-) diff --git a/deps/picotls b/deps/picotls index 4ce36f14b..5490f219b 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit 4ce36f14b4c39c2be58cfeb153708b01d8028e76 +Subproject commit 5490f219ba8d401db86f577f423532e161d31b6e diff --git a/lib/quicly.c b/lib/quicly.c index e231cdb30..7f32ac3ec 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1131,7 +1131,7 @@ static void destroy_stream(quicly_stream_t *stream, int err) QUICLY_PROBE(STREAM_ON_DESTROY, conn, conn->stash.now, stream, err); QUICLY_LOG_CONN(stream_on_destroy, conn, { - PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_PTR(stream, stream); PTLSLOG_ELEMENT_SIGNED(err, err); }); @@ -1553,9 +1553,8 @@ static int update_1rtt_egress_key(quicly_conn_t *conn) QUICLY_PROBE(CRYPTO_SEND_KEY_UPDATE, conn, conn->stash.now, space->cipher.egress.key_phase, QUICLY_PROBE_HEXDUMP(space->cipher.egress.secret, cipher->hash->digest_size)); QUICLY_LOG_CONN(crypto_send_key_update, conn, { - PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_UNSIGNED(phase, space->cipher.egress.key_phase); - // TODO: handle secret }); return 0; @@ -1573,9 +1572,8 @@ static int received_key_update(quicly_conn_t *conn, uint64_t newly_decrypted_key QUICLY_PROBE(CRYPTO_RECEIVE_KEY_UPDATE, conn, conn->stash.now, space->cipher.ingress.key_phase.decrypted, QUICLY_PROBE_HEXDUMP(space->cipher.ingress.secret, ptls_get_cipher(conn->crypto.tls)->hash->digest_size)); QUICLY_LOG_CONN(crypto_receive_key_update, conn, { - PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_UNSIGNED(phase, space->cipher.ingress.key_phase.decrypted); - // TODO: handle secret }); if (space->cipher.egress.key_phase < space->cipher.ingress.key_phase.decrypted) { @@ -1596,14 +1594,14 @@ void quicly_free(quicly_conn_t *conn) lock_now(conn, 0); QUICLY_PROBE(FREE, conn, conn->stash.now); - QUICLY_LOG_CONN(free, conn, { PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(free, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); #if QUICLY_USE_EMBEDDED_PROBES || QUICLY_USE_DTRACE if (QUICLY_CONN_STATS_ENABLED()) { quicly_stats_t stats; quicly_get_stats(conn, &stats); QUICLY_PROBE(CONN_STATS, conn, conn->stash.now, &stats, sizeof(stats)); - // TODO: emit stats + // TODO: emit stats with QUICLY_LOG_CONN() } #endif destroy_all_streams(conn, 0, 1); @@ -1714,7 +1712,7 @@ static int apply_stream_frame(quicly_stream_t *stream, quicly_stream_frame_t *fr QUICLY_PROBE(STREAM_RECEIVE, stream->conn, stream->conn->stash.now, stream, frame->offset, frame->data.len); QUICLY_LOG_CONN(stream_receive, stream->conn, { - PTLSLOG_ELEMENT_UNSIGNED(time, stream->conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); PTLSLOG_ELEMENT_PTR(stream, stream); PTLSLOG_ELEMENT_UNSIGNED(off, frame->offset); PTLSLOG_ELEMENT_UNSIGNED(len, frame->data.len); @@ -1755,10 +1753,9 @@ static int apply_stream_frame(quicly_stream_t *stream, quicly_stream_frame_t *fr const void *apply_src = frame->data.base + frame->data.len - apply_len; QUICLY_PROBE(STREAM_ON_RECEIVE, stream->conn, stream->conn->stash.now, stream, (size_t)buf_offset, apply_src, apply_len); QUICLY_LOG_CONN(stream_on_receive, stream->conn, { - PTLSLOG_ELEMENT_UNSIGNED(time, stream->conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); PTLSLOG_ELEMENT_PTR(stream, stream); PTLSLOG_ELEMENT_UNSIGNED(off, buf_offset); - // TODO: handle src PTLSLOG_ELEMENT_UNSIGNED(src_len, apply_len); }); stream->callbacks->on_receive(stream, (size_t)buf_offset, apply_src, apply_len); @@ -2309,7 +2306,7 @@ int quicly_connect(quicly_conn_t **_conn, quicly_context_t *ctx, const char *ser QUICLY_PROBE(CONNECT, conn, conn->stash.now, conn->super.version); QUICLY_LOG_CONN(connect, conn, { - PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_UNSIGNED(version, conn->super.version); }); @@ -2480,9 +2477,8 @@ static int aead_decrypt_1rtt(void *ctx, uint64_t pn, quicly_decoded_packet_t *pa QUICLY_PROBE(CRYPTO_RECEIVE_KEY_UPDATE_PREPARE, conn, conn->stash.now, space->cipher.ingress.key_phase.prepared, QUICLY_PROBE_HEXDUMP(space->cipher.ingress.secret, cipher->hash->digest_size)); QUICLY_LOG_CONN(crypto_receive_key_update_prepare, conn, { - PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_UNSIGNED(phase, space->cipher.ingress.key_phase.prepared); - // TODO: hande secret }); } } @@ -2667,7 +2663,7 @@ static int on_ack_stream_ack_one(quicly_conn_t *conn, quicly_stream_id_t stream_ QUICLY_PROBE(STREAM_ON_SEND_SHIFT, stream->conn, stream->conn->stash.now, stream, bytes_to_shift); stream->callbacks->on_send_shift(stream, bytes_to_shift); QUICLY_LOG_CONN(stream_on_send_shift, stream->conn, { - PTLSLOG_ELEMENT_UNSIGNED(time, stream->conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); PTLSLOG_ELEMENT_PTR(stream, stream); PTLSLOG_ELEMENT_UNSIGNED(delta, bytes_to_shift); }); @@ -2703,7 +2699,7 @@ static int on_ack_stream(quicly_sentmap_t *map, const quicly_sent_packet_t *pack QUICLY_PROBE(STREAM_ACKED, conn, conn->stash.now, sent->data.stream.stream_id, sent->data.stream.args.start, sent->data.stream.args.end - sent->data.stream.args.start); QUICLY_LOG_CONN(stream_acked, conn, { - PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_SIGNED(stream_id, sent->data.stream.stream_id); PTLSLOG_ELEMENT_UNSIGNED(off, sent->data.stream.args.start); PTLSLOG_ELEMENT_UNSIGNED(len, sent->data.stream.args.end - sent->data.stream.args.start); @@ -2732,7 +2728,7 @@ static int on_ack_stream(quicly_sentmap_t *map, const quicly_sent_packet_t *pack QUICLY_PROBE(STREAM_LOST, conn, conn->stash.now, sent->data.stream.stream_id, sent->data.stream.args.start, sent->data.stream.args.end - sent->data.stream.args.start); QUICLY_LOG_CONN(stream_lost, conn, { - PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_SIGNED(stream_id, sent->data.stream.stream_id); PTLSLOG_ELEMENT_UNSIGNED(off, sent->data.stream.args.start); PTLSLOG_ELEMENT_UNSIGNED(len, sent->data.stream.args.end - sent->data.stream.args.start); @@ -2905,7 +2901,7 @@ static int on_ack_new_token(quicly_sentmap_t *map, const quicly_sent_packet_t *p if (acked) { QUICLY_PROBE(NEW_TOKEN_ACKED, conn, conn->stash.now, sent->data.new_token.generation); QUICLY_LOG_CONN(new_token_acked, conn, { - PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_UNSIGNED(generation, sent->data.new_token.generation); }); if (conn->egress.new_token.max_acked < sent->data.new_token.generation) @@ -3307,7 +3303,7 @@ static int do_allocate_frame(quicly_conn_t *conn, quicly_send_context_t *s, size QUICLY_PROBE(PACKET_PREPARE, conn, conn->stash.now, s->current.first_byte, QUICLY_PROBE_HEXDUMP(conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len)); QUICLY_LOG_CONN(packet_prepare, conn, { - PTLSLOG_ELEMENT_UNSIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_UNSIGNED(first_octet, s->current.first_byte); PTLSLOG_ELEMENT_SAFESTR( dcid, PTLS_HEXDUMP(conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len)); @@ -3429,6 +3425,11 @@ static int send_ack(quicly_conn_t *conn, struct st_quicly_pn_space_t *space, qui ++conn->super.stats.num_frames_sent.ack; QUICLY_PROBE(ACK_SEND, conn, conn->stash.now, space->ack_queue.ranges[space->ack_queue.num_ranges - 1].end - 1, ack_delay); + QUICLY_LOG_CONN(ack_send, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(largest_acked, space->ack_queue.ranges[space->ack_queue.num_ranges - 1].end - 1); + PTLSLOG_ELEMENT_UNSIGNED(ack_delay, ack_delay); + }); /* when there are no less than QUICLY_NUM_ACK_BLOCKS_TO_INDUCE_ACKACK (8) gaps, bundle PING once every 4 packets being sent */ if (space->ack_queue.num_ranges >= QUICLY_NUM_ACK_BLOCKS_TO_INDUCE_ACKACK && conn->egress.packet_number % 4 == 0 && @@ -3436,6 +3437,7 @@ static int send_ack(quicly_conn_t *conn, struct st_quicly_pn_space_t *space, qui *dst++ = QUICLY_FRAME_TYPE_PING; ++conn->super.stats.num_frames_sent.ping; QUICLY_PROBE(PING_SEND, conn, conn->stash.now); + QUICLY_LOG_CONN(ping_send, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); } s->dst = dst; @@ -3510,6 +3512,11 @@ static int send_control_frames_of_stream(quicly_stream_t *stream, quicly_send_co ++stream->conn->super.stats.num_frames_sent.stop_sending; QUICLY_PROBE(STOP_SENDING_SEND, stream->conn, stream->conn->stash.now, stream->stream_id, stream->_send_aux.stop_sending.error_code); + QUICLY_LOG_CONN(stop_sending_send, stream->conn, { + PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); + PTLSLOG_ELEMENT_UNSIGNED(error_code, stream->_send_aux.stop_sending.error_code); + }); } /* send MAX_STREAM_DATA if necessary */ @@ -3528,6 +3535,11 @@ static int send_control_frames_of_stream(quicly_stream_t *stream, quicly_send_co /* update stats */ ++stream->conn->super.stats.num_frames_sent.max_stream_data; QUICLY_PROBE(MAX_STREAM_DATA_SEND, stream->conn, stream->conn->stash.now, stream, new_value); + QUICLY_LOG_CONN(max_stream_data_send, stream->conn, { + PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); + PTLSLOG_ELEMENT_PTR(stream, stream); + PTLSLOG_ELEMENT_UNSIGNED(maximum, new_value); + }); } /* send RESET_STREAM if necessary */ @@ -3540,6 +3552,12 @@ static int send_control_frames_of_stream(quicly_stream_t *stream, quicly_send_co ++stream->conn->super.stats.num_frames_sent.reset_stream; QUICLY_PROBE(RESET_STREAM_SEND, stream->conn, stream->conn->stash.now, stream->stream_id, stream->_send_aux.reset_stream.error_code, stream->sendstate.size_inflight); + QUICLY_LOG_CONN(reset_stream_send, stream->conn, { + PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); + PTLSLOG_ELEMENT_UNSIGNED(error_code, stream->_send_aux.reset_stream.error_code); + PTLSLOG_ELEMENT_UNSIGNED(final_size, stream->sendstate.size_inflight); + }); } /* send STREAM_DATA_BLOCKED if necessary */ @@ -3555,6 +3573,11 @@ static int send_control_frames_of_stream(quicly_stream_t *stream, quicly_send_co stream->_send_aux.blocked = QUICLY_SENDER_STATE_UNACKED; ++stream->conn->super.stats.num_frames_sent.stream_data_blocked; QUICLY_PROBE(STREAM_DATA_BLOCKED_SEND, stream->conn, stream->conn->stash.now, stream->stream_id, offset); + QUICLY_LOG_CONN(stream_data_blocked_send, stream->conn, { + PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); + PTLSLOG_ELEMENT_UNSIGNED(maximum, offset); + }); } return 0; @@ -3738,6 +3761,12 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) assert(len != 0); size_t emit_off = (size_t)(off - stream->sendstate.acked.ranges[0].end); QUICLY_PROBE(STREAM_ON_SEND_EMIT, stream->conn, stream->conn->stash.now, stream, emit_off, len); + QUICLY_LOG_CONN(stream_on_send_emit, stream->conn, { + PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); + PTLSLOG_ELEMENT_PTR(stream, stream); + PTLSLOG_ELEMENT_UNSIGNED(off, off); + PTLSLOG_ELEMENT_UNSIGNED(capacity, len); + }); stream->callbacks->on_send_emit(stream, emit_off, dst, &len, &wrote_all); if (stream->conn->super.state >= QUICLY_STATE_CLOSING) { return QUICLY_ERROR_IS_CLOSING; @@ -3772,6 +3801,14 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) stream->conn->super.stats.num_bytes.stream_data_resent += (stream->sendstate.size_inflight < off + len ? stream->sendstate.size_inflight : off + len) - off; QUICLY_PROBE(STREAM_SEND, stream->conn, stream->conn->stash.now, stream, off, len, is_fin); + QUICLY_LOG_CONN(stream_send, stream->conn, { + PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); + PTLSLOG_ELEMENT_PTR(stream, stream); + PTLSLOG_ELEMENT_UNSIGNED(off, off); + PTLSLOG_ELEMENT_UNSIGNED(len, len); + PTLSLOG_ELEMENT_SIGNED(is_fin, is_fin); + }); + QUICLY_PROBE(QUICTRACE_SEND_STREAM, stream->conn, stream->conn->stash.now, stream, off, len, is_fin); /* update sendstate (and also MAX_DATA counter) */ if (stream->sendstate.size_inflight < off + len) { @@ -3862,8 +3899,19 @@ static void on_loss_detected(quicly_loss_t *loss, const quicly_sent_packet_t *lo lost_packet->packet_number, conn->egress.packet_number, conn->stash.now, conn->egress.max_udp_payload_size); QUICLY_PROBE(PACKET_LOST, conn, conn->stash.now, lost_packet->packet_number, lost_packet->ack_epoch); + QUICLY_LOG_CONN(packet_lost, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(pn, lost_packet->packet_number); + PTLSLOG_ELEMENT_UNSIGNED(packet_type, lost_packet->ack_epoch); + }); QUICLY_PROBE(CC_CONGESTION, conn, conn->stash.now, lost_packet->packet_number + 1, conn->egress.loss.sentmap.bytes_in_flight, conn->egress.cc.cwnd); + QUICLY_LOG_CONN(cc_congestion, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(max_lost_pn, lost_packet->packet_number + 1); + PTLSLOG_ELEMENT_UNSIGNED(flight, conn->egress.loss.sentmap.bytes_in_flight); + PTLSLOG_ELEMENT_UNSIGNED(cwnd, conn->egress.cc.cwnd); + }); QUICLY_PROBE(QUICTRACE_CC_LOST, conn, conn->stash.now, &conn->egress.loss.rtt, conn->egress.cc.cwnd, conn->egress.loss.sentmap.bytes_in_flight); } @@ -3895,6 +3943,11 @@ static int send_max_streams(quicly_conn_t *conn, int uni, quicly_send_context_t ++conn->super.stats.num_frames_sent.max_streams_bidi; } QUICLY_PROBE(MAX_STREAMS_SEND, conn, conn->stash.now, new_count, uni); + QUICLY_LOG_CONN(max_streams_send, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(maximum, new_count); + PTLSLOG_ELEMENT_SIGNED(is_unidirectional, uni); + }); return 0; } @@ -3924,6 +3977,11 @@ static int send_streams_blocked(quicly_conn_t *conn, int uni, quicly_send_contex ++conn->super.stats.num_frames_sent.streams_blocked; QUICLY_PROBE(STREAMS_BLOCKED_SEND, conn, conn->stash.now, max_streams->count, uni); + QUICLY_LOG_CONN(streams_blocked_send, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(maximum, max_streams->count); + PTLSLOG_ELEMENT_SIGNED(is_unidirectional, uni); + }); return 0; } @@ -3968,6 +4026,7 @@ static int send_handshake_done(quicly_conn_t *conn, quicly_send_context_t *s) conn->egress.pending_flows &= ~QUICLY_PENDING_FLOW_HANDSHAKE_DONE_BIT; ++conn->super.stats.num_frames_sent.handshake_done; QUICLY_PROBE(HANDSHAKE_DONE_SEND, conn, conn->stash.now); + QUICLY_LOG_CONN(handshake_done_send, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); ret = 0; Exit: @@ -3988,6 +4047,10 @@ static int send_data_blocked(quicly_conn_t *conn, quicly_send_context_t *s) ++conn->super.stats.num_frames_sent.data_blocked; QUICLY_PROBE(DATA_BLOCKED_SEND, conn, conn->stash.now, offset); + QUICLY_LOG_CONN(data_blocked_send, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(off, offset); + }); ret = 0; Exit: @@ -4028,6 +4091,11 @@ static int send_resumption_token(quicly_conn_t *conn, quicly_send_context_t *s) ++conn->super.stats.num_frames_sent.new_token; QUICLY_PROBE(NEW_TOKEN_SEND, conn, conn->stash.now, tokenbuf.base, tokenbuf.off, sent->data.new_token.generation); + QUICLY_LOG_CONN(new_token_send, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SAFESTR(token, PTLS_HEXDUMP(tokenbuf.base, tokenbuf.off)); + PTLSLOG_ELEMENT_UNSIGNED(generation, sent->data.new_token.generation); + }); ret = 0; Exit: ptls_buffer_dispose(&tokenbuf); @@ -4228,6 +4296,7 @@ static int send_handshake_flow(quicly_conn_t *conn, size_t epoch, quicly_send_co conn->egress.last_retransmittable_sent_at = conn->stash.now; ++conn->super.stats.num_frames_sent.ping; QUICLY_PROBE(PING_SEND, conn, conn->stash.now); + QUICLY_LOG_CONN(ping_send, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); } } @@ -4270,9 +4339,20 @@ static int send_connection_close(quicly_conn_t *conn, size_t epoch, quicly_send_ if (offending_frame_type != UINT64_MAX) { ++conn->super.stats.num_frames_sent.transport_close; QUICLY_PROBE(TRANSPORT_CLOSE_SEND, conn, conn->stash.now, error_code, offending_frame_type, reason_phrase); + QUICLY_LOG_CONN(transport_close_send, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(error_code, error_code); + PTLSLOG_ELEMENT_UNSIGNED(frame_type, offending_frame_type); + PTLSLOG_ELEMENT_UNSAFESTR(reason_phrase, reason_phrase); + }); } else { ++conn->super.stats.num_frames_sent.application_close; QUICLY_PROBE(APPLICATION_CLOSE_SEND, conn, conn->stash.now, error_code, reason_phrase); + QUICLY_LOG_CONN(application_close_send, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(error_code, error_code); + PTLSLOG_ELEMENT_UNSAFESTR(reason_phrase, reason_phrase); + }); } return 0; @@ -4298,6 +4378,14 @@ static int send_new_connection_id(quicly_conn_t *conn, quicly_send_context_t *s, QUICLY_PROBE(NEW_CONNECTION_ID_SEND, conn, conn->stash.now, new_cid->sequence, retire_prior_to, QUICLY_PROBE_HEXDUMP(new_cid->cid.cid, new_cid->cid.len), QUICLY_PROBE_HEXDUMP(new_cid->stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN)); + QUICLY_LOG_CONN(new_connection_id_send, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(sequence, new_cid->sequence); + PTLSLOG_ELEMENT_UNSIGNED(retire_prior_to, retire_prior_to); + PTLSLOG_ELEMENT_SAFESTR(cid, PTLS_HEXDUMP(new_cid->cid.cid, new_cid->cid.len)); + PTLSLOG_ELEMENT_SAFESTR(stateless_reset_token, + PTLS_HEXDUMP(new_cid->stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN)); + }); return 0; } @@ -4317,6 +4405,10 @@ static int send_retire_connection_id(quicly_conn_t *conn, quicly_send_context_t ++conn->super.stats.num_frames_sent.retire_connection_id; QUICLY_PROBE(RETIRE_CONNECTION_ID_SEND, conn, conn->stash.now, sequence); + QUICLY_LOG_CONN(retire_connection_id_send, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(sequence, sequence); + }); return 0; } @@ -4336,6 +4428,12 @@ static int update_traffic_key_cb(ptls_update_traffic_key_t *self, ptls_t *tls, i QUICLY_PROBE(CRYPTO_UPDATE_SECRET, conn, conn->stash.now, is_enc, epoch, log_label, QUICLY_PROBE_HEXDUMP(secret, cipher->hash->digest_size)); + QUICLY_LOG_CONN(crypto_update_secret, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(is_enc, is_enc); + PTLSLOG_ELEMENT_UNSIGNED(epoch, epoch); + PTLSLOG_ELEMENT_SAFESTR(label, log_label); + }); if (tlsctx->log_event != NULL) { char hexbuf[PTLS_MAX_DIGEST_SIZE * 2 + 1]; @@ -4423,6 +4521,7 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) /* handle timeouts */ if (conn->idle_timeout.at <= conn->stash.now) { QUICLY_PROBE(IDLE_TIMEOUT, conn, conn->stash.now); + QUICLY_LOG_CONN(idle_timeout, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); goto CloseNow; } /* handle handshake timeouts */ @@ -4430,11 +4529,20 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) conn->created_at + (uint64_t)conn->super.ctx->handshake_timeout_rtt_multiplier * conn->egress.loss.rtt.smoothed <= conn->stash.now) { QUICLY_PROBE(HANDSHAKE_TIMEOUT, conn, conn->stash.now, conn->stash.now - conn->created_at, conn->egress.loss.rtt.smoothed); + QUICLY_LOG_CONN(handshake_timeout, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(elapsed, conn->stash.now - conn->created_at); + PTLSLOG_ELEMENT_UNSIGNED(rtt_smoothed, conn->egress.loss.rtt.smoothed); + }); conn->super.stats.num_handshake_timeouts++; goto CloseNow; } if (conn->super.stats.num_packets.initial_handshake_sent > conn->super.ctx->max_initial_handshake_packets) { QUICLY_PROBE(INITIAL_HANDSHAKE_PACKET_EXCEED, conn, conn->stash.now, conn->super.stats.num_packets.initial_handshake_sent); + QUICLY_LOG_CONN(initial_handshake_packet_exceed, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(num_packets, conn->super.stats.num_packets.initial_handshake_sent); + }); conn->super.stats.num_initial_handshake_exceeded++; goto CloseNow; } @@ -4452,6 +4560,12 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) * that is considered inflight. */ QUICLY_PROBE(PTO, conn, conn->stash.now, conn->egress.loss.sentmap.bytes_in_flight, conn->egress.cc.cwnd, conn->egress.loss.pto_count); + QUICLY_LOG_CONN(pto, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(inflight, conn->egress.loss.sentmap.bytes_in_flight); + PTLSLOG_ELEMENT_UNSIGNED(cwnd, conn->egress.cc.cwnd); + PTLSLOG_ELEMENT_SIGNED(pto_count, conn->egress.loss.pto_count); + }); ++conn->super.stats.num_ptos; size_t bytes_to_mark = min_packets_to_send * conn->egress.max_udp_payload_size; if (conn->initial != NULL && (ret = mark_frames_on_pto(conn, QUICLY_EPOCH_INITIAL, &bytes_to_mark)) != 0) @@ -4504,6 +4618,10 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) if (s->dst_end - s->dst >= required_space) { s->dst = quicly_encode_datagram_frame(s->dst, *payload); QUICLY_PROBE(DATAGRAM_SEND, conn, conn->stash.now, payload->base, payload->len); + QUICLY_LOG_CONN(datagram_send, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(payload_len, payload->len); + }); } else { /* FIXME: At the moment, we add a padding because we do not have a way to reclaim allocated space, and because * it is forbidden to send an empty QUIC packet. */ @@ -4519,6 +4637,7 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) *s->dst++ = QUICLY_FRAME_TYPE_PING; ++conn->super.stats.num_frames_sent.ping; QUICLY_PROBE(PING_SEND, conn, conn->stash.now); + QUICLY_LOG_CONN(ping_send, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); } /* take actions only permitted for short header packets */ if (conn->application->one_rtt_writable) { @@ -4568,6 +4687,10 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) quicly_maxsender_record(&conn->ingress.max_data.sender, new_value, &sent->data.max_data.args); ++conn->super.stats.num_frames_sent.max_data; QUICLY_PROBE(MAX_DATA_SEND, conn, conn->stash.now, new_value); + QUICLY_LOG_CONN(max_data_send, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(maximum, new_value); + }); } if (conn->egress.data_blocked == QUICLY_SENDER_STATE_SEND && (ret = send_data_blocked(conn, s)) != 0) goto Exit; @@ -4693,6 +4816,12 @@ int quicly_send(quicly_conn_t *conn, quicly_address_t *dest, quicly_address_t *s QUICLY_PROBE(SEND, conn, conn->stash.now, conn->super.state, QUICLY_PROBE_HEXDUMP(conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len)); + QUICLY_LOG_CONN(send, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(state, conn->super.state); + PTLSLOG_ELEMENT_SAFESTR( + dcid, PTLS_HEXDUMP(conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len)); + }); if (conn->super.state >= QUICLY_STATE_CLOSING) { quicly_sentmap_iter_t iter; @@ -4927,6 +5056,10 @@ int quicly_get_or_open_stream(quicly_conn_t *conn, uint64_t stream_id, quicly_st goto Exit; } QUICLY_PROBE(STREAM_ON_OPEN, conn, conn->stash.now, *stream); + QUICLY_LOG_CONN(stream_on_open, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_PTR(stream, *stream); + }); if ((ret = conn->super.ctx->stream_open->cb(conn->super.ctx->stream_open, *stream)) != 0) { *stream = NULL; goto Exit; @@ -4977,6 +5110,12 @@ static int handle_reset_stream_frame(quicly_conn_t *conn, struct st_quicly_handl if ((ret = quicly_decode_reset_stream_frame(&state->src, state->end, &frame)) != 0) return ret; QUICLY_PROBE(RESET_STREAM_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.app_error_code, frame.final_size); + QUICLY_LOG_CONN(reset_stream_receive, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(stream_id, frame.stream_id); + PTLSLOG_ELEMENT_UNSIGNED(app_error_code, frame.app_error_code); + PTLSLOG_ELEMENT_UNSIGNED(final_size, frame.final_size); + }); if ((ret = quicly_get_or_open_stream(conn, frame.stream_id, &stream)) != 0 || stream == NULL) return ret; @@ -4988,6 +5127,11 @@ static int handle_reset_stream_frame(quicly_conn_t *conn, struct st_quicly_handl stream->conn->ingress.max_data.bytes_consumed += bytes_missing; int err = QUICLY_ERROR_FROM_APPLICATION_ERROR_CODE(frame.app_error_code); QUICLY_PROBE(STREAM_ON_RECEIVE_RESET, stream->conn, stream->conn->stash.now, stream, err); + QUICLY_LOG_CONN(stream_on_receive_reset, stream->conn, { + PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); + PTLSLOG_ELEMENT_PTR(stream, stream); + PTLSLOG_ELEMENT_SIGNED(err, err); + }); stream->callbacks->on_receive_reset(stream, err); if (stream->conn->super.state >= QUICLY_STATE_CLOSING) return QUICLY_ERROR_IS_CLOSING; @@ -5036,6 +5180,11 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload * Processing acks in packet number order requires processing the ack blocks in reverse order. */ uint64_t pn_block_max = pn_acked + frame.ack_block_lengths[gap_index] - 1; QUICLY_PROBE(ACK_BLOCK_RECEIVED, conn, conn->stash.now, pn_acked, pn_block_max); + QUICLY_LOG_CONN(ack_block_received, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(pn_acked, pn_acked); + PTLSLOG_ELEMENT_UNSIGNED(pn_block_max, pn_block_max); + }); while (quicly_sentmap_get(&iter)->packet_number < pn_acked) quicly_sentmap_skip(&iter); do { @@ -5066,6 +5215,11 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload largest_newly_acked.pn = pn_acked; largest_newly_acked.sent_at = sent->sent_at; QUICLY_PROBE(PACKET_ACKED, conn, conn->stash.now, pn_acked, is_late_ack); + QUICLY_LOG_CONN(packet_acked, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(pn, pn_acked); + PTLSLOG_ELEMENT_SIGNED(is_late_ack, is_late_ack); + }); if (sent->cc_bytes_in_flight != 0) { bytes_acked += sent->cc_bytes_in_flight; conn->super.stats.num_bytes.ack_received += sent->cc_bytes_in_flight; @@ -5078,6 +5232,10 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload space->cipher.egress.key_update_pn.last = UINT64_MAX; space->cipher.egress.key_update_pn.next = conn->egress.packet_number + conn->super.ctx->max_packets_per_key; QUICLY_PROBE(CRYPTO_SEND_KEY_UPDATE_CONFIRMED, conn, conn->stash.now, space->cipher.egress.key_update_pn.next); + QUICLY_LOG_CONN(crypto_send_key_update_confirmed, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(next_pn, space->cipher.egress.key_update_pn.next); + }); } } ++pn_acked; @@ -5092,6 +5250,10 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload return ret; QUICLY_PROBE(ACK_DELAY_RECEIVED, conn, conn->stash.now, frame.ack_delay); + QUICLY_LOG_CONN(ack_delay_received, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(ack_delay, frame.ack_delay); + }); quicly_ratemeter_on_ack(&conn->egress.ratemeter, conn->stash.now, conn->super.stats.num_bytes.ack_received, largest_newly_acked.pn); @@ -5112,6 +5274,13 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload QUICLY_PROBE(CC_ACK_RECEIVED, conn, conn->stash.now, frame.largest_acknowledged, bytes_acked, conn->egress.cc.cwnd, conn->egress.loss.sentmap.bytes_in_flight); + QUICLY_LOG_CONN(cc_ack_received, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(largest_acked, frame.largest_acknowledged); + PTLSLOG_ELEMENT_UNSIGNED(bytes_acked, bytes_acked); + PTLSLOG_ELEMENT_UNSIGNED(cwnd, conn->egress.cc.cwnd); + PTLSLOG_ELEMENT_UNSIGNED(inflight, conn->egress.loss.sentmap.bytes_in_flight); + }); /* loss-detection */ if ((ret = quicly_loss_detect_loss(&conn->egress.loss, conn->stash.now, conn->super.remote.transport_params.max_ack_delay, @@ -5132,6 +5301,11 @@ static int handle_max_stream_data_frame(quicly_conn_t *conn, struct st_quicly_ha return ret; QUICLY_PROBE(MAX_STREAM_DATA_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.max_stream_data); + QUICLY_LOG_CONN(max_stream_data_receive, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(stream_id, frame.stream_id); + PTLSLOG_ELEMENT_UNSIGNED(max_stream_data, frame.max_stream_data); + }); if (!quicly_stream_has_send_side(quicly_is_client(conn), frame.stream_id)) return QUICLY_TRANSPORT_ERROR_FRAME_ENCODING; @@ -5159,6 +5333,10 @@ static int handle_data_blocked_frame(quicly_conn_t *conn, struct st_quicly_handl return ret; QUICLY_PROBE(DATA_BLOCKED_RECEIVE, conn, conn->stash.now, frame.offset); + QUICLY_LOG_CONN(data_blocked_receive, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(off, frame.offset); + }); quicly_maxsender_request_transmit(&conn->ingress.max_data.sender); if (should_send_max_data(conn)) @@ -5177,6 +5355,11 @@ static int handle_stream_data_blocked_frame(quicly_conn_t *conn, struct st_quicl return ret; QUICLY_PROBE(STREAM_DATA_BLOCKED_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.offset); + QUICLY_LOG_CONN(stream_data_blocked_receive, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SIGNED(stream_id, frame.stream_id); + PTLSLOG_ELEMENT_UNSIGNED(maximum, frame.offset); + }); if (!quicly_stream_has_receive_side(quicly_is_client(conn), frame.stream_id)) return QUICLY_TRANSPORT_ERROR_FRAME_ENCODING; @@ -5199,6 +5382,11 @@ static int handle_streams_blocked_frame(quicly_conn_t *conn, struct st_quicly_ha return ret; QUICLY_PROBE(STREAMS_BLOCKED_RECEIVE, conn, conn->stash.now, frame.count, uni); + QUICLY_LOG_CONN(streams_blocked_receive, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(maximum, frame.count); + PTLSLOG_ELEMENT_SIGNED(is_unidirectional, uni); + }); if (should_send_max_streams(conn, uni)) { quicly_maxsender_t *maxsender = uni ? &conn->ingress.max_streams.uni : &conn->ingress.max_streams.bidi; @@ -5218,6 +5406,11 @@ static int handle_max_streams_frame(quicly_conn_t *conn, struct st_quicly_handle return ret; QUICLY_PROBE(MAX_STREAMS_RECEIVE, conn, conn->stash.now, frame.count, uni); + QUICLY_LOG_CONN(max_streams_receive, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(maximum, frame.count); + PTLSLOG_ELEMENT_SIGNED(is_unidirectional, uni); + }); if ((ret = update_max_streams(uni ? &conn->egress.max_streams.uni : &conn->egress.max_streams.bidi, frame.count)) != 0) return ret; @@ -5260,6 +5453,10 @@ static int handle_new_token_frame(quicly_conn_t *conn, struct st_quicly_handle_p if ((ret = quicly_decode_new_token_frame(&state->src, state->end, &frame)) != 0) return ret; QUICLY_PROBE(NEW_TOKEN_RECEIVE, conn, conn->stash.now, frame.token.base, frame.token.len); + QUICLY_LOG_CONN(new_token_receive, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SAFESTR(token, PTLS_HEXDUMP(frame.token.base, frame.token.len)); + }); if (conn->super.ctx->save_resumption_token == NULL) return 0; return conn->super.ctx->save_resumption_token->cb(conn->super.ctx->save_resumption_token, conn, frame.token); @@ -5274,6 +5471,11 @@ static int handle_stop_sending_frame(quicly_conn_t *conn, struct st_quicly_handl if ((ret = quicly_decode_stop_sending_frame(&state->src, state->end, &frame)) != 0) return ret; QUICLY_PROBE(STOP_SENDING_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.app_error_code); + QUICLY_LOG_CONN(stop_sending_receive, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(stream_id, frame.stream_id); + PTLSLOG_ELEMENT_UNSIGNED(error_code, frame.app_error_code); + }); if ((ret = quicly_get_or_open_stream(conn, frame.stream_id, &stream)) != 0 || stream == NULL) return ret; @@ -5283,6 +5485,11 @@ static int handle_stop_sending_frame(quicly_conn_t *conn, struct st_quicly_handl int err = QUICLY_ERROR_FROM_APPLICATION_ERROR_CODE(frame.app_error_code); quicly_reset_stream(stream, err); QUICLY_PROBE(STREAM_ON_SEND_STOP, stream->conn, stream->conn->stash.now, stream, err); + QUICLY_LOG_CONN(stream_on_send_stop, stream->conn, { + PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); + PTLSLOG_ELEMENT_PTR(stream, stream); + PTLSLOG_ELEMENT_SIGNED(err, err); + }); stream->callbacks->on_send_stop(stream, err); if (stream->conn->super.state >= QUICLY_STATE_CLOSING) return QUICLY_ERROR_IS_CLOSING; @@ -5300,6 +5507,10 @@ static int handle_max_data_frame(quicly_conn_t *conn, struct st_quicly_handle_pa return ret; QUICLY_PROBE(MAX_DATA_RECEIVE, conn, conn->stash.now, frame.max_data); + QUICLY_LOG_CONN(max_data_receive, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(maximum, frame.max_data); + }); if (frame.max_data <= conn->egress.max_data.permitted) return 0; @@ -5316,6 +5527,10 @@ static int negotiate_using_version(quicly_conn_t *conn, uint32_t version) /* set selected version, update transport parameters extension ID */ conn->super.version = version; QUICLY_PROBE(VERSION_SWITCH, conn, conn->stash.now, version); + QUICLY_LOG_CONN(version_switch, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(new_version, version); + }); /* replace initial keys */ if ((ret = reinstall_initial_encryption(conn, PTLS_ERROR_LIBRARY)) != 0) @@ -5490,6 +5705,12 @@ static int handle_transport_close_frame(quicly_conn_t *conn, struct st_quicly_ha QUICLY_PROBE(TRANSPORT_CLOSE_RECEIVE, conn, conn->stash.now, frame.error_code, frame.frame_type, QUICLY_PROBE_ESCAPE_UNSAFE_STRING(frame.reason_phrase.base, frame.reason_phrase.len)); + QUICLY_LOG_CONN(transport_close_receive, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(error_code, frame.error_code); + PTLSLOG_ELEMENT_UNSIGNED(frame_type, frame.frame_type); + PTLSLOG_ELEMENT_UNSAFESTR(reason_phrase, (const char *)frame.reason_phrase.base); + }); return handle_close(conn, QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(frame.error_code), frame.frame_type, frame.reason_phrase); } @@ -5503,6 +5724,11 @@ static int handle_application_close_frame(quicly_conn_t *conn, struct st_quicly_ QUICLY_PROBE(APPLICATION_CLOSE_RECEIVE, conn, conn->stash.now, frame.error_code, QUICLY_PROBE_ESCAPE_UNSAFE_STRING(frame.reason_phrase.base, frame.reason_phrase.len)); + QUICLY_LOG_CONN(application_close_receive, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(error_code, frame.error_code); + PTLSLOG_ELEMENT_UNSAFESTR(reason_phrase, (const char *)frame.reason_phrase.base); + }); return handle_close(conn, QUICLY_ERROR_FROM_APPLICATION_ERROR_CODE(frame.error_code), UINT64_MAX, frame.reason_phrase); } @@ -5514,6 +5740,7 @@ static int handle_padding_frame(quicly_conn_t *conn, struct st_quicly_handle_pay static int handle_ping_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) { QUICLY_PROBE(PING_RECEIVE, conn, conn->stash.now); + QUICLY_LOG_CONN(ping_receive, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); return 0; } @@ -5531,6 +5758,13 @@ static int handle_new_connection_id_frame(quicly_conn_t *conn, struct st_quicly_ QUICLY_PROBE(NEW_CONNECTION_ID_RECEIVE, conn, conn->stash.now, frame.sequence, frame.retire_prior_to, QUICLY_PROBE_HEXDUMP(frame.cid.base, frame.cid.len), QUICLY_PROBE_HEXDUMP(frame.stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN)); + QUICLY_LOG_CONN(new_connection_id_receive, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(sequence, frame.sequence); + PTLSLOG_ELEMENT_UNSIGNED(retire_prior_to, frame.retire_prior_to); + PTLSLOG_ELEMENT_SAFESTR(cid, PTLS_HEXDUMP(frame.cid.base, frame.cid.len)); + PTLSLOG_ELEMENT_SAFESTR(stateless_reset_token, PTLS_HEXDUMP(frame.stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN)); + }); if (frame.sequence < conn->super.remote.largest_retire_prior_to) { /* An endpoint that receives a NEW_CONNECTION_ID frame with a sequence number smaller than the Retire Prior To @@ -5568,6 +5802,10 @@ static int handle_retire_connection_id_frame(quicly_conn_t *conn, struct st_quic return ret; QUICLY_PROBE(RETIRE_CONNECTION_ID_RECEIVE, conn, conn->stash.now, frame.sequence); + QUICLY_LOG_CONN(retire_connection_id_receive, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(sequence, frame.sequence); + }); if (frame.sequence >= conn->super.local.cid_set.plaintext.path_id) { /* Receipt of a RETIRE_CONNECTION_ID frame containing a sequence number greater than any previously sent to the remote peer @@ -5588,6 +5826,7 @@ static int handle_handshake_done_frame(quicly_conn_t *conn, struct st_quicly_han int ret; QUICLY_PROBE(HANDSHAKE_DONE_RECEIVE, conn, conn->stash.now); + QUICLY_LOG_CONN(handshake_done_receive, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); if (!quicly_is_client(conn)) return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; @@ -5616,6 +5855,10 @@ static int handle_datagram_frame(quicly_conn_t *conn, struct st_quicly_handle_pa if ((ret = quicly_decode_datagram_frame(state->frame_type, &state->src, state->end, &frame)) != 0) return ret; QUICLY_PROBE(DATAGRAM_RECEIVE, conn, conn->stash.now, frame.payload.base, frame.payload.len); + QUICLY_LOG_CONN(datagram_receive, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(payload_len, frame.payload.len); + }); /* handle the frame. Applications might call quicly_close or other functions that modify the connection state. */ conn->super.ctx->receive_datagram_frame->cb(conn->super.ctx->receive_datagram_frame, conn, frame.payload); @@ -5637,6 +5880,14 @@ static int handle_ack_frequency_frame(quicly_conn_t *conn, struct st_quicly_hand QUICLY_PROBE(ACK_FREQUENCY_RECEIVE, conn, conn->stash.now, frame.sequence, frame.packet_tolerance, frame.max_ack_delay, (int)frame.ignore_order, (int)frame.ignore_ce); + QUICLY_LOG_CONN(ack_frequency_receive, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(sequence, frame.sequence); + PTLSLOG_ELEMENT_UNSIGNED(packet_tolerance, frame.packet_tolerance); + PTLSLOG_ELEMENT_UNSIGNED(max_ack_delay, frame.max_ack_delay); + PTLSLOG_ELEMENT_SIGNED(ignore_order, (int)frame.ignore_order); + PTLSLOG_ELEMENT_SIGNED(ignore_ce, (int)frame.ignore_ce); + }); /* Reject Request Max Ack Delay below our TP.min_ack_delay (which is at the moment equal to LOCAL_MAX_ACK_DELAY). */ if (frame.max_ack_delay < QUICLY_LOCAL_MAX_ACK_DELAY * 1000) @@ -5786,6 +6037,7 @@ static int handle_payload(quicly_conn_t *conn, size_t epoch, const uint8_t *_src static int handle_stateless_reset(quicly_conn_t *conn) { QUICLY_PROBE(STATELESS_RESET_RECEIVE, conn, conn->stash.now); + QUICLY_LOG_CONN(stateless_reset_receive, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); return handle_close(conn, QUICLY_ERROR_RECEIVED_STATELESS_RESET, UINT64_MAX, ptls_iovec_init("", 0)); } @@ -5870,7 +6122,18 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * QUICLY_PROBE(ACCEPT, *conn, (*conn)->stash.now, QUICLY_PROBE_HEXDUMP(packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len), address_token); + QUICLY_LOG_CONN(accept, *conn, { + PTLSLOG_ELEMENT_SIGNED(time, (*conn)->stash.now); + PTLSLOG_ELEMENT_SAFESTR(dcid, PTLS_HEXDUMP(packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len)); + PTLSLOG_ELEMENT_PTR(address_token, address_token); + }); QUICLY_PROBE(PACKET_RECEIVED, *conn, (*conn)->stash.now, pn, payload.base, payload.len, get_epoch(packet->octets.base[0])); + QUICLY_LOG_CONN(packet_received, *conn, { + PTLSLOG_ELEMENT_SIGNED(time, (*conn)->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(pn, pn); + PTLSLOG_ELEMENT_UNSIGNED(decrypted_len, payload.len); + PTLSLOG_ELEMENT_UNSIGNED(packet_type, get_epoch(packet->octets.base[0])); + }); /* handle the input; we ignore is_ack_only, we consult if there's any output from TLS in response to CH anyways */ (*conn)->super.stats.num_packets.received += 1; @@ -5917,6 +6180,11 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka QUICLY_PROBE(RECEIVE, conn, conn->stash.now, QUICLY_PROBE_HEXDUMP(packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len), packet->octets.base, packet->octets.len); + QUICLY_LOG_CONN(receive, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_SAFESTR(dcid, PTLS_HEXDUMP(packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len)); + PTLSLOG_ELEMENT_SAFESTR(bytes, PTLS_HEXDUMP(packet->octets.base, packet->octets.len)); + }); if (is_stateless_reset(conn, packet)) { ret = handle_stateless_reset(conn); @@ -6074,6 +6342,11 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka } QUICLY_PROBE(PACKET_RECEIVED, conn, conn->stash.now, pn, payload.base, payload.len, get_epoch(packet->octets.base[0])); + QUICLY_LOG_CONN(packet_received, conn, { + PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(decrypted_len, payload.len); + PTLSLOG_ELEMENT_UNSIGNED(packet_type, get_epoch(packet->octets.base[0])); + }); /* update states */ if (conn->super.state == QUICLY_STATE_FIRSTFLIGHT) @@ -6209,6 +6482,8 @@ int quicly_open_stream(quicly_conn_t *conn, quicly_stream_t **_stream, int uni) /* application-layer initialization */ QUICLY_PROBE(STREAM_ON_OPEN, conn, conn->stash.now, stream); + QUICLY_LOG_CONN(stream_on_open, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); + if ((ret = conn->super.ctx->stream_open->cb(conn->super.ctx->stream_open, stream)) != 0) return ret; diff --git a/quicly-probes.d b/quicly-probes.d index b9629e714..a8f688e8d 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -70,7 +70,7 @@ provider quicly { probe cc_congestion(struct st_quicly_conn_t *conn, int64_t at, uint64_t max_lost_pn, size_t inflight, uint32_t cwnd); probe ack_block_received(struct st_quicly_conn_t *conn, int64_t at, uint64_t ack_block_begin, uint64_t ack_block_end); - probe ack_delay_received(struct st_quicly_conn_t *conn, int64_t at, int64_t ack_delay); + probe ack_delay_received(struct st_quicly_conn_t *conn, int64_t at, uint64_t ack_delay); probe ack_send(struct st_quicly_conn_t *conn, int64_t at, uint64_t largest_acked, uint64_t ack_delay); probe ping_send(struct st_quicly_conn_t *conn, int64_t at); @@ -90,10 +90,10 @@ provider quicly { probe stream_lost(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t off, size_t len); probe reset_stream_send(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint16_t error_code, uint64_t final_size); - probe reset_stream_receive(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint16_t error_code, uint64_t final_size); + probe reset_stream_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t stream_id, uint16_t error_code, uint64_t final_size); probe stop_sending_send(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint16_t error_code); - probe stop_sending_receive(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint16_t error_code); + probe stop_sending_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t stream_id, uint16_t error_code); probe max_data_send(struct st_quicly_conn_t *conn, int64_t at, uint64_t maximum); probe max_data_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t maximum); @@ -102,7 +102,7 @@ provider quicly { probe max_streams_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t maximum, int is_unidirectional); probe max_stream_data_send(struct st_quicly_conn_t *conn, int64_t at, struct st_quicly_stream_t *stream, uint64_t maximum); - probe max_stream_data_receive(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t maximum); + probe max_stream_data_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t stream_id, uint64_t maximum); probe new_token_send(struct st_quicly_conn_t *conn, int64_t at, uint8_t *token, size_t token_len, uint64_t generation); probe new_token_acked(struct st_quicly_conn_t *conn, int64_t at, uint64_t generation); From 575108d7dd109e9637725952e8817b45760a62a7 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Thu, 28 Jul 2022 06:56:35 +0000 Subject: [PATCH 250/361] make sure ptlslog is compatible with qlog-adapter.py --- t/qlog-adaprter.t | 103 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100755 t/qlog-adaprter.t diff --git a/t/qlog-adaprter.t b/t/qlog-adaprter.t new file mode 100755 index 000000000..d7889379a --- /dev/null +++ b/t/qlog-adaprter.t @@ -0,0 +1,103 @@ +#! /usr/bin/env perl + +use strict; +use warnings; +use Digest::MD5 qw(md5_hex); +use File::Temp qw(tempdir); +use IO::Socket::INET; +use JSON; +use Net::EmptyPort qw(empty_port); +use POSIX ":sys_wait_h"; +use Scope::Guard qw(scope_guard); +use Test::More; +use Time::HiRes qw(sleep); + +$ENV{BINARY_DIR} ||= "."; +my $cli = "$ENV{BINARY_DIR}/cli"; +my $port = empty_port({ + host => "127.0.0.1", + proto => "udp", +}); +my $tempdir = tempdir(CLEANUP => 1); + +subtest "hello" => sub { + my $guard = spawn_server(); + my $resp = `$cli -j $tempdir/events -p /12 127.0.0.1 $port 2> /dev/null`; + is $resp, "hello world\n"; + + subtest "events" => sub { + my $events_jsonl = slurp_file("$tempdir/events"); + diag("raw events:\n$events_jsonl") if $ENV{TEST_DEBUG}; + + my @events = map { decode_json($_) } split /\n/, $events_jsonl; + + my ($event) = find_event(\@events, "quicly", "connect"); + ok $event, "quicly:connect exists"; + is $event->{version}, 1; + + ($event) = find_event(\@events, "quicly", "free"); + ok $event, "quicly:free exists"; + }; + + subtest "qlog-adapter", sub { + my $qlog = `misc/qlog-adapter.py < $tempdir/events`; + is $?, 0, "qlog-adapter can transform raw event logs"; + diag("qlog:\n$qlog") if $ENV{TEST_DEBUG}; + my @events = map { decode_json($_) } split /\n/, $qlog; + cmp_ok scalar(@events), ">=", 2, "it has at least two events"; + # TODO: validate the events according to the qlog spec + }; +}; + + +done_testing; + +sub find_event { + my($events, $module, $type) = @_; + + my @results; + for my $event (@$events) { + if ($event->{module} eq $module && $event->{type} eq $type) { + push @results, $event; + } + } + return @results; +} + +sub spawn_server { + my @cmd; + if (grep(/^-W$/, @_)) { + @cmd = ($cli, "-k", "t/assets/ec256-key-pair.pem", "-c", "t/assets/ec256-pub.pem", @_, "127.0.0.1", $port); + } else { + @cmd = ($cli, "-k", "t/assets/server.key", "-c", "t/assets/server.crt", @_, "127.0.0.1", $port); + } + my $pid = fork; + die "fork failed:$!" + unless defined $pid; + if ($pid == 0) { + exec @cmd; + die "failed to exec $cmd[0]:$?"; + } + while (`netstat -na` !~ /^udp.*\s127\.0\.0\.1[\.:]$port\s/m) { + if (waitpid($pid, WNOHANG) == $pid) { + die "failed to launch server"; + } + sleep 0.1; + } + return scope_guard(sub { + kill 9, $pid; + while (waitpid($pid, 0) != $pid) {} + }); +} + +sub slurp_file { + my $fn = shift; + open my $fh, "<", $fn + or die "failed to open file:$fn:$!"; + do { + local $/; + <$fh>; + }; +} + +1; From 6d3be6a9fff76344db0d5c39b88976ca21cc9749 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Wed, 3 Aug 2022 06:04:38 +0000 Subject: [PATCH 251/361] update picotls --- deps/picotls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/picotls b/deps/picotls index 5490f219b..b394a8ce3 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit 5490f219ba8d401db86f577f423532e161d31b6e +Subproject commit b394a8ce3ffc9ac769b7c8e969ddf515f3fab9c7 From c26aacb4bfb9c099b15a7ac283c2ad425f1c37b8 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Wed, 3 Aug 2022 06:05:04 +0000 Subject: [PATCH 252/361] fix event strucutres to match what qlog-adapter.py expects --- include/quicly.h | 6 +++--- lib/quicly.c | 27 ++++++++++++++------------- misc/qlog-adapter.py | 14 ++++++++++---- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index fcbc91bb6..1e91e69eb 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -1238,14 +1238,14 @@ extern const quicly_stream_callbacks_t quicly_stream_noop_callbacks; #define QUICLY_LOG(type, block) PTLSLOG(quicly, type, block) -#define QUICLY_LOG_CONN(type, _conn, block) \ +#define QUICLY_LOG_CONN(_type, _conn, _block) \ do { \ quicly_conn_t *__conn = (_conn); \ if (!ptls_skip_tracing(__conn->crypto.tls)) \ - QUICLY_LOG(type, { \ + QUICLY_LOG(_type, { \ PTLSLOG_ELEMENT_PTR(conn, __conn); \ do { \ - block \ + _block \ } while (0); \ }); \ } while (0) diff --git a/lib/quicly.c b/lib/quicly.c index 7f32ac3ec..0707593f4 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1132,7 +1132,7 @@ static void destroy_stream(quicly_stream_t *stream, int err) QUICLY_PROBE(STREAM_ON_DESTROY, conn, conn->stash.now, stream, err); QUICLY_LOG_CONN(stream_on_destroy, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_PTR(stream, stream); + PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLSLOG_ELEMENT_SIGNED(err, err); }); @@ -1713,7 +1713,7 @@ static int apply_stream_frame(quicly_stream_t *stream, quicly_stream_frame_t *fr QUICLY_PROBE(STREAM_RECEIVE, stream->conn, stream->conn->stash.now, stream, frame->offset, frame->data.len); QUICLY_LOG_CONN(stream_receive, stream->conn, { PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); - PTLSLOG_ELEMENT_PTR(stream, stream); + PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLSLOG_ELEMENT_UNSIGNED(off, frame->offset); PTLSLOG_ELEMENT_UNSIGNED(len, frame->data.len); }); @@ -1754,7 +1754,7 @@ static int apply_stream_frame(quicly_stream_t *stream, quicly_stream_frame_t *fr QUICLY_PROBE(STREAM_ON_RECEIVE, stream->conn, stream->conn->stash.now, stream, (size_t)buf_offset, apply_src, apply_len); QUICLY_LOG_CONN(stream_on_receive, stream->conn, { PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); - PTLSLOG_ELEMENT_PTR(stream, stream); + PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLSLOG_ELEMENT_UNSIGNED(off, buf_offset); PTLSLOG_ELEMENT_UNSIGNED(src_len, apply_len); }); @@ -2664,7 +2664,7 @@ static int on_ack_stream_ack_one(quicly_conn_t *conn, quicly_stream_id_t stream_ stream->callbacks->on_send_shift(stream, bytes_to_shift); QUICLY_LOG_CONN(stream_on_send_shift, stream->conn, { PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); - PTLSLOG_ELEMENT_PTR(stream, stream); + PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLSLOG_ELEMENT_UNSIGNED(delta, bytes_to_shift); }); } @@ -3189,7 +3189,7 @@ static int commit_send_packet(quicly_conn_t *conn, quicly_send_context_t *s, int PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_UNSIGNED(pn, conn->egress.packet_number); PTLSLOG_ELEMENT_UNSIGNED(len, s->dst - s->target.first_byte_at); - PTLSLOG_ELEMENT_UNSIGNED(type, get_epoch(*s->target.first_byte_at)); + PTLSLOG_ELEMENT_UNSIGNED(packet_type, get_epoch(*s->target.first_byte_at)); PTLSLOG_ELEMENT_SIGNED(ack_only, !s->target.ack_eliciting); }); @@ -3537,7 +3537,7 @@ static int send_control_frames_of_stream(quicly_stream_t *stream, quicly_send_co QUICLY_PROBE(MAX_STREAM_DATA_SEND, stream->conn, stream->conn->stash.now, stream, new_value); QUICLY_LOG_CONN(max_stream_data_send, stream->conn, { PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); - PTLSLOG_ELEMENT_PTR(stream, stream); + PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLSLOG_ELEMENT_UNSIGNED(maximum, new_value); }); } @@ -3763,7 +3763,7 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) QUICLY_PROBE(STREAM_ON_SEND_EMIT, stream->conn, stream->conn->stash.now, stream, emit_off, len); QUICLY_LOG_CONN(stream_on_send_emit, stream->conn, { PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); - PTLSLOG_ELEMENT_PTR(stream, stream); + PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLSLOG_ELEMENT_UNSIGNED(off, off); PTLSLOG_ELEMENT_UNSIGNED(capacity, len); }); @@ -3803,7 +3803,7 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) QUICLY_PROBE(STREAM_SEND, stream->conn, stream->conn->stash.now, stream, off, len, is_fin); QUICLY_LOG_CONN(stream_send, stream->conn, { PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); - PTLSLOG_ELEMENT_PTR(stream, stream); + PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLSLOG_ELEMENT_UNSIGNED(off, off); PTLSLOG_ELEMENT_UNSIGNED(len, len); PTLSLOG_ELEMENT_SIGNED(is_fin, is_fin); @@ -5058,7 +5058,7 @@ int quicly_get_or_open_stream(quicly_conn_t *conn, uint64_t stream_id, quicly_st QUICLY_PROBE(STREAM_ON_OPEN, conn, conn->stash.now, *stream); QUICLY_LOG_CONN(stream_on_open, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_PTR(stream, *stream); + PTLSLOG_ELEMENT_SIGNED(stream_id, (*stream)->stream_id); }); if ((ret = conn->super.ctx->stream_open->cb(conn->super.ctx->stream_open, *stream)) != 0) { *stream = NULL; @@ -5129,7 +5129,7 @@ static int handle_reset_stream_frame(quicly_conn_t *conn, struct st_quicly_handl QUICLY_PROBE(STREAM_ON_RECEIVE_RESET, stream->conn, stream->conn->stash.now, stream, err); QUICLY_LOG_CONN(stream_on_receive_reset, stream->conn, { PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); - PTLSLOG_ELEMENT_PTR(stream, stream); + PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLSLOG_ELEMENT_SIGNED(err, err); }); stream->callbacks->on_receive_reset(stream, err); @@ -5182,8 +5182,8 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload QUICLY_PROBE(ACK_BLOCK_RECEIVED, conn, conn->stash.now, pn_acked, pn_block_max); QUICLY_LOG_CONN(ack_block_received, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(pn_acked, pn_acked); - PTLSLOG_ELEMENT_UNSIGNED(pn_block_max, pn_block_max); + PTLSLOG_ELEMENT_UNSIGNED(ack_block_begin, pn_acked); + PTLSLOG_ELEMENT_UNSIGNED(ack_block_end, pn_block_max); }); while (quicly_sentmap_get(&iter)->packet_number < pn_acked) quicly_sentmap_skip(&iter); @@ -5487,7 +5487,7 @@ static int handle_stop_sending_frame(quicly_conn_t *conn, struct st_quicly_handl QUICLY_PROBE(STREAM_ON_SEND_STOP, stream->conn, stream->conn->stash.now, stream, err); QUICLY_LOG_CONN(stream_on_send_stop, stream->conn, { PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); - PTLSLOG_ELEMENT_PTR(stream, stream); + PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLSLOG_ELEMENT_SIGNED(err, err); }); stream->callbacks->on_send_stop(stream, err); @@ -6344,6 +6344,7 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka QUICLY_PROBE(PACKET_RECEIVED, conn, conn->stash.now, pn, payload.base, payload.len, get_epoch(packet->octets.base[0])); QUICLY_LOG_CONN(packet_received, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLSLOG_ELEMENT_UNSIGNED(pn, pn); PTLSLOG_ELEMENT_UNSIGNED(decrypted_len, payload.len); PTLSLOG_ELEMENT_UNSIGNED(packet_type, get_epoch(packet->octets.base[0])); }); diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index e47eff928..813e80806 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -57,7 +57,6 @@ def handle_packet_received(events, idx): handler = FRAME_EVENT_HANDLERS.get(ev["type"]) if handler: frames.append(handler(ev)) - ret = { "time": events[idx]["time"], "name": "transport:packet_received", @@ -199,7 +198,7 @@ def handle_new_token_receive(event): return { "frame_type": "new_token", "token": event["token"], - "generation": event["generation"] + # "generation": event["generation"] } def handle_new_token_send(event): @@ -363,7 +362,14 @@ def usage(): def load_quicly_events(infile): events = [] for line in infile: - events.append(json.loads(line)) + object = json.loads(line) + # normalize the key format to kebab-case + normalized_object = {} + for key, value in object.items(): + normalized_object[key.replace("_", "-")] = value + if "type" in normalized_object: + normalized_object["type"] = normalized_object["type"].replace("_", "-") + events.append(normalized_object) return events def main(): @@ -394,7 +400,7 @@ def main(): "time_format": "absolute" } } - })) + }, separators=(',', ':'))) for i, event in enumerate(source_events): handler = QLOG_EVENT_HANDLERS.get(event["type"]) if handler: From c6bd983b8179045071ac9e2f2cdcf29081b52670 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Thu, 4 Aug 2022 06:33:06 +0000 Subject: [PATCH 253/361] update picotls --- deps/picotls | 2 +- lib/quicly.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/deps/picotls b/deps/picotls index b394a8ce3..215a07026 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit b394a8ce3ffc9ac769b7c8e969ddf515f3fab9c7 +Subproject commit 215a070262d19455deab5befe180a5139d47d05a diff --git a/lib/quicly.c b/lib/quicly.c index 0707593f4..c6a738ea9 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -4343,7 +4343,7 @@ static int send_connection_close(quicly_conn_t *conn, size_t epoch, quicly_send_ PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_UNSIGNED(error_code, error_code); PTLSLOG_ELEMENT_UNSIGNED(frame_type, offending_frame_type); - PTLSLOG_ELEMENT_UNSAFESTR(reason_phrase, reason_phrase); + PTLSLOG_ELEMENT_UNSAFESTR(reason_phrase, reason_phrase, strlen(reason_phrase)); }); } else { ++conn->super.stats.num_frames_sent.application_close; @@ -4351,7 +4351,7 @@ static int send_connection_close(quicly_conn_t *conn, size_t epoch, quicly_send_ QUICLY_LOG_CONN(application_close_send, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_UNSIGNED(error_code, error_code); - PTLSLOG_ELEMENT_UNSAFESTR(reason_phrase, reason_phrase); + PTLSLOG_ELEMENT_UNSAFESTR(reason_phrase, reason_phrase, strlen(reason_phrase)); }); } @@ -5709,7 +5709,7 @@ static int handle_transport_close_frame(quicly_conn_t *conn, struct st_quicly_ha PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_UNSIGNED(error_code, frame.error_code); PTLSLOG_ELEMENT_UNSIGNED(frame_type, frame.frame_type); - PTLSLOG_ELEMENT_UNSAFESTR(reason_phrase, (const char *)frame.reason_phrase.base); + PTLSLOG_ELEMENT_UNSAFESTR(reason_phrase, (const char *)frame.reason_phrase.base, frame.reason_phrase.len); }); return handle_close(conn, QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(frame.error_code), frame.frame_type, frame.reason_phrase); } @@ -5727,7 +5727,7 @@ static int handle_application_close_frame(quicly_conn_t *conn, struct st_quicly_ QUICLY_LOG_CONN(application_close_receive, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_UNSIGNED(error_code, frame.error_code); - PTLSLOG_ELEMENT_UNSAFESTR(reason_phrase, (const char *)frame.reason_phrase.base); + PTLSLOG_ELEMENT_UNSAFESTR(reason_phrase, (const char *)frame.reason_phrase.base, frame.reason_phrase.len); }); return handle_close(conn, QUICLY_ERROR_FROM_APPLICATION_ERROR_CODE(frame.error_code), UINT64_MAX, frame.reason_phrase); } From 049a0e62fce37735d68ca3df494ed3fbc6363f5a Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Tue, 9 Aug 2022 04:32:50 +0000 Subject: [PATCH 254/361] update picotls and follow the changes --- deps/picotls | 2 +- lib/quicly.c | 31 ++++++++++++++++--------------- src/cli.c | 11 ++--------- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/deps/picotls b/deps/picotls index 215a07026..ec3e4db54 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit 215a070262d19455deab5befe180a5139d47d05a +Subproject commit ec3e4db547aab89dbca81b4db7e5ed941d680f76 diff --git a/lib/quicly.c b/lib/quicly.c index c6a738ea9..f4e619b52 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -93,7 +93,11 @@ KHASH_MAP_INIT_INT64(quicly_stream_t, quicly_stream_t *) #else #define QUICLY_PROBE(label, conn, ...) QUICLY_TRACER(label, conn, __VA_ARGS__) #endif -#define QUICLY_PROBE_HEXDUMP(s, l) PTLS_HEXDUMP((s), (l)) +#define QUICLY_PROBE_HEXDUMP(s, l) \ + ({ \ + size_t _l = (l); \ + ptls_hexdump(alloca(_l * 2 + 1), (s), _l); \ + }) #define QUICLY_PROBE_ESCAPE_UNSAFE_STRING(s, l) \ ({ \ size_t _l = (l); \ @@ -3305,8 +3309,7 @@ static int do_allocate_frame(quicly_conn_t *conn, quicly_send_context_t *s, size QUICLY_LOG_CONN(packet_prepare, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_UNSIGNED(first_octet, s->current.first_byte); - PTLSLOG_ELEMENT_SAFESTR( - dcid, PTLS_HEXDUMP(conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len)); + PTLSLOG_ELEMENT_HEXDUMP(dcid, conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len); }); /* emit header */ @@ -4093,7 +4096,7 @@ static int send_resumption_token(quicly_conn_t *conn, quicly_send_context_t *s) QUICLY_PROBE(NEW_TOKEN_SEND, conn, conn->stash.now, tokenbuf.base, tokenbuf.off, sent->data.new_token.generation); QUICLY_LOG_CONN(new_token_send, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_SAFESTR(token, PTLS_HEXDUMP(tokenbuf.base, tokenbuf.off)); + PTLSLOG_ELEMENT_HEXDUMP(token, tokenbuf.base, tokenbuf.off); PTLSLOG_ELEMENT_UNSIGNED(generation, sent->data.new_token.generation); }); ret = 0; @@ -4382,9 +4385,8 @@ static int send_new_connection_id(quicly_conn_t *conn, quicly_send_context_t *s, PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_UNSIGNED(sequence, new_cid->sequence); PTLSLOG_ELEMENT_UNSIGNED(retire_prior_to, retire_prior_to); - PTLSLOG_ELEMENT_SAFESTR(cid, PTLS_HEXDUMP(new_cid->cid.cid, new_cid->cid.len)); - PTLSLOG_ELEMENT_SAFESTR(stateless_reset_token, - PTLS_HEXDUMP(new_cid->stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN)); + PTLSLOG_ELEMENT_HEXDUMP(cid, new_cid->cid.cid, new_cid->cid.len); + PTLSLOG_ELEMENT_HEXDUMP(stateless_reset_token, new_cid->stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN); }); return 0; @@ -4819,8 +4821,7 @@ int quicly_send(quicly_conn_t *conn, quicly_address_t *dest, quicly_address_t *s QUICLY_LOG_CONN(send, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_SIGNED(state, conn->super.state); - PTLSLOG_ELEMENT_SAFESTR( - dcid, PTLS_HEXDUMP(conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len)); + PTLSLOG_ELEMENT_HEXDUMP(dcid, conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len); }); if (conn->super.state >= QUICLY_STATE_CLOSING) { @@ -5455,7 +5456,7 @@ static int handle_new_token_frame(quicly_conn_t *conn, struct st_quicly_handle_p QUICLY_PROBE(NEW_TOKEN_RECEIVE, conn, conn->stash.now, frame.token.base, frame.token.len); QUICLY_LOG_CONN(new_token_receive, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_SAFESTR(token, PTLS_HEXDUMP(frame.token.base, frame.token.len)); + PTLSLOG_ELEMENT_HEXDUMP(token, frame.token.base, frame.token.len); }); if (conn->super.ctx->save_resumption_token == NULL) return 0; @@ -5762,8 +5763,8 @@ static int handle_new_connection_id_frame(quicly_conn_t *conn, struct st_quicly_ PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_UNSIGNED(sequence, frame.sequence); PTLSLOG_ELEMENT_UNSIGNED(retire_prior_to, frame.retire_prior_to); - PTLSLOG_ELEMENT_SAFESTR(cid, PTLS_HEXDUMP(frame.cid.base, frame.cid.len)); - PTLSLOG_ELEMENT_SAFESTR(stateless_reset_token, PTLS_HEXDUMP(frame.stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN)); + PTLSLOG_ELEMENT_HEXDUMP(cid, frame.cid.base, frame.cid.len); + PTLSLOG_ELEMENT_HEXDUMP(stateless_reset_token, frame.stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN); }); if (frame.sequence < conn->super.remote.largest_retire_prior_to) { @@ -6124,7 +6125,7 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * QUICLY_PROBE_HEXDUMP(packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len), address_token); QUICLY_LOG_CONN(accept, *conn, { PTLSLOG_ELEMENT_SIGNED(time, (*conn)->stash.now); - PTLSLOG_ELEMENT_SAFESTR(dcid, PTLS_HEXDUMP(packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len)); + PTLSLOG_ELEMENT_HEXDUMP(dcid, packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len); PTLSLOG_ELEMENT_PTR(address_token, address_token); }); QUICLY_PROBE(PACKET_RECEIVED, *conn, (*conn)->stash.now, pn, payload.base, payload.len, get_epoch(packet->octets.base[0])); @@ -6182,8 +6183,8 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka packet->octets.len); QUICLY_LOG_CONN(receive, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_SAFESTR(dcid, PTLS_HEXDUMP(packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len)); - PTLSLOG_ELEMENT_SAFESTR(bytes, PTLS_HEXDUMP(packet->octets.base, packet->octets.len)); + PTLSLOG_ELEMENT_HEXDUMP(dcid, packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len); + PTLSLOG_ELEMENT_HEXDUMP(bytes, packet->octets.base, packet->octets.len); }); if (is_stateless_reset(conn, packet)) { diff --git a/src/cli.c b/src/cli.c index 423e474db..139f44a76 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1025,6 +1025,7 @@ static void usage(const char *cmd) " -G enable UDP generic segmentation offload\n" " -i interval interval to reissue requests (in milliseconds)\n" " -I timeout idle timeout (in milliseconds; default: 600,000)\n" + " -j log-file file to log probe events in JSON-Lines\n" " -K num-packets perform key update every num-packets packets\n" " -l log-file file to log traffic secrets\n" " -M max stream data (in bytes; default: 1MB)\n" @@ -1074,14 +1075,7 @@ static void setup_ptlslog(const char *fn) fprintf(stderr, "failed to open file:%s:%s\n", fn, strerror(errno)); exit(1); } - ptlslog_fd = fd; -} - -static void setup_ptlslog_from_env(void) -{ - const char *fn = getenv("PTLSLOG"); - if (fn) - setup_ptlslog(fn); + ptlslog_add_fd(fd); } int main(int argc, char **argv) @@ -1103,7 +1097,6 @@ int main(int argc, char **argv) setup_session_cache(ctx.tls); quicly_amend_ptls_context(ctx.tls); - setup_ptlslog_from_env(); { uint8_t secret[PTLS_MAX_DIGEST_SIZE]; From 3191349deedec4bd2a31c2e3123c0a3f4d3987cf Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Wed, 17 Aug 2022 08:52:18 +0000 Subject: [PATCH 255/361] update picotls --- deps/picotls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/picotls b/deps/picotls index ec3e4db54..6d51eb750 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit ec3e4db547aab89dbca81b4db7e5ed941d680f76 +Subproject commit 6d51eb7501b117e2851044c16e933fe87ef2c760 From cd6ca9b370c40ff329c97e5d890fee162d8e25d5 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 14 Sep 2022 16:06:58 +0900 Subject: [PATCH 256/361] update pcitols --- deps/picotls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/picotls b/deps/picotls index 7970614ad..1c89c85c0 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit 7970614ad049d194fe1691bdf0cc66c6930a3a2f +Subproject commit 1c89c85c0a0686af25998678c27260d6e24fc854 From 1911d72fb9b588335bc7e7454e3f3b7eeafe99c4 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Tue, 27 Sep 2022 07:57:06 +0000 Subject: [PATCH 257/361] update picotls --- deps/picotls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/picotls b/deps/picotls index 6d51eb750..a705f8641 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit 6d51eb7501b117e2851044c16e933fe87ef2c760 +Subproject commit a705f864158d054de5b8a32504f917c4ef659600 From 29aada5965fcbd20ab9447999ea031823d0b51b6 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Thu, 29 Sep 2022 02:30:47 +0000 Subject: [PATCH 258/361] use PTLSLOG_ELEMENT_BOOL for boolean values --- deps/picotls | 2 +- lib/quicly.c | 16 ++++++++-------- t/e2e.t | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/deps/picotls b/deps/picotls index a705f8641..afa31ec9f 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit a705f864158d054de5b8a32504f917c4ef659600 +Subproject commit afa31ec9f8b9dffcb1d072c620134c7bf193788f diff --git a/lib/quicly.c b/lib/quicly.c index f475976ca..c83bac9e3 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3195,7 +3195,7 @@ static int commit_send_packet(quicly_conn_t *conn, quicly_send_context_t *s, int PTLSLOG_ELEMENT_UNSIGNED(pn, conn->egress.packet_number); PTLSLOG_ELEMENT_UNSIGNED(len, s->dst - s->target.first_byte_at); PTLSLOG_ELEMENT_UNSIGNED(packet_type, get_epoch(*s->target.first_byte_at)); - PTLSLOG_ELEMENT_SIGNED(ack_only, !s->target.ack_eliciting); + PTLSLOG_ELEMENT_BOOL(ack_only, !s->target.ack_eliciting); }); ++conn->egress.packet_number; @@ -3810,7 +3810,7 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLSLOG_ELEMENT_UNSIGNED(off, off); PTLSLOG_ELEMENT_UNSIGNED(len, len); - PTLSLOG_ELEMENT_SIGNED(is_fin, is_fin); + PTLSLOG_ELEMENT_BOOL(is_fin, is_fin); }); QUICLY_PROBE(QUICTRACE_SEND_STREAM, stream->conn, stream->conn->stash.now, stream, off, len, is_fin); @@ -3950,7 +3950,7 @@ static int send_max_streams(quicly_conn_t *conn, int uni, quicly_send_context_t QUICLY_LOG_CONN(max_streams_send, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_UNSIGNED(maximum, new_count); - PTLSLOG_ELEMENT_SIGNED(is_unidirectional, uni); + PTLSLOG_ELEMENT_BOOL(is_unidirectional, uni); }); return 0; @@ -3984,7 +3984,7 @@ static int send_streams_blocked(quicly_conn_t *conn, int uni, quicly_send_contex QUICLY_LOG_CONN(streams_blocked_send, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_UNSIGNED(maximum, max_streams->count); - PTLSLOG_ELEMENT_SIGNED(is_unidirectional, uni); + PTLSLOG_ELEMENT_BOOL(is_unidirectional, uni); }); return 0; @@ -4433,7 +4433,7 @@ static int update_traffic_key_cb(ptls_update_traffic_key_t *self, ptls_t *tls, i QUICLY_PROBE_HEXDUMP(secret, cipher->hash->digest_size)); QUICLY_LOG_CONN(crypto_update_secret, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(is_enc, is_enc); + PTLSLOG_ELEMENT_BOOL(is_enc, is_enc); PTLSLOG_ELEMENT_UNSIGNED(epoch, epoch); PTLSLOG_ELEMENT_SAFESTR(label, log_label); }); @@ -5221,7 +5221,7 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload QUICLY_LOG_CONN(packet_acked, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_UNSIGNED(pn, pn_acked); - PTLSLOG_ELEMENT_SIGNED(is_late_ack, is_late_ack); + PTLSLOG_ELEMENT_BOOL(is_late_ack, is_late_ack); }); if (sent->cc_bytes_in_flight != 0) { bytes_acked += sent->cc_bytes_in_flight; @@ -5391,7 +5391,7 @@ static int handle_streams_blocked_frame(quicly_conn_t *conn, struct st_quicly_ha QUICLY_LOG_CONN(streams_blocked_receive, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_UNSIGNED(maximum, frame.count); - PTLSLOG_ELEMENT_SIGNED(is_unidirectional, uni); + PTLSLOG_ELEMENT_BOOL(is_unidirectional, uni); }); if (should_send_max_streams(conn, uni)) { @@ -5415,7 +5415,7 @@ static int handle_max_streams_frame(quicly_conn_t *conn, struct st_quicly_handle QUICLY_LOG_CONN(max_streams_receive, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); PTLSLOG_ELEMENT_UNSIGNED(maximum, frame.count); - PTLSLOG_ELEMENT_SIGNED(is_unidirectional, uni); + PTLSLOG_ELEMENT_BOOL(is_unidirectional, uni); }); if ((ret = update_max_streams(uni ? &conn->egress.max_streams.uni : &conn->egress.max_streams.bidi, frame.count)) != 0) diff --git a/t/e2e.t b/t/e2e.t index 05a35f3bf..f6dec3739 100755 --- a/t/e2e.t +++ b/t/e2e.t @@ -214,7 +214,7 @@ subtest "no-compatible-version" => sub { }; subtest "idle-timeout" => sub { - my $guard = spawn_server(qw(-I 1000 -e), "$tempdir/server-events"); + my $guard = spawn_server(qw(-I 2000 -e), "$tempdir/server-events"); my $resp = `$cli -e $tempdir/client-events -p /12 -i 2000 127.0.0.1 $port 2> /dev/null`; # Because we start using idle timeout at the moment we dispose handshake key (currently 3PTO after handshake), there is an # uncertainty in if the first request-response is covered by the idle timeout. Therefore, we check if we have either one or From 18f4fa60ead301c229e8c85444fa9b7523a2e345 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Thu, 29 Sep 2022 05:43:48 +0000 Subject: [PATCH 259/361] revert unnecessary changes --- t/e2e.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/e2e.t b/t/e2e.t index f6dec3739..05a35f3bf 100755 --- a/t/e2e.t +++ b/t/e2e.t @@ -214,7 +214,7 @@ subtest "no-compatible-version" => sub { }; subtest "idle-timeout" => sub { - my $guard = spawn_server(qw(-I 2000 -e), "$tempdir/server-events"); + my $guard = spawn_server(qw(-I 1000 -e), "$tempdir/server-events"); my $resp = `$cli -e $tempdir/client-events -p /12 -i 2000 127.0.0.1 $port 2> /dev/null`; # Because we start using idle timeout at the moment we dispose handshake key (currently 3PTO after handshake), there is an # uncertainty in if the first request-response is covered by the idle timeout. Therefore, we check if we have either one or From 51d691bb7f44fde42eb6955334ab8f10c8e02713 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Thu, 29 Sep 2022 05:48:41 +0000 Subject: [PATCH 260/361] fix missing `break` --- src/cli.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cli.c b/src/cli.c index 139f44a76..e69be008d 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1186,6 +1186,7 @@ int main(int argc, char **argv) fprintf(stderr, "failed to parse idle timeout: %s\n", optarg); exit(1); } + break; case 'j': setup_ptlslog(optarg); break; From af4c3c4e0ad55245a4364c3829460de0e0c42d77 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Thu, 29 Sep 2022 06:00:58 +0000 Subject: [PATCH 261/361] tidy JSON output --- misc/qlog-adapter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/qlog-adapter.py b/misc/qlog-adapter.py index 813e80806..13e99f10e 100755 --- a/misc/qlog-adapter.py +++ b/misc/qlog-adapter.py @@ -404,7 +404,7 @@ def main(): for i, event in enumerate(source_events): handler = QLOG_EVENT_HANDLERS.get(event["type"]) if handler: - print(json.dumps(handler(source_events, i))) + print(json.dumps(handler(source_events, i), separators=(',', ':'))) if __name__ == "__main__": main() From 6108cc9de94a277799b8e1dfc67ac8f44be53f5d Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Thu, 29 Sep 2022 06:01:12 +0000 Subject: [PATCH 262/361] test qlog_version (too simple, but better than nothing) --- t/qlog-adaprter.t | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/t/qlog-adaprter.t b/t/qlog-adaprter.t index d7889379a..613c9eabb 100755 --- a/t/qlog-adaprter.t +++ b/t/qlog-adaprter.t @@ -45,7 +45,10 @@ subtest "hello" => sub { diag("qlog:\n$qlog") if $ENV{TEST_DEBUG}; my @events = map { decode_json($_) } split /\n/, $qlog; cmp_ok scalar(@events), ">=", 2, "it has at least two events"; - # TODO: validate the events according to the qlog spec + + # https://github.com/quicwg/qlog/blob/main/draft-ietf-quic-qlog-main-schema.md#the-high-level-qlog-schema-top-level + ok $events[0]->{qlog_version}, "it has qlog_version"; + # TODO: validate the events according to the qlog schema }; }; From 20e2d44ee6c4f899f35b27c9f72c8214786f2173 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Thu, 29 Sep 2022 06:55:06 +0000 Subject: [PATCH 263/361] update picotls --- deps/picotls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/picotls b/deps/picotls index afa31ec9f..2226024f2 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit afa31ec9f8b9dffcb1d072c620134c7bf193788f +Subproject commit 2226024f26869f531b54def5c833f717302be6a7 From 59ca90510f32e2f8ecbcf4ab821d1297e845e65c Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Fri, 30 Sep 2022 01:26:49 +0000 Subject: [PATCH 264/361] fix C++ compatibility, and making sure it compiles in tests --- CMakeLists.txt | 7 ++++++- include/quicly/loss.h | 25 +++++++++++++++---------- t/cpp-compat.cc | 7 +++++++ 3 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 t/cpp-compat.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index fe05fe682..8ff9968e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,9 @@ SET(CMAKE_C_FLAGS "-std=c99 -Wall -g -DQUICLY_USE_TRACER=1 ${CC_WARNING_FLAGS} $ SET(CMAKE_C_FLAGS_DEBUG "-O0") SET(CMAKE_C_FLAGS_RELEASE "-O2") +# C++ flags are used only in tests +SET(CMAKE_CXX_FLAGS "-Wall") + INCLUDE_DIRECTORIES( ${OPENSSL_INCLUDE_DIR} deps/klib @@ -135,9 +138,11 @@ TARGET_LINK_LIBRARIES(examples-echo quicly ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS} ADD_EXECUTABLE(udpfw t/udpfw.c) +ADD_EXECUTABLE(cpp-compat t/cpp-compat.cc) + ADD_CUSTOM_TARGET(check env BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR} WITH_DTRACE=${WITH_DTRACE} prove --exec "sh -c" -v ${CMAKE_CURRENT_BINARY_DIR}/*.t t/*.t WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS cli test.t) + DEPENDS cli test.t cpp-compat) ADD_CUSTOM_TARGET(format clang-format -i `git ls-files include lib src t | egrep '\\.[ch]$$'`) diff --git a/include/quicly/loss.h b/include/quicly/loss.h index 2fac428f3..011367675 100644 --- a/include/quicly/loss.h +++ b/include/quicly/loss.h @@ -247,16 +247,21 @@ inline uint32_t quicly_rtt_get_pto(quicly_rtt_t *rtt, uint32_t max_ack_delay, ui inline void quicly_loss_init(quicly_loss_t *r, const quicly_loss_conf_t *conf, uint32_t initial_rtt, const uint16_t *max_ack_delay, const uint8_t *ack_delay_exponent) { - *r = (quicly_loss_t){.conf = conf, - .max_ack_delay = max_ack_delay, - .ack_delay_exponent = ack_delay_exponent, - .pto_count = 0, - .thresholds = {.use_packet_based = 1, .time_based_percentile = 1024 / 8 /* start from 1/8 RTT */}, - .time_of_last_packet_sent = 0, - .largest_acked_packet_plus1 = {0}, - .total_bytes_sent = 0, - .loss_time = INT64_MAX, - .alarm_at = INT64_MAX}; + *r = (quicly_loss_t){ + .conf = conf, + .max_ack_delay = max_ack_delay, + .ack_delay_exponent = ack_delay_exponent, + .thresholds = + { + .use_packet_based = 1, .time_based_percentile = 1024 / 8, /* start from 1/8 RTT */ + }, + .pto_count = 0, + .time_of_last_packet_sent = 0, + .largest_acked_packet_plus1 = {0}, + .total_bytes_sent = 0, + .loss_time = INT64_MAX, + .alarm_at = INT64_MAX, + }; quicly_rtt_init(&r->rtt, conf, initial_rtt); quicly_sentmap_init(&r->sentmap); } diff --git a/t/cpp-compat.cc b/t/cpp-compat.cc new file mode 100644 index 000000000..107c977e7 --- /dev/null +++ b/t/cpp-compat.cc @@ -0,0 +1,7 @@ +extern "C" { +#include "quicly.h" +} + +int main() { + return 0; +} From 4f9563be3535587634ee98fd78f4632d41f77ada Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Fri, 30 Sep 2022 04:58:30 +0000 Subject: [PATCH 265/361] update picotls --- CMakeLists.txt | 6 ++++-- deps/picotls | 2 +- include/quicly.h | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ff9968e5..61db68add 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,7 @@ OPTION(WITH_FUSION "whether or not to use the Fusion AES-GCM engine in the cli b IF(NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE Release) ENDIF(NOT CMAKE_BUILD_TYPE) -SET(CMAKE_C_FLAGS "-std=c99 -Wall -g -DQUICLY_USE_TRACER=1 ${CC_WARNING_FLAGS} ${CMAKE_C_FLAGS}") +SET(CMAKE_C_FLAGS "-std=c99 -Wall -g -DPICOTLS_USE_PTLSLOG -DQUICLY_USE_TRACER=1 ${CC_WARNING_FLAGS} ${CMAKE_C_FLAGS}") SET(CMAKE_C_FLAGS_DEBUG "-O0") SET(CMAKE_C_FLAGS_RELEASE "-O2") @@ -51,7 +51,9 @@ INCLUDE_DIRECTORIES( SET(PICOTLS_OPENSSL_FILES deps/picotls/lib/openssl.c deps/picotls/lib/pembase64.c - deps/picotls/lib/picotls.c) + deps/picotls/lib/picotls.c + deps/picotls/lib/ptlslog.c +) SET(QUICLY_LIBRARY_FILES lib/frame.c diff --git a/deps/picotls b/deps/picotls index 2226024f2..dbe9a4916 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit 2226024f26869f531b54def5c833f717302be6a7 +Subproject commit dbe9a4916ea9d6e0ba1e806e9eb32ac2515dd36d diff --git a/include/quicly.h b/include/quicly.h index f46f72eac..b24f85bdf 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -33,6 +33,7 @@ extern "C" { #include #include #include "picotls.h" +#include "picotls/ptlslog.h" #include "quicly/constants.h" #include "quicly/frame.h" #include "quicly/local_cid.h" From e9d167f0b1eb6a7d70adb231a5eea18bf9353c39 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 7 Oct 2022 11:12:44 +0900 Subject: [PATCH 266/361] add test case that checks C++ compatibility of the header files --- quicly.xcodeproj/project.pbxproj | 2 ++ t/cplusplus.t | 12 ++++++++++++ 2 files changed, 14 insertions(+) create mode 100755 t/cplusplus.t diff --git a/quicly.xcodeproj/project.pbxproj b/quicly.xcodeproj/project.pbxproj index a6cf2236e..32706da63 100644 --- a/quicly.xcodeproj/project.pbxproj +++ b/quicly.xcodeproj/project.pbxproj @@ -185,6 +185,7 @@ 0829878C26DF775B0053638F /* rate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = rate.h; sourceTree = ""; }; 0829878D26E03D4D0053638F /* rate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = rate.c; sourceTree = ""; }; 0829879126E0A9DF0053638F /* rate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = rate.c; sourceTree = ""; }; + 085125F728EFC0480074C124 /* cplusplus.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = cplusplus.t; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.perl; }; E904233C24AED0410072C5B7 /* loss.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = loss.c; sourceTree = ""; }; E904234024AEFB980072C5B7 /* loss.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = loss.c; sourceTree = ""; }; E9056C071F56965300E2B96C /* linklist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = linklist.h; sourceTree = ""; }; @@ -463,6 +464,7 @@ E9CC44121EC1926000DC7D3E /* t */ = { isa = PBXGroup; children = ( + 085125F728EFC0480074C124 /* cplusplus.t */, E98884C221E3F23A0060F010 /* e2e.t */, E99F8C281F4EAEF800C26B3D /* frame.c */, E9736533246FD3DA0039AA49 /* local_cid.c */, diff --git a/t/cplusplus.t b/t/cplusplus.t new file mode 100755 index 000000000..ad6085312 --- /dev/null +++ b/t/cplusplus.t @@ -0,0 +1,12 @@ +#! /usr/bin/perl + +use strict; +use warnings; +use Test::More; + +plan skip_all => "g++ not found" + unless system("which g++ > /dev/null 2>&1") == 0; + +is system(qw(g++ -Iinclude -Ideps/picotls/include --include quicly.h -c -x c++ -Wall /dev/null)), 0; + +done_testing; From c9167711778857000de278c4242dfd34ad86b2cc Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 7 Oct 2022 11:15:11 +0900 Subject: [PATCH 267/361] C++ requires that the order is same as is defined --- include/quicly/loss.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/quicly/loss.h b/include/quicly/loss.h index 2fac428f3..cbc307a5c 100644 --- a/include/quicly/loss.h +++ b/include/quicly/loss.h @@ -250,8 +250,8 @@ inline void quicly_loss_init(quicly_loss_t *r, const quicly_loss_conf_t *conf, u *r = (quicly_loss_t){.conf = conf, .max_ack_delay = max_ack_delay, .ack_delay_exponent = ack_delay_exponent, - .pto_count = 0, .thresholds = {.use_packet_based = 1, .time_based_percentile = 1024 / 8 /* start from 1/8 RTT */}, + .pto_count = 0, .time_of_last_packet_sent = 0, .largest_acked_packet_plus1 = {0}, .total_bytes_sent = 0, From 65f2a7e3b7bb8f887272171f68e364930ab85aac Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 7 Oct 2022 12:34:43 +0900 Subject: [PATCH 268/361] Revert "fix C++ compatibility, and making sure it compiles in tests" This reverts commit 59ca90510f32e2f8ecbcf4ab821d1297e845e65c. --- CMakeLists.txt | 7 +------ include/quicly/loss.h | 25 ++++++++++--------------- t/cpp-compat.cc | 7 ------- 3 files changed, 11 insertions(+), 28 deletions(-) delete mode 100644 t/cpp-compat.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ff9968e5..fe05fe682 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,9 +37,6 @@ SET(CMAKE_C_FLAGS "-std=c99 -Wall -g -DQUICLY_USE_TRACER=1 ${CC_WARNING_FLAGS} $ SET(CMAKE_C_FLAGS_DEBUG "-O0") SET(CMAKE_C_FLAGS_RELEASE "-O2") -# C++ flags are used only in tests -SET(CMAKE_CXX_FLAGS "-Wall") - INCLUDE_DIRECTORIES( ${OPENSSL_INCLUDE_DIR} deps/klib @@ -138,11 +135,9 @@ TARGET_LINK_LIBRARIES(examples-echo quicly ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS} ADD_EXECUTABLE(udpfw t/udpfw.c) -ADD_EXECUTABLE(cpp-compat t/cpp-compat.cc) - ADD_CUSTOM_TARGET(check env BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR} WITH_DTRACE=${WITH_DTRACE} prove --exec "sh -c" -v ${CMAKE_CURRENT_BINARY_DIR}/*.t t/*.t WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS cli test.t cpp-compat) + DEPENDS cli test.t) ADD_CUSTOM_TARGET(format clang-format -i `git ls-files include lib src t | egrep '\\.[ch]$$'`) diff --git a/include/quicly/loss.h b/include/quicly/loss.h index 011367675..2fac428f3 100644 --- a/include/quicly/loss.h +++ b/include/quicly/loss.h @@ -247,21 +247,16 @@ inline uint32_t quicly_rtt_get_pto(quicly_rtt_t *rtt, uint32_t max_ack_delay, ui inline void quicly_loss_init(quicly_loss_t *r, const quicly_loss_conf_t *conf, uint32_t initial_rtt, const uint16_t *max_ack_delay, const uint8_t *ack_delay_exponent) { - *r = (quicly_loss_t){ - .conf = conf, - .max_ack_delay = max_ack_delay, - .ack_delay_exponent = ack_delay_exponent, - .thresholds = - { - .use_packet_based = 1, .time_based_percentile = 1024 / 8, /* start from 1/8 RTT */ - }, - .pto_count = 0, - .time_of_last_packet_sent = 0, - .largest_acked_packet_plus1 = {0}, - .total_bytes_sent = 0, - .loss_time = INT64_MAX, - .alarm_at = INT64_MAX, - }; + *r = (quicly_loss_t){.conf = conf, + .max_ack_delay = max_ack_delay, + .ack_delay_exponent = ack_delay_exponent, + .pto_count = 0, + .thresholds = {.use_packet_based = 1, .time_based_percentile = 1024 / 8 /* start from 1/8 RTT */}, + .time_of_last_packet_sent = 0, + .largest_acked_packet_plus1 = {0}, + .total_bytes_sent = 0, + .loss_time = INT64_MAX, + .alarm_at = INT64_MAX}; quicly_rtt_init(&r->rtt, conf, initial_rtt); quicly_sentmap_init(&r->sentmap); } diff --git a/t/cpp-compat.cc b/t/cpp-compat.cc deleted file mode 100644 index 107c977e7..000000000 --- a/t/cpp-compat.cc +++ /dev/null @@ -1,7 +0,0 @@ -extern "C" { -#include "quicly.h" -} - -int main() { - return 0; -} From fe1f557132a53aa834cb04ad396c40669946b193 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 7 Oct 2022 16:01:40 +0900 Subject: [PATCH 269/361] update picotls --- deps/picotls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/picotls b/deps/picotls index 2226024f2..aa08aa501 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit 2226024f26869f531b54def5c833f717302be6a7 +Subproject commit aa08aa501238f0e0bd2e78238fa9bd0f46466b55 From 0fbc4b70c80b9ab8e7a4c42a72770a423fc6a18b Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 7 Oct 2022 12:42:48 +0900 Subject: [PATCH 270/361] follow the name changes --- include/quicly.h | 4 +- lib/quicly.c | 430 +++++++++++++++++++++++------------------------ src/cli.c | 2 +- 3 files changed, 218 insertions(+), 218 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index f46f72eac..d188a1f77 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -1244,14 +1244,14 @@ void quicly_stream_noop_on_receive_reset(quicly_stream_t *stream, int err); extern const quicly_stream_callbacks_t quicly_stream_noop_callbacks; -#define QUICLY_LOG(type, block) PTLSLOG(quicly, type, block) +#define QUICLY_LOG(type, block) PTLS_LOG(quicly, type, block) #define QUICLY_LOG_CONN(_type, _conn, _block) \ do { \ quicly_conn_t *__conn = (_conn); \ if (!ptls_skip_tracing(__conn->crypto.tls)) \ QUICLY_LOG(_type, { \ - PTLSLOG_ELEMENT_PTR(conn, __conn); \ + PTLS_LOG_ELEMENT_PTR(conn, __conn); \ do { \ _block \ } while (0); \ diff --git a/lib/quicly.c b/lib/quicly.c index c83bac9e3..f95cca13a 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -982,8 +982,8 @@ void crypto_stream_receive(quicly_stream_t *stream, size_t off, const void *src, quicly_streambuf_ingress_shift(stream, input.len); QUICLY_PROBE(CRYPTO_HANDSHAKE, conn, conn->stash.now, handshake_result); QUICLY_LOG_CONN(crypto_handshake, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(ret, handshake_result); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(ret, handshake_result); }); switch (handshake_result) { case 0: @@ -1135,9 +1135,9 @@ static void destroy_stream(quicly_stream_t *stream, int err) QUICLY_PROBE(STREAM_ON_DESTROY, conn, conn->stash.now, stream, err); QUICLY_LOG_CONN(stream_on_destroy, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); - PTLSLOG_ELEMENT_SIGNED(err, err); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); + PTLS_LOG_ELEMENT_SIGNED(err, err); }); if (stream->callbacks != NULL) @@ -1559,8 +1559,8 @@ static int update_1rtt_egress_key(quicly_conn_t *conn) QUICLY_PROBE(CRYPTO_SEND_KEY_UPDATE, conn, conn->stash.now, space->cipher.egress.key_phase, QUICLY_PROBE_HEXDUMP(space->cipher.egress.secret, cipher->hash->digest_size)); QUICLY_LOG_CONN(crypto_send_key_update, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(phase, space->cipher.egress.key_phase); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(phase, space->cipher.egress.key_phase); }); return 0; @@ -1578,8 +1578,8 @@ static int received_key_update(quicly_conn_t *conn, uint64_t newly_decrypted_key QUICLY_PROBE(CRYPTO_RECEIVE_KEY_UPDATE, conn, conn->stash.now, space->cipher.ingress.key_phase.decrypted, QUICLY_PROBE_HEXDUMP(space->cipher.ingress.secret, ptls_get_cipher(conn->crypto.tls)->hash->digest_size)); QUICLY_LOG_CONN(crypto_receive_key_update, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(phase, space->cipher.ingress.key_phase.decrypted); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(phase, space->cipher.ingress.key_phase.decrypted); }); if (space->cipher.egress.key_phase < space->cipher.ingress.key_phase.decrypted) { @@ -1600,7 +1600,7 @@ void quicly_free(quicly_conn_t *conn) lock_now(conn, 0); QUICLY_PROBE(FREE, conn, conn->stash.now); - QUICLY_LOG_CONN(free, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(free, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); #if QUICLY_USE_EMBEDDED_PROBES || QUICLY_USE_DTRACE if (QUICLY_CONN_STATS_ENABLED()) { @@ -1718,10 +1718,10 @@ static int apply_stream_frame(quicly_stream_t *stream, quicly_stream_frame_t *fr QUICLY_PROBE(STREAM_RECEIVE, stream->conn, stream->conn->stash.now, stream, frame->offset, frame->data.len); QUICLY_LOG_CONN(stream_receive, stream->conn, { - PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); - PTLSLOG_ELEMENT_UNSIGNED(off, frame->offset); - PTLSLOG_ELEMENT_UNSIGNED(len, frame->data.len); + PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); + PTLS_LOG_ELEMENT_UNSIGNED(off, frame->offset); + PTLS_LOG_ELEMENT_UNSIGNED(len, frame->data.len); }); if (quicly_recvstate_transfer_complete(&stream->recvstate)) @@ -1759,10 +1759,10 @@ static int apply_stream_frame(quicly_stream_t *stream, quicly_stream_frame_t *fr const void *apply_src = frame->data.base + frame->data.len - apply_len; QUICLY_PROBE(STREAM_ON_RECEIVE, stream->conn, stream->conn->stash.now, stream, (size_t)buf_offset, apply_src, apply_len); QUICLY_LOG_CONN(stream_on_receive, stream->conn, { - PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); - PTLSLOG_ELEMENT_UNSIGNED(off, buf_offset); - PTLSLOG_ELEMENT_UNSIGNED(src_len, apply_len); + PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); + PTLS_LOG_ELEMENT_UNSIGNED(off, buf_offset); + PTLS_LOG_ELEMENT_UNSIGNED(src_len, apply_len); }); stream->callbacks->on_receive(stream, (size_t)buf_offset, apply_src, apply_len); if (stream->conn->super.state >= QUICLY_STATE_CLOSING) @@ -2312,8 +2312,8 @@ int quicly_connect(quicly_conn_t **_conn, quicly_context_t *ctx, const char *ser QUICLY_PROBE(CONNECT, conn, conn->stash.now, conn->super.version); QUICLY_LOG_CONN(connect, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(version, conn->super.version); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(version, conn->super.version); }); if ((ret = setup_handshake_space_and_flow(conn, QUICLY_EPOCH_INITIAL)) != 0) @@ -2483,8 +2483,8 @@ static int aead_decrypt_1rtt(void *ctx, uint64_t pn, quicly_decoded_packet_t *pa QUICLY_PROBE(CRYPTO_RECEIVE_KEY_UPDATE_PREPARE, conn, conn->stash.now, space->cipher.ingress.key_phase.prepared, QUICLY_PROBE_HEXDUMP(space->cipher.ingress.secret, cipher->hash->digest_size)); QUICLY_LOG_CONN(crypto_receive_key_update_prepare, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(phase, space->cipher.ingress.key_phase.prepared); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(phase, space->cipher.ingress.key_phase.prepared); }); } } @@ -2669,9 +2669,9 @@ static int on_ack_stream_ack_one(quicly_conn_t *conn, quicly_stream_id_t stream_ QUICLY_PROBE(STREAM_ON_SEND_SHIFT, stream->conn, stream->conn->stash.now, stream, bytes_to_shift); stream->callbacks->on_send_shift(stream, bytes_to_shift); QUICLY_LOG_CONN(stream_on_send_shift, stream->conn, { - PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); - PTLSLOG_ELEMENT_UNSIGNED(delta, bytes_to_shift); + PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); + PTLS_LOG_ELEMENT_UNSIGNED(delta, bytes_to_shift); }); } if (stream_is_destroyable(stream)) { @@ -2705,10 +2705,10 @@ static int on_ack_stream(quicly_sentmap_t *map, const quicly_sent_packet_t *pack QUICLY_PROBE(STREAM_ACKED, conn, conn->stash.now, sent->data.stream.stream_id, sent->data.stream.args.start, sent->data.stream.args.end - sent->data.stream.args.start); QUICLY_LOG_CONN(stream_acked, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(stream_id, sent->data.stream.stream_id); - PTLSLOG_ELEMENT_UNSIGNED(off, sent->data.stream.args.start); - PTLSLOG_ELEMENT_UNSIGNED(len, sent->data.stream.args.end - sent->data.stream.args.start); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(stream_id, sent->data.stream.stream_id); + PTLS_LOG_ELEMENT_UNSIGNED(off, sent->data.stream.args.start); + PTLS_LOG_ELEMENT_UNSIGNED(len, sent->data.stream.args.end - sent->data.stream.args.start); }); if (packet->frames_in_flight && conn->stash.on_ack_stream.active_acked_cache.stream_id == sent->data.stream.stream_id && @@ -2734,10 +2734,10 @@ static int on_ack_stream(quicly_sentmap_t *map, const quicly_sent_packet_t *pack QUICLY_PROBE(STREAM_LOST, conn, conn->stash.now, sent->data.stream.stream_id, sent->data.stream.args.start, sent->data.stream.args.end - sent->data.stream.args.start); QUICLY_LOG_CONN(stream_lost, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(stream_id, sent->data.stream.stream_id); - PTLSLOG_ELEMENT_UNSIGNED(off, sent->data.stream.args.start); - PTLSLOG_ELEMENT_UNSIGNED(len, sent->data.stream.args.end - sent->data.stream.args.start); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(stream_id, sent->data.stream.stream_id); + PTLS_LOG_ELEMENT_UNSIGNED(off, sent->data.stream.args.start); + PTLS_LOG_ELEMENT_UNSIGNED(len, sent->data.stream.args.end - sent->data.stream.args.start); }); quicly_stream_t *stream; @@ -2907,8 +2907,8 @@ static int on_ack_new_token(quicly_sentmap_t *map, const quicly_sent_packet_t *p if (acked) { QUICLY_PROBE(NEW_TOKEN_ACKED, conn, conn->stash.now, sent->data.new_token.generation); QUICLY_LOG_CONN(new_token_acked, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(generation, sent->data.new_token.generation); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(generation, sent->data.new_token.generation); }); if (conn->egress.new_token.max_acked < sent->data.new_token.generation) conn->egress.new_token.max_acked = sent->data.new_token.generation; @@ -3191,11 +3191,11 @@ static int commit_send_packet(quicly_conn_t *conn, quicly_send_context_t *s, int QUICLY_PROBE(PACKET_SENT, conn, conn->stash.now, conn->egress.packet_number, s->dst - s->target.first_byte_at, get_epoch(*s->target.first_byte_at), !s->target.ack_eliciting); QUICLY_LOG_CONN(packet_sent, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(pn, conn->egress.packet_number); - PTLSLOG_ELEMENT_UNSIGNED(len, s->dst - s->target.first_byte_at); - PTLSLOG_ELEMENT_UNSIGNED(packet_type, get_epoch(*s->target.first_byte_at)); - PTLSLOG_ELEMENT_BOOL(ack_only, !s->target.ack_eliciting); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(pn, conn->egress.packet_number); + PTLS_LOG_ELEMENT_UNSIGNED(len, s->dst - s->target.first_byte_at); + PTLS_LOG_ELEMENT_UNSIGNED(packet_type, get_epoch(*s->target.first_byte_at)); + PTLS_LOG_ELEMENT_BOOL(ack_only, !s->target.ack_eliciting); }); ++conn->egress.packet_number; @@ -3308,9 +3308,9 @@ static int do_allocate_frame(quicly_conn_t *conn, quicly_send_context_t *s, size QUICLY_PROBE(PACKET_PREPARE, conn, conn->stash.now, s->current.first_byte, QUICLY_PROBE_HEXDUMP(conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len)); QUICLY_LOG_CONN(packet_prepare, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(first_octet, s->current.first_byte); - PTLSLOG_ELEMENT_HEXDUMP(dcid, conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(first_octet, s->current.first_byte); + PTLS_LOG_ELEMENT_HEXDUMP(dcid, conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len); }); /* emit header */ @@ -3430,9 +3430,9 @@ static int send_ack(quicly_conn_t *conn, struct st_quicly_pn_space_t *space, qui ++conn->super.stats.num_frames_sent.ack; QUICLY_PROBE(ACK_SEND, conn, conn->stash.now, space->ack_queue.ranges[space->ack_queue.num_ranges - 1].end - 1, ack_delay); QUICLY_LOG_CONN(ack_send, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(largest_acked, space->ack_queue.ranges[space->ack_queue.num_ranges - 1].end - 1); - PTLSLOG_ELEMENT_UNSIGNED(ack_delay, ack_delay); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(largest_acked, space->ack_queue.ranges[space->ack_queue.num_ranges - 1].end - 1); + PTLS_LOG_ELEMENT_UNSIGNED(ack_delay, ack_delay); }); /* when there are no less than QUICLY_NUM_ACK_BLOCKS_TO_INDUCE_ACKACK (8) gaps, bundle PING once every 4 packets being sent */ @@ -3441,7 +3441,7 @@ static int send_ack(quicly_conn_t *conn, struct st_quicly_pn_space_t *space, qui *dst++ = QUICLY_FRAME_TYPE_PING; ++conn->super.stats.num_frames_sent.ping; QUICLY_PROBE(PING_SEND, conn, conn->stash.now); - QUICLY_LOG_CONN(ping_send, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(ping_send, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); } s->dst = dst; @@ -3517,9 +3517,9 @@ static int send_control_frames_of_stream(quicly_stream_t *stream, quicly_send_co QUICLY_PROBE(STOP_SENDING_SEND, stream->conn, stream->conn->stash.now, stream->stream_id, stream->_send_aux.stop_sending.error_code); QUICLY_LOG_CONN(stop_sending_send, stream->conn, { - PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); - PTLSLOG_ELEMENT_UNSIGNED(error_code, stream->_send_aux.stop_sending.error_code); + PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); + PTLS_LOG_ELEMENT_UNSIGNED(error_code, stream->_send_aux.stop_sending.error_code); }); } @@ -3540,9 +3540,9 @@ static int send_control_frames_of_stream(quicly_stream_t *stream, quicly_send_co ++stream->conn->super.stats.num_frames_sent.max_stream_data; QUICLY_PROBE(MAX_STREAM_DATA_SEND, stream->conn, stream->conn->stash.now, stream, new_value); QUICLY_LOG_CONN(max_stream_data_send, stream->conn, { - PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); - PTLSLOG_ELEMENT_UNSIGNED(maximum, new_value); + PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); + PTLS_LOG_ELEMENT_UNSIGNED(maximum, new_value); }); } @@ -3557,10 +3557,10 @@ static int send_control_frames_of_stream(quicly_stream_t *stream, quicly_send_co QUICLY_PROBE(RESET_STREAM_SEND, stream->conn, stream->conn->stash.now, stream->stream_id, stream->_send_aux.reset_stream.error_code, stream->sendstate.size_inflight); QUICLY_LOG_CONN(reset_stream_send, stream->conn, { - PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); - PTLSLOG_ELEMENT_UNSIGNED(error_code, stream->_send_aux.reset_stream.error_code); - PTLSLOG_ELEMENT_UNSIGNED(final_size, stream->sendstate.size_inflight); + PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); + PTLS_LOG_ELEMENT_UNSIGNED(error_code, stream->_send_aux.reset_stream.error_code); + PTLS_LOG_ELEMENT_UNSIGNED(final_size, stream->sendstate.size_inflight); }); } @@ -3578,9 +3578,9 @@ static int send_control_frames_of_stream(quicly_stream_t *stream, quicly_send_co ++stream->conn->super.stats.num_frames_sent.stream_data_blocked; QUICLY_PROBE(STREAM_DATA_BLOCKED_SEND, stream->conn, stream->conn->stash.now, stream->stream_id, offset); QUICLY_LOG_CONN(stream_data_blocked_send, stream->conn, { - PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); - PTLSLOG_ELEMENT_UNSIGNED(maximum, offset); + PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); + PTLS_LOG_ELEMENT_UNSIGNED(maximum, offset); }); } @@ -3766,10 +3766,10 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) size_t emit_off = (size_t)(off - stream->sendstate.acked.ranges[0].end); QUICLY_PROBE(STREAM_ON_SEND_EMIT, stream->conn, stream->conn->stash.now, stream, emit_off, len); QUICLY_LOG_CONN(stream_on_send_emit, stream->conn, { - PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); - PTLSLOG_ELEMENT_UNSIGNED(off, off); - PTLSLOG_ELEMENT_UNSIGNED(capacity, len); + PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); + PTLS_LOG_ELEMENT_UNSIGNED(off, off); + PTLS_LOG_ELEMENT_UNSIGNED(capacity, len); }); stream->callbacks->on_send_emit(stream, emit_off, dst, &len, &wrote_all); if (stream->conn->super.state >= QUICLY_STATE_CLOSING) { @@ -3806,11 +3806,11 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) (stream->sendstate.size_inflight < off + len ? stream->sendstate.size_inflight : off + len) - off; QUICLY_PROBE(STREAM_SEND, stream->conn, stream->conn->stash.now, stream, off, len, is_fin); QUICLY_LOG_CONN(stream_send, stream->conn, { - PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); - PTLSLOG_ELEMENT_UNSIGNED(off, off); - PTLSLOG_ELEMENT_UNSIGNED(len, len); - PTLSLOG_ELEMENT_BOOL(is_fin, is_fin); + PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); + PTLS_LOG_ELEMENT_UNSIGNED(off, off); + PTLS_LOG_ELEMENT_UNSIGNED(len, len); + PTLS_LOG_ELEMENT_BOOL(is_fin, is_fin); }); QUICLY_PROBE(QUICTRACE_SEND_STREAM, stream->conn, stream->conn->stash.now, stream, off, len, is_fin); @@ -3904,17 +3904,17 @@ static void on_loss_detected(quicly_loss_t *loss, const quicly_sent_packet_t *lo conn->egress.max_udp_payload_size); QUICLY_PROBE(PACKET_LOST, conn, conn->stash.now, lost_packet->packet_number, lost_packet->ack_epoch); QUICLY_LOG_CONN(packet_lost, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(pn, lost_packet->packet_number); - PTLSLOG_ELEMENT_UNSIGNED(packet_type, lost_packet->ack_epoch); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(pn, lost_packet->packet_number); + PTLS_LOG_ELEMENT_UNSIGNED(packet_type, lost_packet->ack_epoch); }); QUICLY_PROBE(CC_CONGESTION, conn, conn->stash.now, lost_packet->packet_number + 1, conn->egress.loss.sentmap.bytes_in_flight, conn->egress.cc.cwnd); QUICLY_LOG_CONN(cc_congestion, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(max_lost_pn, lost_packet->packet_number + 1); - PTLSLOG_ELEMENT_UNSIGNED(flight, conn->egress.loss.sentmap.bytes_in_flight); - PTLSLOG_ELEMENT_UNSIGNED(cwnd, conn->egress.cc.cwnd); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(max_lost_pn, lost_packet->packet_number + 1); + PTLS_LOG_ELEMENT_UNSIGNED(flight, conn->egress.loss.sentmap.bytes_in_flight); + PTLS_LOG_ELEMENT_UNSIGNED(cwnd, conn->egress.cc.cwnd); }); QUICLY_PROBE(QUICTRACE_CC_LOST, conn, conn->stash.now, &conn->egress.loss.rtt, conn->egress.cc.cwnd, conn->egress.loss.sentmap.bytes_in_flight); @@ -3948,9 +3948,9 @@ static int send_max_streams(quicly_conn_t *conn, int uni, quicly_send_context_t } QUICLY_PROBE(MAX_STREAMS_SEND, conn, conn->stash.now, new_count, uni); QUICLY_LOG_CONN(max_streams_send, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(maximum, new_count); - PTLSLOG_ELEMENT_BOOL(is_unidirectional, uni); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(maximum, new_count); + PTLS_LOG_ELEMENT_BOOL(is_unidirectional, uni); }); return 0; @@ -3982,9 +3982,9 @@ static int send_streams_blocked(quicly_conn_t *conn, int uni, quicly_send_contex ++conn->super.stats.num_frames_sent.streams_blocked; QUICLY_PROBE(STREAMS_BLOCKED_SEND, conn, conn->stash.now, max_streams->count, uni); QUICLY_LOG_CONN(streams_blocked_send, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(maximum, max_streams->count); - PTLSLOG_ELEMENT_BOOL(is_unidirectional, uni); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(maximum, max_streams->count); + PTLS_LOG_ELEMENT_BOOL(is_unidirectional, uni); }); return 0; @@ -4030,7 +4030,7 @@ static int send_handshake_done(quicly_conn_t *conn, quicly_send_context_t *s) conn->egress.pending_flows &= ~QUICLY_PENDING_FLOW_HANDSHAKE_DONE_BIT; ++conn->super.stats.num_frames_sent.handshake_done; QUICLY_PROBE(HANDSHAKE_DONE_SEND, conn, conn->stash.now); - QUICLY_LOG_CONN(handshake_done_send, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(handshake_done_send, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); ret = 0; Exit: @@ -4052,8 +4052,8 @@ static int send_data_blocked(quicly_conn_t *conn, quicly_send_context_t *s) ++conn->super.stats.num_frames_sent.data_blocked; QUICLY_PROBE(DATA_BLOCKED_SEND, conn, conn->stash.now, offset); QUICLY_LOG_CONN(data_blocked_send, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(off, offset); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(off, offset); }); ret = 0; @@ -4096,9 +4096,9 @@ static int send_resumption_token(quicly_conn_t *conn, quicly_send_context_t *s) ++conn->super.stats.num_frames_sent.new_token; QUICLY_PROBE(NEW_TOKEN_SEND, conn, conn->stash.now, tokenbuf.base, tokenbuf.off, sent->data.new_token.generation); QUICLY_LOG_CONN(new_token_send, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_HEXDUMP(token, tokenbuf.base, tokenbuf.off); - PTLSLOG_ELEMENT_UNSIGNED(generation, sent->data.new_token.generation); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_HEXDUMP(token, tokenbuf.base, tokenbuf.off); + PTLS_LOG_ELEMENT_UNSIGNED(generation, sent->data.new_token.generation); }); ret = 0; Exit: @@ -4300,7 +4300,7 @@ static int send_handshake_flow(quicly_conn_t *conn, size_t epoch, quicly_send_co conn->egress.last_retransmittable_sent_at = conn->stash.now; ++conn->super.stats.num_frames_sent.ping; QUICLY_PROBE(PING_SEND, conn, conn->stash.now); - QUICLY_LOG_CONN(ping_send, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(ping_send, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); } } @@ -4344,18 +4344,18 @@ static int send_connection_close(quicly_conn_t *conn, size_t epoch, quicly_send_ ++conn->super.stats.num_frames_sent.transport_close; QUICLY_PROBE(TRANSPORT_CLOSE_SEND, conn, conn->stash.now, error_code, offending_frame_type, reason_phrase); QUICLY_LOG_CONN(transport_close_send, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(error_code, error_code); - PTLSLOG_ELEMENT_UNSIGNED(frame_type, offending_frame_type); - PTLSLOG_ELEMENT_UNSAFESTR(reason_phrase, reason_phrase, strlen(reason_phrase)); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(error_code, error_code); + PTLS_LOG_ELEMENT_UNSIGNED(frame_type, offending_frame_type); + PTLS_LOG_ELEMENT_UNSAFESTR(reason_phrase, reason_phrase, strlen(reason_phrase)); }); } else { ++conn->super.stats.num_frames_sent.application_close; QUICLY_PROBE(APPLICATION_CLOSE_SEND, conn, conn->stash.now, error_code, reason_phrase); QUICLY_LOG_CONN(application_close_send, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(error_code, error_code); - PTLSLOG_ELEMENT_UNSAFESTR(reason_phrase, reason_phrase, strlen(reason_phrase)); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(error_code, error_code); + PTLS_LOG_ELEMENT_UNSAFESTR(reason_phrase, reason_phrase, strlen(reason_phrase)); }); } @@ -4383,11 +4383,11 @@ static int send_new_connection_id(quicly_conn_t *conn, quicly_send_context_t *s, QUICLY_PROBE_HEXDUMP(new_cid->cid.cid, new_cid->cid.len), QUICLY_PROBE_HEXDUMP(new_cid->stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN)); QUICLY_LOG_CONN(new_connection_id_send, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(sequence, new_cid->sequence); - PTLSLOG_ELEMENT_UNSIGNED(retire_prior_to, retire_prior_to); - PTLSLOG_ELEMENT_HEXDUMP(cid, new_cid->cid.cid, new_cid->cid.len); - PTLSLOG_ELEMENT_HEXDUMP(stateless_reset_token, new_cid->stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(sequence, new_cid->sequence); + PTLS_LOG_ELEMENT_UNSIGNED(retire_prior_to, retire_prior_to); + PTLS_LOG_ELEMENT_HEXDUMP(cid, new_cid->cid.cid, new_cid->cid.len); + PTLS_LOG_ELEMENT_HEXDUMP(stateless_reset_token, new_cid->stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN); }); return 0; @@ -4409,8 +4409,8 @@ static int send_retire_connection_id(quicly_conn_t *conn, quicly_send_context_t ++conn->super.stats.num_frames_sent.retire_connection_id; QUICLY_PROBE(RETIRE_CONNECTION_ID_SEND, conn, conn->stash.now, sequence); QUICLY_LOG_CONN(retire_connection_id_send, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(sequence, sequence); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(sequence, sequence); }); return 0; @@ -4432,10 +4432,10 @@ static int update_traffic_key_cb(ptls_update_traffic_key_t *self, ptls_t *tls, i QUICLY_PROBE(CRYPTO_UPDATE_SECRET, conn, conn->stash.now, is_enc, epoch, log_label, QUICLY_PROBE_HEXDUMP(secret, cipher->hash->digest_size)); QUICLY_LOG_CONN(crypto_update_secret, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_BOOL(is_enc, is_enc); - PTLSLOG_ELEMENT_UNSIGNED(epoch, epoch); - PTLSLOG_ELEMENT_SAFESTR(label, log_label); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_BOOL(is_enc, is_enc); + PTLS_LOG_ELEMENT_UNSIGNED(epoch, epoch); + PTLS_LOG_ELEMENT_SAFESTR(label, log_label); }); if (tlsctx->log_event != NULL) { @@ -4524,7 +4524,7 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) /* handle timeouts */ if (conn->idle_timeout.at <= conn->stash.now) { QUICLY_PROBE(IDLE_TIMEOUT, conn, conn->stash.now); - QUICLY_LOG_CONN(idle_timeout, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(idle_timeout, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); goto CloseNow; } /* handle handshake timeouts */ @@ -4533,9 +4533,9 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) conn->stash.now) { QUICLY_PROBE(HANDSHAKE_TIMEOUT, conn, conn->stash.now, conn->stash.now - conn->created_at, conn->egress.loss.rtt.smoothed); QUICLY_LOG_CONN(handshake_timeout, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(elapsed, conn->stash.now - conn->created_at); - PTLSLOG_ELEMENT_UNSIGNED(rtt_smoothed, conn->egress.loss.rtt.smoothed); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(elapsed, conn->stash.now - conn->created_at); + PTLS_LOG_ELEMENT_UNSIGNED(rtt_smoothed, conn->egress.loss.rtt.smoothed); }); conn->super.stats.num_handshake_timeouts++; goto CloseNow; @@ -4543,8 +4543,8 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) if (conn->super.stats.num_packets.initial_handshake_sent > conn->super.ctx->max_initial_handshake_packets) { QUICLY_PROBE(INITIAL_HANDSHAKE_PACKET_EXCEED, conn, conn->stash.now, conn->super.stats.num_packets.initial_handshake_sent); QUICLY_LOG_CONN(initial_handshake_packet_exceed, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(num_packets, conn->super.stats.num_packets.initial_handshake_sent); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(num_packets, conn->super.stats.num_packets.initial_handshake_sent); }); conn->super.stats.num_initial_handshake_exceeded++; goto CloseNow; @@ -4564,10 +4564,10 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) QUICLY_PROBE(PTO, conn, conn->stash.now, conn->egress.loss.sentmap.bytes_in_flight, conn->egress.cc.cwnd, conn->egress.loss.pto_count); QUICLY_LOG_CONN(pto, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(inflight, conn->egress.loss.sentmap.bytes_in_flight); - PTLSLOG_ELEMENT_UNSIGNED(cwnd, conn->egress.cc.cwnd); - PTLSLOG_ELEMENT_SIGNED(pto_count, conn->egress.loss.pto_count); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(inflight, conn->egress.loss.sentmap.bytes_in_flight); + PTLS_LOG_ELEMENT_UNSIGNED(cwnd, conn->egress.cc.cwnd); + PTLS_LOG_ELEMENT_SIGNED(pto_count, conn->egress.loss.pto_count); }); ++conn->super.stats.num_ptos; size_t bytes_to_mark = min_packets_to_send * conn->egress.max_udp_payload_size; @@ -4622,8 +4622,8 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) s->dst = quicly_encode_datagram_frame(s->dst, *payload); QUICLY_PROBE(DATAGRAM_SEND, conn, conn->stash.now, payload->base, payload->len); QUICLY_LOG_CONN(datagram_send, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(payload_len, payload->len); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(payload_len, payload->len); }); } else { /* FIXME: At the moment, we add a padding because we do not have a way to reclaim allocated space, and because @@ -4640,7 +4640,7 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) *s->dst++ = QUICLY_FRAME_TYPE_PING; ++conn->super.stats.num_frames_sent.ping; QUICLY_PROBE(PING_SEND, conn, conn->stash.now); - QUICLY_LOG_CONN(ping_send, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(ping_send, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); } /* take actions only permitted for short header packets */ if (conn->application->one_rtt_writable) { @@ -4691,8 +4691,8 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) ++conn->super.stats.num_frames_sent.max_data; QUICLY_PROBE(MAX_DATA_SEND, conn, conn->stash.now, new_value); QUICLY_LOG_CONN(max_data_send, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(maximum, new_value); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(maximum, new_value); }); } if (conn->egress.data_blocked == QUICLY_SENDER_STATE_SEND && (ret = send_data_blocked(conn, s)) != 0) @@ -4820,9 +4820,9 @@ int quicly_send(quicly_conn_t *conn, quicly_address_t *dest, quicly_address_t *s QUICLY_PROBE(SEND, conn, conn->stash.now, conn->super.state, QUICLY_PROBE_HEXDUMP(conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len)); QUICLY_LOG_CONN(send, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(state, conn->super.state); - PTLSLOG_ELEMENT_HEXDUMP(dcid, conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(state, conn->super.state); + PTLS_LOG_ELEMENT_HEXDUMP(dcid, conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len); }); if (conn->super.state >= QUICLY_STATE_CLOSING) { @@ -5059,8 +5059,8 @@ int quicly_get_or_open_stream(quicly_conn_t *conn, uint64_t stream_id, quicly_st } QUICLY_PROBE(STREAM_ON_OPEN, conn, conn->stash.now, *stream); QUICLY_LOG_CONN(stream_on_open, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(stream_id, (*stream)->stream_id); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(stream_id, (*stream)->stream_id); }); if ((ret = conn->super.ctx->stream_open->cb(conn->super.ctx->stream_open, *stream)) != 0) { *stream = NULL; @@ -5113,10 +5113,10 @@ static int handle_reset_stream_frame(quicly_conn_t *conn, struct st_quicly_handl return ret; QUICLY_PROBE(RESET_STREAM_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.app_error_code, frame.final_size); QUICLY_LOG_CONN(reset_stream_receive, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(stream_id, frame.stream_id); - PTLSLOG_ELEMENT_UNSIGNED(app_error_code, frame.app_error_code); - PTLSLOG_ELEMENT_UNSIGNED(final_size, frame.final_size); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(stream_id, frame.stream_id); + PTLS_LOG_ELEMENT_UNSIGNED(app_error_code, frame.app_error_code); + PTLS_LOG_ELEMENT_UNSIGNED(final_size, frame.final_size); }); if ((ret = quicly_get_or_open_stream(conn, frame.stream_id, &stream)) != 0 || stream == NULL) @@ -5130,9 +5130,9 @@ static int handle_reset_stream_frame(quicly_conn_t *conn, struct st_quicly_handl int err = QUICLY_ERROR_FROM_APPLICATION_ERROR_CODE(frame.app_error_code); QUICLY_PROBE(STREAM_ON_RECEIVE_RESET, stream->conn, stream->conn->stash.now, stream, err); QUICLY_LOG_CONN(stream_on_receive_reset, stream->conn, { - PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); - PTLSLOG_ELEMENT_SIGNED(err, err); + PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); + PTLS_LOG_ELEMENT_SIGNED(err, err); }); stream->callbacks->on_receive_reset(stream, err); if (stream->conn->super.state >= QUICLY_STATE_CLOSING) @@ -5183,9 +5183,9 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload uint64_t pn_block_max = pn_acked + frame.ack_block_lengths[gap_index] - 1; QUICLY_PROBE(ACK_BLOCK_RECEIVED, conn, conn->stash.now, pn_acked, pn_block_max); QUICLY_LOG_CONN(ack_block_received, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(ack_block_begin, pn_acked); - PTLSLOG_ELEMENT_UNSIGNED(ack_block_end, pn_block_max); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(ack_block_begin, pn_acked); + PTLS_LOG_ELEMENT_UNSIGNED(ack_block_end, pn_block_max); }); while (quicly_sentmap_get(&iter)->packet_number < pn_acked) quicly_sentmap_skip(&iter); @@ -5219,9 +5219,9 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload largest_newly_acked.sent_at = sent->sent_at; QUICLY_PROBE(PACKET_ACKED, conn, conn->stash.now, pn_acked, is_late_ack); QUICLY_LOG_CONN(packet_acked, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(pn, pn_acked); - PTLSLOG_ELEMENT_BOOL(is_late_ack, is_late_ack); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(pn, pn_acked); + PTLS_LOG_ELEMENT_BOOL(is_late_ack, is_late_ack); }); if (sent->cc_bytes_in_flight != 0) { bytes_acked += sent->cc_bytes_in_flight; @@ -5236,8 +5236,8 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload space->cipher.egress.key_update_pn.next = conn->egress.packet_number + conn->super.ctx->max_packets_per_key; QUICLY_PROBE(CRYPTO_SEND_KEY_UPDATE_CONFIRMED, conn, conn->stash.now, space->cipher.egress.key_update_pn.next); QUICLY_LOG_CONN(crypto_send_key_update_confirmed, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(next_pn, space->cipher.egress.key_update_pn.next); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(next_pn, space->cipher.egress.key_update_pn.next); }); } } @@ -5254,8 +5254,8 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload QUICLY_PROBE(ACK_DELAY_RECEIVED, conn, conn->stash.now, frame.ack_delay); QUICLY_LOG_CONN(ack_delay_received, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(ack_delay, frame.ack_delay); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(ack_delay, frame.ack_delay); }); quicly_ratemeter_on_ack(&conn->egress.ratemeter, conn->stash.now, conn->super.stats.num_bytes.ack_received, @@ -5281,11 +5281,11 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload QUICLY_PROBE(CC_ACK_RECEIVED, conn, conn->stash.now, frame.largest_acknowledged, bytes_acked, conn->egress.cc.cwnd, conn->egress.loss.sentmap.bytes_in_flight); QUICLY_LOG_CONN(cc_ack_received, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(largest_acked, frame.largest_acknowledged); - PTLSLOG_ELEMENT_UNSIGNED(bytes_acked, bytes_acked); - PTLSLOG_ELEMENT_UNSIGNED(cwnd, conn->egress.cc.cwnd); - PTLSLOG_ELEMENT_UNSIGNED(inflight, conn->egress.loss.sentmap.bytes_in_flight); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(largest_acked, frame.largest_acknowledged); + PTLS_LOG_ELEMENT_UNSIGNED(bytes_acked, bytes_acked); + PTLS_LOG_ELEMENT_UNSIGNED(cwnd, conn->egress.cc.cwnd); + PTLS_LOG_ELEMENT_UNSIGNED(inflight, conn->egress.loss.sentmap.bytes_in_flight); }); /* loss-detection */ @@ -5308,9 +5308,9 @@ static int handle_max_stream_data_frame(quicly_conn_t *conn, struct st_quicly_ha QUICLY_PROBE(MAX_STREAM_DATA_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.max_stream_data); QUICLY_LOG_CONN(max_stream_data_receive, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(stream_id, frame.stream_id); - PTLSLOG_ELEMENT_UNSIGNED(max_stream_data, frame.max_stream_data); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(stream_id, frame.stream_id); + PTLS_LOG_ELEMENT_UNSIGNED(max_stream_data, frame.max_stream_data); }); if (!quicly_stream_has_send_side(quicly_is_client(conn), frame.stream_id)) @@ -5340,8 +5340,8 @@ static int handle_data_blocked_frame(quicly_conn_t *conn, struct st_quicly_handl QUICLY_PROBE(DATA_BLOCKED_RECEIVE, conn, conn->stash.now, frame.offset); QUICLY_LOG_CONN(data_blocked_receive, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(off, frame.offset); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(off, frame.offset); }); quicly_maxsender_request_transmit(&conn->ingress.max_data.sender); @@ -5362,9 +5362,9 @@ static int handle_stream_data_blocked_frame(quicly_conn_t *conn, struct st_quicl QUICLY_PROBE(STREAM_DATA_BLOCKED_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.offset); QUICLY_LOG_CONN(stream_data_blocked_receive, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(stream_id, frame.stream_id); - PTLSLOG_ELEMENT_UNSIGNED(maximum, frame.offset); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(stream_id, frame.stream_id); + PTLS_LOG_ELEMENT_UNSIGNED(maximum, frame.offset); }); if (!quicly_stream_has_receive_side(quicly_is_client(conn), frame.stream_id)) @@ -5389,9 +5389,9 @@ static int handle_streams_blocked_frame(quicly_conn_t *conn, struct st_quicly_ha QUICLY_PROBE(STREAMS_BLOCKED_RECEIVE, conn, conn->stash.now, frame.count, uni); QUICLY_LOG_CONN(streams_blocked_receive, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(maximum, frame.count); - PTLSLOG_ELEMENT_BOOL(is_unidirectional, uni); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(maximum, frame.count); + PTLS_LOG_ELEMENT_BOOL(is_unidirectional, uni); }); if (should_send_max_streams(conn, uni)) { @@ -5413,9 +5413,9 @@ static int handle_max_streams_frame(quicly_conn_t *conn, struct st_quicly_handle QUICLY_PROBE(MAX_STREAMS_RECEIVE, conn, conn->stash.now, frame.count, uni); QUICLY_LOG_CONN(max_streams_receive, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(maximum, frame.count); - PTLSLOG_ELEMENT_BOOL(is_unidirectional, uni); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(maximum, frame.count); + PTLS_LOG_ELEMENT_BOOL(is_unidirectional, uni); }); if ((ret = update_max_streams(uni ? &conn->egress.max_streams.uni : &conn->egress.max_streams.bidi, frame.count)) != 0) @@ -5460,8 +5460,8 @@ static int handle_new_token_frame(quicly_conn_t *conn, struct st_quicly_handle_p return ret; QUICLY_PROBE(NEW_TOKEN_RECEIVE, conn, conn->stash.now, frame.token.base, frame.token.len); QUICLY_LOG_CONN(new_token_receive, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_HEXDUMP(token, frame.token.base, frame.token.len); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_HEXDUMP(token, frame.token.base, frame.token.len); }); if (conn->super.ctx->save_resumption_token == NULL) return 0; @@ -5478,9 +5478,9 @@ static int handle_stop_sending_frame(quicly_conn_t *conn, struct st_quicly_handl return ret; QUICLY_PROBE(STOP_SENDING_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.app_error_code); QUICLY_LOG_CONN(stop_sending_receive, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(stream_id, frame.stream_id); - PTLSLOG_ELEMENT_UNSIGNED(error_code, frame.app_error_code); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(stream_id, frame.stream_id); + PTLS_LOG_ELEMENT_UNSIGNED(error_code, frame.app_error_code); }); if ((ret = quicly_get_or_open_stream(conn, frame.stream_id, &stream)) != 0 || stream == NULL) @@ -5492,9 +5492,9 @@ static int handle_stop_sending_frame(quicly_conn_t *conn, struct st_quicly_handl quicly_reset_stream(stream, err); QUICLY_PROBE(STREAM_ON_SEND_STOP, stream->conn, stream->conn->stash.now, stream, err); QUICLY_LOG_CONN(stream_on_send_stop, stream->conn, { - PTLSLOG_ELEMENT_SIGNED(time, stream->conn->stash.now); - PTLSLOG_ELEMENT_SIGNED(stream_id, stream->stream_id); - PTLSLOG_ELEMENT_SIGNED(err, err); + PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); + PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); + PTLS_LOG_ELEMENT_SIGNED(err, err); }); stream->callbacks->on_send_stop(stream, err); if (stream->conn->super.state >= QUICLY_STATE_CLOSING) @@ -5514,8 +5514,8 @@ static int handle_max_data_frame(quicly_conn_t *conn, struct st_quicly_handle_pa QUICLY_PROBE(MAX_DATA_RECEIVE, conn, conn->stash.now, frame.max_data); QUICLY_LOG_CONN(max_data_receive, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(maximum, frame.max_data); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(maximum, frame.max_data); }); if (frame.max_data <= conn->egress.max_data.permitted) @@ -5534,8 +5534,8 @@ static int negotiate_using_version(quicly_conn_t *conn, uint32_t version) conn->super.version = version; QUICLY_PROBE(VERSION_SWITCH, conn, conn->stash.now, version); QUICLY_LOG_CONN(version_switch, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(new_version, version); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(new_version, version); }); /* replace initial keys */ @@ -5712,10 +5712,10 @@ static int handle_transport_close_frame(quicly_conn_t *conn, struct st_quicly_ha QUICLY_PROBE(TRANSPORT_CLOSE_RECEIVE, conn, conn->stash.now, frame.error_code, frame.frame_type, QUICLY_PROBE_ESCAPE_UNSAFE_STRING(frame.reason_phrase.base, frame.reason_phrase.len)); QUICLY_LOG_CONN(transport_close_receive, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(error_code, frame.error_code); - PTLSLOG_ELEMENT_UNSIGNED(frame_type, frame.frame_type); - PTLSLOG_ELEMENT_UNSAFESTR(reason_phrase, (const char *)frame.reason_phrase.base, frame.reason_phrase.len); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(error_code, frame.error_code); + PTLS_LOG_ELEMENT_UNSIGNED(frame_type, frame.frame_type); + PTLS_LOG_ELEMENT_UNSAFESTR(reason_phrase, (const char *)frame.reason_phrase.base, frame.reason_phrase.len); }); return handle_close(conn, QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(frame.error_code), frame.frame_type, frame.reason_phrase); } @@ -5731,9 +5731,9 @@ static int handle_application_close_frame(quicly_conn_t *conn, struct st_quicly_ QUICLY_PROBE(APPLICATION_CLOSE_RECEIVE, conn, conn->stash.now, frame.error_code, QUICLY_PROBE_ESCAPE_UNSAFE_STRING(frame.reason_phrase.base, frame.reason_phrase.len)); QUICLY_LOG_CONN(application_close_receive, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(error_code, frame.error_code); - PTLSLOG_ELEMENT_UNSAFESTR(reason_phrase, (const char *)frame.reason_phrase.base, frame.reason_phrase.len); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(error_code, frame.error_code); + PTLS_LOG_ELEMENT_UNSAFESTR(reason_phrase, (const char *)frame.reason_phrase.base, frame.reason_phrase.len); }); return handle_close(conn, QUICLY_ERROR_FROM_APPLICATION_ERROR_CODE(frame.error_code), UINT64_MAX, frame.reason_phrase); } @@ -5746,7 +5746,7 @@ static int handle_padding_frame(quicly_conn_t *conn, struct st_quicly_handle_pay static int handle_ping_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) { QUICLY_PROBE(PING_RECEIVE, conn, conn->stash.now); - QUICLY_LOG_CONN(ping_receive, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(ping_receive, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); return 0; } @@ -5765,11 +5765,11 @@ static int handle_new_connection_id_frame(quicly_conn_t *conn, struct st_quicly_ QUICLY_PROBE_HEXDUMP(frame.cid.base, frame.cid.len), QUICLY_PROBE_HEXDUMP(frame.stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN)); QUICLY_LOG_CONN(new_connection_id_receive, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(sequence, frame.sequence); - PTLSLOG_ELEMENT_UNSIGNED(retire_prior_to, frame.retire_prior_to); - PTLSLOG_ELEMENT_HEXDUMP(cid, frame.cid.base, frame.cid.len); - PTLSLOG_ELEMENT_HEXDUMP(stateless_reset_token, frame.stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(sequence, frame.sequence); + PTLS_LOG_ELEMENT_UNSIGNED(retire_prior_to, frame.retire_prior_to); + PTLS_LOG_ELEMENT_HEXDUMP(cid, frame.cid.base, frame.cid.len); + PTLS_LOG_ELEMENT_HEXDUMP(stateless_reset_token, frame.stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN); }); if (frame.sequence < conn->super.remote.largest_retire_prior_to) { @@ -5809,8 +5809,8 @@ static int handle_retire_connection_id_frame(quicly_conn_t *conn, struct st_quic QUICLY_PROBE(RETIRE_CONNECTION_ID_RECEIVE, conn, conn->stash.now, frame.sequence); QUICLY_LOG_CONN(retire_connection_id_receive, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(sequence, frame.sequence); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(sequence, frame.sequence); }); if (frame.sequence >= conn->super.local.cid_set.plaintext.path_id) { @@ -5832,7 +5832,7 @@ static int handle_handshake_done_frame(quicly_conn_t *conn, struct st_quicly_han int ret; QUICLY_PROBE(HANDSHAKE_DONE_RECEIVE, conn, conn->stash.now); - QUICLY_LOG_CONN(handshake_done_receive, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(handshake_done_receive, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); if (!quicly_is_client(conn)) return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; @@ -5862,8 +5862,8 @@ static int handle_datagram_frame(quicly_conn_t *conn, struct st_quicly_handle_pa return ret; QUICLY_PROBE(DATAGRAM_RECEIVE, conn, conn->stash.now, frame.payload.base, frame.payload.len); QUICLY_LOG_CONN(datagram_receive, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(payload_len, frame.payload.len); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(payload_len, frame.payload.len); }); /* handle the frame. Applications might call quicly_close or other functions that modify the connection state. */ @@ -5887,12 +5887,12 @@ static int handle_ack_frequency_frame(quicly_conn_t *conn, struct st_quicly_hand QUICLY_PROBE(ACK_FREQUENCY_RECEIVE, conn, conn->stash.now, frame.sequence, frame.packet_tolerance, frame.max_ack_delay, (int)frame.ignore_order, (int)frame.ignore_ce); QUICLY_LOG_CONN(ack_frequency_receive, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(sequence, frame.sequence); - PTLSLOG_ELEMENT_UNSIGNED(packet_tolerance, frame.packet_tolerance); - PTLSLOG_ELEMENT_UNSIGNED(max_ack_delay, frame.max_ack_delay); - PTLSLOG_ELEMENT_SIGNED(ignore_order, (int)frame.ignore_order); - PTLSLOG_ELEMENT_SIGNED(ignore_ce, (int)frame.ignore_ce); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(sequence, frame.sequence); + PTLS_LOG_ELEMENT_UNSIGNED(packet_tolerance, frame.packet_tolerance); + PTLS_LOG_ELEMENT_UNSIGNED(max_ack_delay, frame.max_ack_delay); + PTLS_LOG_ELEMENT_SIGNED(ignore_order, (int)frame.ignore_order); + PTLS_LOG_ELEMENT_SIGNED(ignore_ce, (int)frame.ignore_ce); }); /* Reject Request Max Ack Delay below our TP.min_ack_delay (which is at the moment equal to LOCAL_MAX_ACK_DELAY). */ @@ -6043,7 +6043,7 @@ static int handle_payload(quicly_conn_t *conn, size_t epoch, const uint8_t *_src static int handle_stateless_reset(quicly_conn_t *conn) { QUICLY_PROBE(STATELESS_RESET_RECEIVE, conn, conn->stash.now); - QUICLY_LOG_CONN(stateless_reset_receive, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(stateless_reset_receive, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); return handle_close(conn, QUICLY_ERROR_RECEIVED_STATELESS_RESET, UINT64_MAX, ptls_iovec_init("", 0)); } @@ -6129,16 +6129,16 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * QUICLY_PROBE(ACCEPT, *conn, (*conn)->stash.now, QUICLY_PROBE_HEXDUMP(packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len), address_token); QUICLY_LOG_CONN(accept, *conn, { - PTLSLOG_ELEMENT_SIGNED(time, (*conn)->stash.now); - PTLSLOG_ELEMENT_HEXDUMP(dcid, packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len); - PTLSLOG_ELEMENT_PTR(address_token, address_token); + PTLS_LOG_ELEMENT_SIGNED(time, (*conn)->stash.now); + PTLS_LOG_ELEMENT_HEXDUMP(dcid, packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len); + PTLS_LOG_ELEMENT_PTR(address_token, address_token); }); QUICLY_PROBE(PACKET_RECEIVED, *conn, (*conn)->stash.now, pn, payload.base, payload.len, get_epoch(packet->octets.base[0])); QUICLY_LOG_CONN(packet_received, *conn, { - PTLSLOG_ELEMENT_SIGNED(time, (*conn)->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(pn, pn); - PTLSLOG_ELEMENT_UNSIGNED(decrypted_len, payload.len); - PTLSLOG_ELEMENT_UNSIGNED(packet_type, get_epoch(packet->octets.base[0])); + PTLS_LOG_ELEMENT_SIGNED(time, (*conn)->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(pn, pn); + PTLS_LOG_ELEMENT_UNSIGNED(decrypted_len, payload.len); + PTLS_LOG_ELEMENT_UNSIGNED(packet_type, get_epoch(packet->octets.base[0])); }); /* handle the input; we ignore is_ack_only, we consult if there's any output from TLS in response to CH anyways */ @@ -6187,9 +6187,9 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka QUICLY_PROBE_HEXDUMP(packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len), packet->octets.base, packet->octets.len); QUICLY_LOG_CONN(receive, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_HEXDUMP(dcid, packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len); - PTLSLOG_ELEMENT_HEXDUMP(bytes, packet->octets.base, packet->octets.len); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_HEXDUMP(dcid, packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len); + PTLS_LOG_ELEMENT_HEXDUMP(bytes, packet->octets.base, packet->octets.len); }); if (is_stateless_reset(conn, packet)) { @@ -6349,10 +6349,10 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka QUICLY_PROBE(PACKET_RECEIVED, conn, conn->stash.now, pn, payload.base, payload.len, get_epoch(packet->octets.base[0])); QUICLY_LOG_CONN(packet_received, conn, { - PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(pn, pn); - PTLSLOG_ELEMENT_UNSIGNED(decrypted_len, payload.len); - PTLSLOG_ELEMENT_UNSIGNED(packet_type, get_epoch(packet->octets.base[0])); + PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); + PTLS_LOG_ELEMENT_UNSIGNED(pn, pn); + PTLS_LOG_ELEMENT_UNSIGNED(decrypted_len, payload.len); + PTLS_LOG_ELEMENT_UNSIGNED(packet_type, get_epoch(packet->octets.base[0])); }); /* update states */ @@ -6489,7 +6489,7 @@ int quicly_open_stream(quicly_conn_t *conn, quicly_stream_t **_stream, int uni) /* application-layer initialization */ QUICLY_PROBE(STREAM_ON_OPEN, conn, conn->stash.now, stream); - QUICLY_LOG_CONN(stream_on_open, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(stream_on_open, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); if ((ret = conn->super.ctx->stream_open->cb(conn->super.ctx->stream_open, stream)) != 0) return ret; diff --git a/src/cli.c b/src/cli.c index e69be008d..e57c6356b 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1075,7 +1075,7 @@ static void setup_ptlslog(const char *fn) fprintf(stderr, "failed to open file:%s:%s\n", fn, strerror(errno)); exit(1); } - ptlslog_add_fd(fd); + ptls_log_add_fd(fd); } int main(int argc, char **argv) From eb5d187a31f22ef935a456e87395d5cc2291274e Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 7 Oct 2022 12:44:15 +0900 Subject: [PATCH 271/361] leading double underscore is reserved --- include/quicly.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index d188a1f77..c95f9c9e5 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -1248,10 +1248,10 @@ extern const quicly_stream_callbacks_t quicly_stream_noop_callbacks; #define QUICLY_LOG_CONN(_type, _conn, _block) \ do { \ - quicly_conn_t *__conn = (_conn); \ - if (!ptls_skip_tracing(__conn->crypto.tls)) \ + quicly_conn_t *_c = (_conn); \ + if (!ptls_skip_tracing(_c->crypto.tls)) \ QUICLY_LOG(_type, { \ - PTLS_LOG_ELEMENT_PTR(conn, __conn); \ + PTLS_LOG_ELEMENT_PTR(conn, _c); \ do { \ _block \ } while (0); \ From e097737fa750ca85433d1f5e5579617a527b34c4 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 7 Oct 2022 12:52:00 +0900 Subject: [PATCH 272/361] [xcode] update project following picotls use of vaes --- quicly.xcodeproj/project.pbxproj | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/quicly.xcodeproj/project.pbxproj b/quicly.xcodeproj/project.pbxproj index 32706da63..03b64b8aa 100644 --- a/quicly.xcodeproj/project.pbxproj +++ b/quicly.xcodeproj/project.pbxproj @@ -925,7 +925,7 @@ "QUICLY_USE_EMBEDDED_PROBES=1", "QUICLY_HAVE_FUSION=1", ); - OTHER_CFLAGS = "-march=native"; + OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( "-L/usr/local/opt/openssl@1.1/lib", "-lcrypto", @@ -942,7 +942,7 @@ "QUICLY_USE_EMBEDDED_PROBES=1", "QUICLY_HAVE_FUSION=1", ); - OTHER_CFLAGS = "-march=native"; + OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( "-L/usr/local/opt/openssl@1.1/lib", "-lcrypto", @@ -1026,6 +1026,13 @@ MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; + OTHER_CFLAGS = ( + "-march=native", + "-maes", + "-mpclmul", + "-mvaes", + "-mvpclmulqdq", + ); SDKROOT = macosx; }; name = Debug; @@ -1078,6 +1085,13 @@ ); MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = NO; + OTHER_CFLAGS = ( + "-march=native", + "-maes", + "-mpclmul", + "-mvaes", + "-mvpclmulqdq", + ); SDKROOT = macosx; }; name = Release; @@ -1114,7 +1128,7 @@ "QUICLY_USE_EMBEDDED_PROBES=1", "QUICLY_HAVE_FUSION=1", ); - OTHER_CFLAGS = "-march=native"; + OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( "-L/usr/local/opt/openssl@1.1/lib", "-lcrypto", @@ -1131,7 +1145,7 @@ "QUICLY_USE_EMBEDDED_PROBES=1", "QUICLY_HAVE_FUSION=1", ); - OTHER_CFLAGS = "-march=native"; + OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( "-L/usr/local/opt/openssl@1.1/lib", "-lcrypto", From 38c020c2ac4bd597d3b811f367e8bb436ed8c9cf Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 7 Oct 2022 15:06:56 +0900 Subject: [PATCH 273/361] emit time automatically --- include/quicly.h | 5 +- lib/quicly.c | 170 ++++++++++------------------------------------- 2 files changed, 36 insertions(+), 139 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index c95f9c9e5..cd77a0a71 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -1244,14 +1244,13 @@ void quicly_stream_noop_on_receive_reset(quicly_stream_t *stream, int err); extern const quicly_stream_callbacks_t quicly_stream_noop_callbacks; -#define QUICLY_LOG(type, block) PTLS_LOG(quicly, type, block) - #define QUICLY_LOG_CONN(_type, _conn, _block) \ do { \ quicly_conn_t *_c = (_conn); \ if (!ptls_skip_tracing(_c->crypto.tls)) \ - QUICLY_LOG(_type, { \ + PTLS_LOG(quicly, _type, { \ PTLS_LOG_ELEMENT_PTR(conn, _c); \ + PTLS_LOG_ELEMENT_SIGNED(time, _c->stash.now); \ do { \ _block \ } while (0); \ diff --git a/lib/quicly.c b/lib/quicly.c index f95cca13a..c4b673198 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -981,10 +981,7 @@ void crypto_stream_receive(quicly_stream_t *stream, size_t off, const void *src, &conn->crypto.handshake_properties); quicly_streambuf_ingress_shift(stream, input.len); QUICLY_PROBE(CRYPTO_HANDSHAKE, conn, conn->stash.now, handshake_result); - QUICLY_LOG_CONN(crypto_handshake, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_SIGNED(ret, handshake_result); - }); + QUICLY_LOG_CONN(crypto_handshake, conn, { PTLS_LOG_ELEMENT_SIGNED(ret, handshake_result); }); switch (handshake_result) { case 0: case PTLS_ERROR_IN_PROGRESS: @@ -1135,7 +1132,6 @@ static void destroy_stream(quicly_stream_t *stream, int err) QUICLY_PROBE(STREAM_ON_DESTROY, conn, conn->stash.now, stream, err); QUICLY_LOG_CONN(stream_on_destroy, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLS_LOG_ELEMENT_SIGNED(err, err); }); @@ -1558,10 +1554,7 @@ static int update_1rtt_egress_key(quicly_conn_t *conn) QUICLY_PROBE(CRYPTO_SEND_KEY_UPDATE, conn, conn->stash.now, space->cipher.egress.key_phase, QUICLY_PROBE_HEXDUMP(space->cipher.egress.secret, cipher->hash->digest_size)); - QUICLY_LOG_CONN(crypto_send_key_update, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_UNSIGNED(phase, space->cipher.egress.key_phase); - }); + QUICLY_LOG_CONN(crypto_send_key_update, conn, { PTLS_LOG_ELEMENT_UNSIGNED(phase, space->cipher.egress.key_phase); }); return 0; } @@ -1577,10 +1570,8 @@ static int received_key_update(quicly_conn_t *conn, uint64_t newly_decrypted_key QUICLY_PROBE(CRYPTO_RECEIVE_KEY_UPDATE, conn, conn->stash.now, space->cipher.ingress.key_phase.decrypted, QUICLY_PROBE_HEXDUMP(space->cipher.ingress.secret, ptls_get_cipher(conn->crypto.tls)->hash->digest_size)); - QUICLY_LOG_CONN(crypto_receive_key_update, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_UNSIGNED(phase, space->cipher.ingress.key_phase.decrypted); - }); + QUICLY_LOG_CONN(crypto_receive_key_update, conn, + { PTLS_LOG_ELEMENT_UNSIGNED(phase, space->cipher.ingress.key_phase.decrypted); }); if (space->cipher.egress.key_phase < space->cipher.ingress.key_phase.decrypted) { return update_1rtt_egress_key(conn); @@ -1600,7 +1591,7 @@ void quicly_free(quicly_conn_t *conn) lock_now(conn, 0); QUICLY_PROBE(FREE, conn, conn->stash.now); - QUICLY_LOG_CONN(free, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(free, conn, {}); #if QUICLY_USE_EMBEDDED_PROBES || QUICLY_USE_DTRACE if (QUICLY_CONN_STATS_ENABLED()) { @@ -1718,7 +1709,6 @@ static int apply_stream_frame(quicly_stream_t *stream, quicly_stream_frame_t *fr QUICLY_PROBE(STREAM_RECEIVE, stream->conn, stream->conn->stash.now, stream, frame->offset, frame->data.len); QUICLY_LOG_CONN(stream_receive, stream->conn, { - PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLS_LOG_ELEMENT_UNSIGNED(off, frame->offset); PTLS_LOG_ELEMENT_UNSIGNED(len, frame->data.len); @@ -1759,7 +1749,6 @@ static int apply_stream_frame(quicly_stream_t *stream, quicly_stream_frame_t *fr const void *apply_src = frame->data.base + frame->data.len - apply_len; QUICLY_PROBE(STREAM_ON_RECEIVE, stream->conn, stream->conn->stash.now, stream, (size_t)buf_offset, apply_src, apply_len); QUICLY_LOG_CONN(stream_on_receive, stream->conn, { - PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLS_LOG_ELEMENT_UNSIGNED(off, buf_offset); PTLS_LOG_ELEMENT_UNSIGNED(src_len, apply_len); @@ -2311,10 +2300,7 @@ int quicly_connect(quicly_conn_t **_conn, quicly_context_t *ctx, const char *ser conn->super.original_dcid = *server_cid; QUICLY_PROBE(CONNECT, conn, conn->stash.now, conn->super.version); - QUICLY_LOG_CONN(connect, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_UNSIGNED(version, conn->super.version); - }); + QUICLY_LOG_CONN(connect, conn, { PTLS_LOG_ELEMENT_UNSIGNED(version, conn->super.version); }); if ((ret = setup_handshake_space_and_flow(conn, QUICLY_EPOCH_INITIAL)) != 0) goto Exit; @@ -2482,10 +2468,8 @@ static int aead_decrypt_1rtt(void *ctx, uint64_t pn, quicly_decoded_packet_t *pa ++space->cipher.ingress.key_phase.prepared; QUICLY_PROBE(CRYPTO_RECEIVE_KEY_UPDATE_PREPARE, conn, conn->stash.now, space->cipher.ingress.key_phase.prepared, QUICLY_PROBE_HEXDUMP(space->cipher.ingress.secret, cipher->hash->digest_size)); - QUICLY_LOG_CONN(crypto_receive_key_update_prepare, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_UNSIGNED(phase, space->cipher.ingress.key_phase.prepared); - }); + QUICLY_LOG_CONN(crypto_receive_key_update_prepare, conn, + { PTLS_LOG_ELEMENT_UNSIGNED(phase, space->cipher.ingress.key_phase.prepared); }); } } @@ -2669,7 +2653,6 @@ static int on_ack_stream_ack_one(quicly_conn_t *conn, quicly_stream_id_t stream_ QUICLY_PROBE(STREAM_ON_SEND_SHIFT, stream->conn, stream->conn->stash.now, stream, bytes_to_shift); stream->callbacks->on_send_shift(stream, bytes_to_shift); QUICLY_LOG_CONN(stream_on_send_shift, stream->conn, { - PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLS_LOG_ELEMENT_UNSIGNED(delta, bytes_to_shift); }); @@ -2705,7 +2688,6 @@ static int on_ack_stream(quicly_sentmap_t *map, const quicly_sent_packet_t *pack QUICLY_PROBE(STREAM_ACKED, conn, conn->stash.now, sent->data.stream.stream_id, sent->data.stream.args.start, sent->data.stream.args.end - sent->data.stream.args.start); QUICLY_LOG_CONN(stream_acked, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_SIGNED(stream_id, sent->data.stream.stream_id); PTLS_LOG_ELEMENT_UNSIGNED(off, sent->data.stream.args.start); PTLS_LOG_ELEMENT_UNSIGNED(len, sent->data.stream.args.end - sent->data.stream.args.start); @@ -2734,7 +2716,6 @@ static int on_ack_stream(quicly_sentmap_t *map, const quicly_sent_packet_t *pack QUICLY_PROBE(STREAM_LOST, conn, conn->stash.now, sent->data.stream.stream_id, sent->data.stream.args.start, sent->data.stream.args.end - sent->data.stream.args.start); QUICLY_LOG_CONN(stream_lost, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_SIGNED(stream_id, sent->data.stream.stream_id); PTLS_LOG_ELEMENT_UNSIGNED(off, sent->data.stream.args.start); PTLS_LOG_ELEMENT_UNSIGNED(len, sent->data.stream.args.end - sent->data.stream.args.start); @@ -2906,10 +2887,7 @@ static int on_ack_new_token(quicly_sentmap_t *map, const quicly_sent_packet_t *p } if (acked) { QUICLY_PROBE(NEW_TOKEN_ACKED, conn, conn->stash.now, sent->data.new_token.generation); - QUICLY_LOG_CONN(new_token_acked, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_UNSIGNED(generation, sent->data.new_token.generation); - }); + QUICLY_LOG_CONN(new_token_acked, conn, { PTLS_LOG_ELEMENT_UNSIGNED(generation, sent->data.new_token.generation); }); if (conn->egress.new_token.max_acked < sent->data.new_token.generation) conn->egress.new_token.max_acked = sent->data.new_token.generation; } @@ -3191,7 +3169,6 @@ static int commit_send_packet(quicly_conn_t *conn, quicly_send_context_t *s, int QUICLY_PROBE(PACKET_SENT, conn, conn->stash.now, conn->egress.packet_number, s->dst - s->target.first_byte_at, get_epoch(*s->target.first_byte_at), !s->target.ack_eliciting); QUICLY_LOG_CONN(packet_sent, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(pn, conn->egress.packet_number); PTLS_LOG_ELEMENT_UNSIGNED(len, s->dst - s->target.first_byte_at); PTLS_LOG_ELEMENT_UNSIGNED(packet_type, get_epoch(*s->target.first_byte_at)); @@ -3308,7 +3285,6 @@ static int do_allocate_frame(quicly_conn_t *conn, quicly_send_context_t *s, size QUICLY_PROBE(PACKET_PREPARE, conn, conn->stash.now, s->current.first_byte, QUICLY_PROBE_HEXDUMP(conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len)); QUICLY_LOG_CONN(packet_prepare, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(first_octet, s->current.first_byte); PTLS_LOG_ELEMENT_HEXDUMP(dcid, conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len); }); @@ -3430,7 +3406,6 @@ static int send_ack(quicly_conn_t *conn, struct st_quicly_pn_space_t *space, qui ++conn->super.stats.num_frames_sent.ack; QUICLY_PROBE(ACK_SEND, conn, conn->stash.now, space->ack_queue.ranges[space->ack_queue.num_ranges - 1].end - 1, ack_delay); QUICLY_LOG_CONN(ack_send, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(largest_acked, space->ack_queue.ranges[space->ack_queue.num_ranges - 1].end - 1); PTLS_LOG_ELEMENT_UNSIGNED(ack_delay, ack_delay); }); @@ -3441,7 +3416,7 @@ static int send_ack(quicly_conn_t *conn, struct st_quicly_pn_space_t *space, qui *dst++ = QUICLY_FRAME_TYPE_PING; ++conn->super.stats.num_frames_sent.ping; QUICLY_PROBE(PING_SEND, conn, conn->stash.now); - QUICLY_LOG_CONN(ping_send, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(ping_send, conn, {}); } s->dst = dst; @@ -3517,7 +3492,6 @@ static int send_control_frames_of_stream(quicly_stream_t *stream, quicly_send_co QUICLY_PROBE(STOP_SENDING_SEND, stream->conn, stream->conn->stash.now, stream->stream_id, stream->_send_aux.stop_sending.error_code); QUICLY_LOG_CONN(stop_sending_send, stream->conn, { - PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLS_LOG_ELEMENT_UNSIGNED(error_code, stream->_send_aux.stop_sending.error_code); }); @@ -3540,7 +3514,6 @@ static int send_control_frames_of_stream(quicly_stream_t *stream, quicly_send_co ++stream->conn->super.stats.num_frames_sent.max_stream_data; QUICLY_PROBE(MAX_STREAM_DATA_SEND, stream->conn, stream->conn->stash.now, stream, new_value); QUICLY_LOG_CONN(max_stream_data_send, stream->conn, { - PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLS_LOG_ELEMENT_UNSIGNED(maximum, new_value); }); @@ -3557,7 +3530,6 @@ static int send_control_frames_of_stream(quicly_stream_t *stream, quicly_send_co QUICLY_PROBE(RESET_STREAM_SEND, stream->conn, stream->conn->stash.now, stream->stream_id, stream->_send_aux.reset_stream.error_code, stream->sendstate.size_inflight); QUICLY_LOG_CONN(reset_stream_send, stream->conn, { - PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLS_LOG_ELEMENT_UNSIGNED(error_code, stream->_send_aux.reset_stream.error_code); PTLS_LOG_ELEMENT_UNSIGNED(final_size, stream->sendstate.size_inflight); @@ -3578,7 +3550,6 @@ static int send_control_frames_of_stream(quicly_stream_t *stream, quicly_send_co ++stream->conn->super.stats.num_frames_sent.stream_data_blocked; QUICLY_PROBE(STREAM_DATA_BLOCKED_SEND, stream->conn, stream->conn->stash.now, stream->stream_id, offset); QUICLY_LOG_CONN(stream_data_blocked_send, stream->conn, { - PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLS_LOG_ELEMENT_UNSIGNED(maximum, offset); }); @@ -3766,7 +3737,6 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) size_t emit_off = (size_t)(off - stream->sendstate.acked.ranges[0].end); QUICLY_PROBE(STREAM_ON_SEND_EMIT, stream->conn, stream->conn->stash.now, stream, emit_off, len); QUICLY_LOG_CONN(stream_on_send_emit, stream->conn, { - PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLS_LOG_ELEMENT_UNSIGNED(off, off); PTLS_LOG_ELEMENT_UNSIGNED(capacity, len); @@ -3806,7 +3776,6 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) (stream->sendstate.size_inflight < off + len ? stream->sendstate.size_inflight : off + len) - off; QUICLY_PROBE(STREAM_SEND, stream->conn, stream->conn->stash.now, stream, off, len, is_fin); QUICLY_LOG_CONN(stream_send, stream->conn, { - PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLS_LOG_ELEMENT_UNSIGNED(off, off); PTLS_LOG_ELEMENT_UNSIGNED(len, len); @@ -3904,14 +3873,12 @@ static void on_loss_detected(quicly_loss_t *loss, const quicly_sent_packet_t *lo conn->egress.max_udp_payload_size); QUICLY_PROBE(PACKET_LOST, conn, conn->stash.now, lost_packet->packet_number, lost_packet->ack_epoch); QUICLY_LOG_CONN(packet_lost, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(pn, lost_packet->packet_number); PTLS_LOG_ELEMENT_UNSIGNED(packet_type, lost_packet->ack_epoch); }); QUICLY_PROBE(CC_CONGESTION, conn, conn->stash.now, lost_packet->packet_number + 1, conn->egress.loss.sentmap.bytes_in_flight, conn->egress.cc.cwnd); QUICLY_LOG_CONN(cc_congestion, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(max_lost_pn, lost_packet->packet_number + 1); PTLS_LOG_ELEMENT_UNSIGNED(flight, conn->egress.loss.sentmap.bytes_in_flight); PTLS_LOG_ELEMENT_UNSIGNED(cwnd, conn->egress.cc.cwnd); @@ -3948,7 +3915,6 @@ static int send_max_streams(quicly_conn_t *conn, int uni, quicly_send_context_t } QUICLY_PROBE(MAX_STREAMS_SEND, conn, conn->stash.now, new_count, uni); QUICLY_LOG_CONN(max_streams_send, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(maximum, new_count); PTLS_LOG_ELEMENT_BOOL(is_unidirectional, uni); }); @@ -3982,7 +3948,6 @@ static int send_streams_blocked(quicly_conn_t *conn, int uni, quicly_send_contex ++conn->super.stats.num_frames_sent.streams_blocked; QUICLY_PROBE(STREAMS_BLOCKED_SEND, conn, conn->stash.now, max_streams->count, uni); QUICLY_LOG_CONN(streams_blocked_send, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(maximum, max_streams->count); PTLS_LOG_ELEMENT_BOOL(is_unidirectional, uni); }); @@ -4030,7 +3995,7 @@ static int send_handshake_done(quicly_conn_t *conn, quicly_send_context_t *s) conn->egress.pending_flows &= ~QUICLY_PENDING_FLOW_HANDSHAKE_DONE_BIT; ++conn->super.stats.num_frames_sent.handshake_done; QUICLY_PROBE(HANDSHAKE_DONE_SEND, conn, conn->stash.now); - QUICLY_LOG_CONN(handshake_done_send, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(handshake_done_send, conn, {}); ret = 0; Exit: @@ -4051,10 +4016,7 @@ static int send_data_blocked(quicly_conn_t *conn, quicly_send_context_t *s) ++conn->super.stats.num_frames_sent.data_blocked; QUICLY_PROBE(DATA_BLOCKED_SEND, conn, conn->stash.now, offset); - QUICLY_LOG_CONN(data_blocked_send, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_UNSIGNED(off, offset); - }); + QUICLY_LOG_CONN(data_blocked_send, conn, { PTLS_LOG_ELEMENT_UNSIGNED(off, offset); }); ret = 0; Exit: @@ -4096,7 +4058,6 @@ static int send_resumption_token(quicly_conn_t *conn, quicly_send_context_t *s) ++conn->super.stats.num_frames_sent.new_token; QUICLY_PROBE(NEW_TOKEN_SEND, conn, conn->stash.now, tokenbuf.base, tokenbuf.off, sent->data.new_token.generation); QUICLY_LOG_CONN(new_token_send, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_HEXDUMP(token, tokenbuf.base, tokenbuf.off); PTLS_LOG_ELEMENT_UNSIGNED(generation, sent->data.new_token.generation); }); @@ -4300,7 +4261,7 @@ static int send_handshake_flow(quicly_conn_t *conn, size_t epoch, quicly_send_co conn->egress.last_retransmittable_sent_at = conn->stash.now; ++conn->super.stats.num_frames_sent.ping; QUICLY_PROBE(PING_SEND, conn, conn->stash.now); - QUICLY_LOG_CONN(ping_send, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(ping_send, conn, {}); } } @@ -4344,7 +4305,6 @@ static int send_connection_close(quicly_conn_t *conn, size_t epoch, quicly_send_ ++conn->super.stats.num_frames_sent.transport_close; QUICLY_PROBE(TRANSPORT_CLOSE_SEND, conn, conn->stash.now, error_code, offending_frame_type, reason_phrase); QUICLY_LOG_CONN(transport_close_send, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(error_code, error_code); PTLS_LOG_ELEMENT_UNSIGNED(frame_type, offending_frame_type); PTLS_LOG_ELEMENT_UNSAFESTR(reason_phrase, reason_phrase, strlen(reason_phrase)); @@ -4353,7 +4313,6 @@ static int send_connection_close(quicly_conn_t *conn, size_t epoch, quicly_send_ ++conn->super.stats.num_frames_sent.application_close; QUICLY_PROBE(APPLICATION_CLOSE_SEND, conn, conn->stash.now, error_code, reason_phrase); QUICLY_LOG_CONN(application_close_send, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(error_code, error_code); PTLS_LOG_ELEMENT_UNSAFESTR(reason_phrase, reason_phrase, strlen(reason_phrase)); }); @@ -4383,7 +4342,6 @@ static int send_new_connection_id(quicly_conn_t *conn, quicly_send_context_t *s, QUICLY_PROBE_HEXDUMP(new_cid->cid.cid, new_cid->cid.len), QUICLY_PROBE_HEXDUMP(new_cid->stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN)); QUICLY_LOG_CONN(new_connection_id_send, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(sequence, new_cid->sequence); PTLS_LOG_ELEMENT_UNSIGNED(retire_prior_to, retire_prior_to); PTLS_LOG_ELEMENT_HEXDUMP(cid, new_cid->cid.cid, new_cid->cid.len); @@ -4408,10 +4366,7 @@ static int send_retire_connection_id(quicly_conn_t *conn, quicly_send_context_t ++conn->super.stats.num_frames_sent.retire_connection_id; QUICLY_PROBE(RETIRE_CONNECTION_ID_SEND, conn, conn->stash.now, sequence); - QUICLY_LOG_CONN(retire_connection_id_send, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_UNSIGNED(sequence, sequence); - }); + QUICLY_LOG_CONN(retire_connection_id_send, conn, { PTLS_LOG_ELEMENT_UNSIGNED(sequence, sequence); }); return 0; } @@ -4432,7 +4387,6 @@ static int update_traffic_key_cb(ptls_update_traffic_key_t *self, ptls_t *tls, i QUICLY_PROBE(CRYPTO_UPDATE_SECRET, conn, conn->stash.now, is_enc, epoch, log_label, QUICLY_PROBE_HEXDUMP(secret, cipher->hash->digest_size)); QUICLY_LOG_CONN(crypto_update_secret, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_BOOL(is_enc, is_enc); PTLS_LOG_ELEMENT_UNSIGNED(epoch, epoch); PTLS_LOG_ELEMENT_SAFESTR(label, log_label); @@ -4524,7 +4478,7 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) /* handle timeouts */ if (conn->idle_timeout.at <= conn->stash.now) { QUICLY_PROBE(IDLE_TIMEOUT, conn, conn->stash.now); - QUICLY_LOG_CONN(idle_timeout, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(idle_timeout, conn, {}); goto CloseNow; } /* handle handshake timeouts */ @@ -4533,7 +4487,6 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) conn->stash.now) { QUICLY_PROBE(HANDSHAKE_TIMEOUT, conn, conn->stash.now, conn->stash.now - conn->created_at, conn->egress.loss.rtt.smoothed); QUICLY_LOG_CONN(handshake_timeout, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_SIGNED(elapsed, conn->stash.now - conn->created_at); PTLS_LOG_ELEMENT_UNSIGNED(rtt_smoothed, conn->egress.loss.rtt.smoothed); }); @@ -4542,10 +4495,8 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) } if (conn->super.stats.num_packets.initial_handshake_sent > conn->super.ctx->max_initial_handshake_packets) { QUICLY_PROBE(INITIAL_HANDSHAKE_PACKET_EXCEED, conn, conn->stash.now, conn->super.stats.num_packets.initial_handshake_sent); - QUICLY_LOG_CONN(initial_handshake_packet_exceed, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_UNSIGNED(num_packets, conn->super.stats.num_packets.initial_handshake_sent); - }); + QUICLY_LOG_CONN(initial_handshake_packet_exceed, conn, + { PTLS_LOG_ELEMENT_UNSIGNED(num_packets, conn->super.stats.num_packets.initial_handshake_sent); }); conn->super.stats.num_initial_handshake_exceeded++; goto CloseNow; } @@ -4564,7 +4515,6 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) QUICLY_PROBE(PTO, conn, conn->stash.now, conn->egress.loss.sentmap.bytes_in_flight, conn->egress.cc.cwnd, conn->egress.loss.pto_count); QUICLY_LOG_CONN(pto, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_SIGNED(inflight, conn->egress.loss.sentmap.bytes_in_flight); PTLS_LOG_ELEMENT_UNSIGNED(cwnd, conn->egress.cc.cwnd); PTLS_LOG_ELEMENT_SIGNED(pto_count, conn->egress.loss.pto_count); @@ -4621,10 +4571,7 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) if (s->dst_end - s->dst >= required_space) { s->dst = quicly_encode_datagram_frame(s->dst, *payload); QUICLY_PROBE(DATAGRAM_SEND, conn, conn->stash.now, payload->base, payload->len); - QUICLY_LOG_CONN(datagram_send, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_UNSIGNED(payload_len, payload->len); - }); + QUICLY_LOG_CONN(datagram_send, conn, { PTLS_LOG_ELEMENT_UNSIGNED(payload_len, payload->len); }); } else { /* FIXME: At the moment, we add a padding because we do not have a way to reclaim allocated space, and because * it is forbidden to send an empty QUIC packet. */ @@ -4640,7 +4587,7 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) *s->dst++ = QUICLY_FRAME_TYPE_PING; ++conn->super.stats.num_frames_sent.ping; QUICLY_PROBE(PING_SEND, conn, conn->stash.now); - QUICLY_LOG_CONN(ping_send, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(ping_send, conn, {}); } /* take actions only permitted for short header packets */ if (conn->application->one_rtt_writable) { @@ -4690,10 +4637,7 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) quicly_maxsender_record(&conn->ingress.max_data.sender, new_value, &sent->data.max_data.args); ++conn->super.stats.num_frames_sent.max_data; QUICLY_PROBE(MAX_DATA_SEND, conn, conn->stash.now, new_value); - QUICLY_LOG_CONN(max_data_send, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_UNSIGNED(maximum, new_value); - }); + QUICLY_LOG_CONN(max_data_send, conn, { PTLS_LOG_ELEMENT_UNSIGNED(maximum, new_value); }); } if (conn->egress.data_blocked == QUICLY_SENDER_STATE_SEND && (ret = send_data_blocked(conn, s)) != 0) goto Exit; @@ -4820,7 +4764,6 @@ int quicly_send(quicly_conn_t *conn, quicly_address_t *dest, quicly_address_t *s QUICLY_PROBE(SEND, conn, conn->stash.now, conn->super.state, QUICLY_PROBE_HEXDUMP(conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len)); QUICLY_LOG_CONN(send, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_SIGNED(state, conn->super.state); PTLS_LOG_ELEMENT_HEXDUMP(dcid, conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len); }); @@ -5058,10 +5001,7 @@ int quicly_get_or_open_stream(quicly_conn_t *conn, uint64_t stream_id, quicly_st goto Exit; } QUICLY_PROBE(STREAM_ON_OPEN, conn, conn->stash.now, *stream); - QUICLY_LOG_CONN(stream_on_open, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_SIGNED(stream_id, (*stream)->stream_id); - }); + QUICLY_LOG_CONN(stream_on_open, conn, { PTLS_LOG_ELEMENT_SIGNED(stream_id, (*stream)->stream_id); }); if ((ret = conn->super.ctx->stream_open->cb(conn->super.ctx->stream_open, *stream)) != 0) { *stream = NULL; goto Exit; @@ -5113,7 +5053,6 @@ static int handle_reset_stream_frame(quicly_conn_t *conn, struct st_quicly_handl return ret; QUICLY_PROBE(RESET_STREAM_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.app_error_code, frame.final_size); QUICLY_LOG_CONN(reset_stream_receive, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(stream_id, frame.stream_id); PTLS_LOG_ELEMENT_UNSIGNED(app_error_code, frame.app_error_code); PTLS_LOG_ELEMENT_UNSIGNED(final_size, frame.final_size); @@ -5130,7 +5069,6 @@ static int handle_reset_stream_frame(quicly_conn_t *conn, struct st_quicly_handl int err = QUICLY_ERROR_FROM_APPLICATION_ERROR_CODE(frame.app_error_code); QUICLY_PROBE(STREAM_ON_RECEIVE_RESET, stream->conn, stream->conn->stash.now, stream, err); QUICLY_LOG_CONN(stream_on_receive_reset, stream->conn, { - PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLS_LOG_ELEMENT_SIGNED(err, err); }); @@ -5183,7 +5121,6 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload uint64_t pn_block_max = pn_acked + frame.ack_block_lengths[gap_index] - 1; QUICLY_PROBE(ACK_BLOCK_RECEIVED, conn, conn->stash.now, pn_acked, pn_block_max); QUICLY_LOG_CONN(ack_block_received, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(ack_block_begin, pn_acked); PTLS_LOG_ELEMENT_UNSIGNED(ack_block_end, pn_block_max); }); @@ -5219,7 +5156,6 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload largest_newly_acked.sent_at = sent->sent_at; QUICLY_PROBE(PACKET_ACKED, conn, conn->stash.now, pn_acked, is_late_ack); QUICLY_LOG_CONN(packet_acked, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(pn, pn_acked); PTLS_LOG_ELEMENT_BOOL(is_late_ack, is_late_ack); }); @@ -5235,10 +5171,8 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload space->cipher.egress.key_update_pn.last = UINT64_MAX; space->cipher.egress.key_update_pn.next = conn->egress.packet_number + conn->super.ctx->max_packets_per_key; QUICLY_PROBE(CRYPTO_SEND_KEY_UPDATE_CONFIRMED, conn, conn->stash.now, space->cipher.egress.key_update_pn.next); - QUICLY_LOG_CONN(crypto_send_key_update_confirmed, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_UNSIGNED(next_pn, space->cipher.egress.key_update_pn.next); - }); + QUICLY_LOG_CONN(crypto_send_key_update_confirmed, conn, + { PTLS_LOG_ELEMENT_UNSIGNED(next_pn, space->cipher.egress.key_update_pn.next); }); } } ++pn_acked; @@ -5253,10 +5187,7 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload return ret; QUICLY_PROBE(ACK_DELAY_RECEIVED, conn, conn->stash.now, frame.ack_delay); - QUICLY_LOG_CONN(ack_delay_received, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_UNSIGNED(ack_delay, frame.ack_delay); - }); + QUICLY_LOG_CONN(ack_delay_received, conn, { PTLS_LOG_ELEMENT_UNSIGNED(ack_delay, frame.ack_delay); }); quicly_ratemeter_on_ack(&conn->egress.ratemeter, conn->stash.now, conn->super.stats.num_bytes.ack_received, largest_newly_acked.pn); @@ -5281,7 +5212,6 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload QUICLY_PROBE(CC_ACK_RECEIVED, conn, conn->stash.now, frame.largest_acknowledged, bytes_acked, conn->egress.cc.cwnd, conn->egress.loss.sentmap.bytes_in_flight); QUICLY_LOG_CONN(cc_ack_received, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(largest_acked, frame.largest_acknowledged); PTLS_LOG_ELEMENT_UNSIGNED(bytes_acked, bytes_acked); PTLS_LOG_ELEMENT_UNSIGNED(cwnd, conn->egress.cc.cwnd); @@ -5308,7 +5238,6 @@ static int handle_max_stream_data_frame(quicly_conn_t *conn, struct st_quicly_ha QUICLY_PROBE(MAX_STREAM_DATA_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.max_stream_data); QUICLY_LOG_CONN(max_stream_data_receive, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(stream_id, frame.stream_id); PTLS_LOG_ELEMENT_UNSIGNED(max_stream_data, frame.max_stream_data); }); @@ -5339,10 +5268,7 @@ static int handle_data_blocked_frame(quicly_conn_t *conn, struct st_quicly_handl return ret; QUICLY_PROBE(DATA_BLOCKED_RECEIVE, conn, conn->stash.now, frame.offset); - QUICLY_LOG_CONN(data_blocked_receive, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_UNSIGNED(off, frame.offset); - }); + QUICLY_LOG_CONN(data_blocked_receive, conn, { PTLS_LOG_ELEMENT_UNSIGNED(off, frame.offset); }); quicly_maxsender_request_transmit(&conn->ingress.max_data.sender); if (should_send_max_data(conn)) @@ -5362,7 +5288,6 @@ static int handle_stream_data_blocked_frame(quicly_conn_t *conn, struct st_quicl QUICLY_PROBE(STREAM_DATA_BLOCKED_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.offset); QUICLY_LOG_CONN(stream_data_blocked_receive, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_SIGNED(stream_id, frame.stream_id); PTLS_LOG_ELEMENT_UNSIGNED(maximum, frame.offset); }); @@ -5389,7 +5314,6 @@ static int handle_streams_blocked_frame(quicly_conn_t *conn, struct st_quicly_ha QUICLY_PROBE(STREAMS_BLOCKED_RECEIVE, conn, conn->stash.now, frame.count, uni); QUICLY_LOG_CONN(streams_blocked_receive, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(maximum, frame.count); PTLS_LOG_ELEMENT_BOOL(is_unidirectional, uni); }); @@ -5413,7 +5337,6 @@ static int handle_max_streams_frame(quicly_conn_t *conn, struct st_quicly_handle QUICLY_PROBE(MAX_STREAMS_RECEIVE, conn, conn->stash.now, frame.count, uni); QUICLY_LOG_CONN(max_streams_receive, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(maximum, frame.count); PTLS_LOG_ELEMENT_BOOL(is_unidirectional, uni); }); @@ -5459,10 +5382,7 @@ static int handle_new_token_frame(quicly_conn_t *conn, struct st_quicly_handle_p if ((ret = quicly_decode_new_token_frame(&state->src, state->end, &frame)) != 0) return ret; QUICLY_PROBE(NEW_TOKEN_RECEIVE, conn, conn->stash.now, frame.token.base, frame.token.len); - QUICLY_LOG_CONN(new_token_receive, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_HEXDUMP(token, frame.token.base, frame.token.len); - }); + QUICLY_LOG_CONN(new_token_receive, conn, { PTLS_LOG_ELEMENT_HEXDUMP(token, frame.token.base, frame.token.len); }); if (conn->super.ctx->save_resumption_token == NULL) return 0; return conn->super.ctx->save_resumption_token->cb(conn->super.ctx->save_resumption_token, conn, frame.token); @@ -5478,7 +5398,6 @@ static int handle_stop_sending_frame(quicly_conn_t *conn, struct st_quicly_handl return ret; QUICLY_PROBE(STOP_SENDING_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.app_error_code); QUICLY_LOG_CONN(stop_sending_receive, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(stream_id, frame.stream_id); PTLS_LOG_ELEMENT_UNSIGNED(error_code, frame.app_error_code); }); @@ -5492,7 +5411,6 @@ static int handle_stop_sending_frame(quicly_conn_t *conn, struct st_quicly_handl quicly_reset_stream(stream, err); QUICLY_PROBE(STREAM_ON_SEND_STOP, stream->conn, stream->conn->stash.now, stream, err); QUICLY_LOG_CONN(stream_on_send_stop, stream->conn, { - PTLS_LOG_ELEMENT_SIGNED(time, stream->conn->stash.now); PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLS_LOG_ELEMENT_SIGNED(err, err); }); @@ -5513,10 +5431,7 @@ static int handle_max_data_frame(quicly_conn_t *conn, struct st_quicly_handle_pa return ret; QUICLY_PROBE(MAX_DATA_RECEIVE, conn, conn->stash.now, frame.max_data); - QUICLY_LOG_CONN(max_data_receive, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_UNSIGNED(maximum, frame.max_data); - }); + QUICLY_LOG_CONN(max_data_receive, conn, { PTLS_LOG_ELEMENT_UNSIGNED(maximum, frame.max_data); }); if (frame.max_data <= conn->egress.max_data.permitted) return 0; @@ -5533,10 +5448,7 @@ static int negotiate_using_version(quicly_conn_t *conn, uint32_t version) /* set selected version, update transport parameters extension ID */ conn->super.version = version; QUICLY_PROBE(VERSION_SWITCH, conn, conn->stash.now, version); - QUICLY_LOG_CONN(version_switch, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_UNSIGNED(new_version, version); - }); + QUICLY_LOG_CONN(version_switch, conn, { PTLS_LOG_ELEMENT_UNSIGNED(new_version, version); }); /* replace initial keys */ if ((ret = reinstall_initial_encryption(conn, PTLS_ERROR_LIBRARY)) != 0) @@ -5712,7 +5624,6 @@ static int handle_transport_close_frame(quicly_conn_t *conn, struct st_quicly_ha QUICLY_PROBE(TRANSPORT_CLOSE_RECEIVE, conn, conn->stash.now, frame.error_code, frame.frame_type, QUICLY_PROBE_ESCAPE_UNSAFE_STRING(frame.reason_phrase.base, frame.reason_phrase.len)); QUICLY_LOG_CONN(transport_close_receive, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(error_code, frame.error_code); PTLS_LOG_ELEMENT_UNSIGNED(frame_type, frame.frame_type); PTLS_LOG_ELEMENT_UNSAFESTR(reason_phrase, (const char *)frame.reason_phrase.base, frame.reason_phrase.len); @@ -5731,7 +5642,6 @@ static int handle_application_close_frame(quicly_conn_t *conn, struct st_quicly_ QUICLY_PROBE(APPLICATION_CLOSE_RECEIVE, conn, conn->stash.now, frame.error_code, QUICLY_PROBE_ESCAPE_UNSAFE_STRING(frame.reason_phrase.base, frame.reason_phrase.len)); QUICLY_LOG_CONN(application_close_receive, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(error_code, frame.error_code); PTLS_LOG_ELEMENT_UNSAFESTR(reason_phrase, (const char *)frame.reason_phrase.base, frame.reason_phrase.len); }); @@ -5746,7 +5656,7 @@ static int handle_padding_frame(quicly_conn_t *conn, struct st_quicly_handle_pay static int handle_ping_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) { QUICLY_PROBE(PING_RECEIVE, conn, conn->stash.now); - QUICLY_LOG_CONN(ping_receive, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(ping_receive, conn, {}); return 0; } @@ -5765,7 +5675,6 @@ static int handle_new_connection_id_frame(quicly_conn_t *conn, struct st_quicly_ QUICLY_PROBE_HEXDUMP(frame.cid.base, frame.cid.len), QUICLY_PROBE_HEXDUMP(frame.stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN)); QUICLY_LOG_CONN(new_connection_id_receive, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(sequence, frame.sequence); PTLS_LOG_ELEMENT_UNSIGNED(retire_prior_to, frame.retire_prior_to); PTLS_LOG_ELEMENT_HEXDUMP(cid, frame.cid.base, frame.cid.len); @@ -5808,10 +5717,7 @@ static int handle_retire_connection_id_frame(quicly_conn_t *conn, struct st_quic return ret; QUICLY_PROBE(RETIRE_CONNECTION_ID_RECEIVE, conn, conn->stash.now, frame.sequence); - QUICLY_LOG_CONN(retire_connection_id_receive, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_UNSIGNED(sequence, frame.sequence); - }); + QUICLY_LOG_CONN(retire_connection_id_receive, conn, { PTLS_LOG_ELEMENT_UNSIGNED(sequence, frame.sequence); }); if (frame.sequence >= conn->super.local.cid_set.plaintext.path_id) { /* Receipt of a RETIRE_CONNECTION_ID frame containing a sequence number greater than any previously sent to the remote peer @@ -5832,7 +5738,7 @@ static int handle_handshake_done_frame(quicly_conn_t *conn, struct st_quicly_han int ret; QUICLY_PROBE(HANDSHAKE_DONE_RECEIVE, conn, conn->stash.now); - QUICLY_LOG_CONN(handshake_done_receive, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(handshake_done_receive, conn, {}); if (!quicly_is_client(conn)) return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; @@ -5861,10 +5767,7 @@ static int handle_datagram_frame(quicly_conn_t *conn, struct st_quicly_handle_pa if ((ret = quicly_decode_datagram_frame(state->frame_type, &state->src, state->end, &frame)) != 0) return ret; QUICLY_PROBE(DATAGRAM_RECEIVE, conn, conn->stash.now, frame.payload.base, frame.payload.len); - QUICLY_LOG_CONN(datagram_receive, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLS_LOG_ELEMENT_UNSIGNED(payload_len, frame.payload.len); - }); + QUICLY_LOG_CONN(datagram_receive, conn, { PTLS_LOG_ELEMENT_UNSIGNED(payload_len, frame.payload.len); }); /* handle the frame. Applications might call quicly_close or other functions that modify the connection state. */ conn->super.ctx->receive_datagram_frame->cb(conn->super.ctx->receive_datagram_frame, conn, frame.payload); @@ -5887,7 +5790,6 @@ static int handle_ack_frequency_frame(quicly_conn_t *conn, struct st_quicly_hand QUICLY_PROBE(ACK_FREQUENCY_RECEIVE, conn, conn->stash.now, frame.sequence, frame.packet_tolerance, frame.max_ack_delay, (int)frame.ignore_order, (int)frame.ignore_ce); QUICLY_LOG_CONN(ack_frequency_receive, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(sequence, frame.sequence); PTLS_LOG_ELEMENT_UNSIGNED(packet_tolerance, frame.packet_tolerance); PTLS_LOG_ELEMENT_UNSIGNED(max_ack_delay, frame.max_ack_delay); @@ -6043,7 +5945,7 @@ static int handle_payload(quicly_conn_t *conn, size_t epoch, const uint8_t *_src static int handle_stateless_reset(quicly_conn_t *conn) { QUICLY_PROBE(STATELESS_RESET_RECEIVE, conn, conn->stash.now); - QUICLY_LOG_CONN(stateless_reset_receive, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(stateless_reset_receive, conn, {}); return handle_close(conn, QUICLY_ERROR_RECEIVED_STATELESS_RESET, UINT64_MAX, ptls_iovec_init("", 0)); } @@ -6129,13 +6031,11 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * QUICLY_PROBE(ACCEPT, *conn, (*conn)->stash.now, QUICLY_PROBE_HEXDUMP(packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len), address_token); QUICLY_LOG_CONN(accept, *conn, { - PTLS_LOG_ELEMENT_SIGNED(time, (*conn)->stash.now); PTLS_LOG_ELEMENT_HEXDUMP(dcid, packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len); PTLS_LOG_ELEMENT_PTR(address_token, address_token); }); QUICLY_PROBE(PACKET_RECEIVED, *conn, (*conn)->stash.now, pn, payload.base, payload.len, get_epoch(packet->octets.base[0])); QUICLY_LOG_CONN(packet_received, *conn, { - PTLS_LOG_ELEMENT_SIGNED(time, (*conn)->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(pn, pn); PTLS_LOG_ELEMENT_UNSIGNED(decrypted_len, payload.len); PTLS_LOG_ELEMENT_UNSIGNED(packet_type, get_epoch(packet->octets.base[0])); @@ -6187,7 +6087,6 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka QUICLY_PROBE_HEXDUMP(packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len), packet->octets.base, packet->octets.len); QUICLY_LOG_CONN(receive, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_HEXDUMP(dcid, packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len); PTLS_LOG_ELEMENT_HEXDUMP(bytes, packet->octets.base, packet->octets.len); }); @@ -6349,7 +6248,6 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka QUICLY_PROBE(PACKET_RECEIVED, conn, conn->stash.now, pn, payload.base, payload.len, get_epoch(packet->octets.base[0])); QUICLY_LOG_CONN(packet_received, conn, { - PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); PTLS_LOG_ELEMENT_UNSIGNED(pn, pn); PTLS_LOG_ELEMENT_UNSIGNED(decrypted_len, payload.len); PTLS_LOG_ELEMENT_UNSIGNED(packet_type, get_epoch(packet->octets.base[0])); @@ -6489,7 +6387,7 @@ int quicly_open_stream(quicly_conn_t *conn, quicly_stream_t **_stream, int uni) /* application-layer initialization */ QUICLY_PROBE(STREAM_ON_OPEN, conn, conn->stash.now, stream); - QUICLY_LOG_CONN(stream_on_open, conn, { PTLS_LOG_ELEMENT_SIGNED(time, conn->stash.now); }); + QUICLY_LOG_CONN(stream_on_open, conn, {}); if ((ret = conn->super.ctx->stream_open->cb(conn->super.ctx->stream_open, stream)) != 0) return ret; From 6bc5e19ab54884919d9aa57f3561345cff26f4db Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 7 Oct 2022 15:23:54 +0900 Subject: [PATCH 274/361] revert changes to src/cli.c; we should be replacing `-e` --- src/cli.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/cli.c b/src/cli.c index e57c6356b..d738156f9 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1025,7 +1025,6 @@ static void usage(const char *cmd) " -G enable UDP generic segmentation offload\n" " -i interval interval to reissue requests (in milliseconds)\n" " -I timeout idle timeout (in milliseconds; default: 600,000)\n" - " -j log-file file to log probe events in JSON-Lines\n" " -K num-packets perform key update every num-packets packets\n" " -l log-file file to log traffic secrets\n" " -M max stream data (in bytes; default: 1MB)\n" @@ -1068,16 +1067,6 @@ static void push_req(const char *path, int to_file) memset(reqs + i + 1, 0, sizeof(*reqs)); } -static void setup_ptlslog(const char *fn) -{ - int fd; - if ((fd = open(fn, O_WRONLY | O_CREAT | O_APPEND, 0666)) == -1) { - fprintf(stderr, "failed to open file:%s:%s\n", fn, strerror(errno)); - exit(1); - } - ptls_log_add_fd(fd); -} - int main(int argc, char **argv) { const char *cert_file = NULL, *raw_pubkey_file = NULL, *host, *port, *cid_key = NULL; @@ -1105,7 +1094,7 @@ int main(int argc, char **argv) address_token_aead.dec = ptls_aead_new(&ptls_openssl_aes128gcm, &ptls_openssl_sha256, 0, secret, ""); } - while ((ch = getopt(argc, argv, "a:b:B:c:C:Dd:k:Ee:f:Gi:I:j:K:l:M:m:NnOp:P:Rr:S:s:u:U:Vvw:W:x:X:y:h")) != -1) { + while ((ch = getopt(argc, argv, "a:b:B:c:C:Dd:k:Ee:f:Gi:I:K:l:M:m:NnOp:P:Rr:S:s:u:U:Vvw:W:x:X:y:h")) != -1) { switch (ch) { case 'a': assert(negotiated_protocols.count < PTLS_ELEMENTSOF(negotiated_protocols.list)); @@ -1186,10 +1175,6 @@ int main(int argc, char **argv) fprintf(stderr, "failed to parse idle timeout: %s\n", optarg); exit(1); } - break; - case 'j': - setup_ptlslog(optarg); - break; case 'K': if (sscanf(optarg, "%" SCNu64, &ctx.max_packets_per_key) != 1) { fprintf(stderr, "failed to parse key update interval: %s\n", optarg); From 6999eba9ab1110248ae9c8db15196a8e6b995352 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 11 Oct 2022 10:39:47 +0900 Subject: [PATCH 275/361] [cli] use the new logging API --- src/cli.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/cli.c b/src/cli.c index d738156f9..6152047cd 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1149,13 +1149,14 @@ int main(int argc, char **argv) case 'E': ctx.expand_client_hello = 1; break; - case 'e': - if ((quicly_trace_fp = fopen(optarg, "w")) == NULL) { + case 'e': { + int fd; + if ((fd = open(optarg, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) { fprintf(stderr, "failed to open file:%s:%s\n", optarg, strerror(errno)); exit(1); } - setvbuf(quicly_trace_fp, NULL, _IONBF, 0); - break; + ptls_log_add_fd(fd); + } break; case 'f': { double fraction; if (sscanf(optarg, "%lf", &fraction) != 1) { From ea918c362569fa3269567c6c2f987e30d99dd157 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 11 Oct 2022 10:39:54 +0900 Subject: [PATCH 276/361] update test --- t/e2e.t | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/t/e2e.t b/t/e2e.t index 05a35f3bf..3fb38e41b 100755 --- a/t/e2e.t +++ b/t/e2e.t @@ -40,8 +40,8 @@ subtest "hello" => sub { subtest "events" => sub { my $events = slurp_file("$tempdir/events"); complex $events, sub { - $_ =~ /"type":"transport-close-send",.*?"type":"([^\"]*)",.*?"type":"([^\"]*)",.*?"type":"([^\"]*)",.*?"type":"([^\"]*)"/s - and $1 eq 'packet-sent' and $2 eq 'send' and $3 eq 'free'; + $_ =~ /"type":"transport_close_send",.*?"type":"([^\"]*)",.*?"type":"([^\"]*)",.*?"type":"([^\"]*)",.*?"type":"([^\"]*)"/s + and $1 eq 'packet_sent' and $2 eq 'send' and $3 eq 'free'; }; }; # check if the client receives extra connection IDs @@ -51,7 +51,7 @@ subtest "hello" => sub { my @seen; my @expected = (0, 1, 1, 1); # expecting to see sequence=1,2,3 as we set active_connection_id_limit to 4 foreach (split(/\n/)) { - if ( /"type":"new-connection-id-receive",.*"sequence":([0-9]+),/ ) { + if ( /"type":"new_connection_id_receive",.*"sequence":([0-9]+),/ ) { # $1 contains sequence number $seen[$1] = 1; } @@ -84,7 +84,7 @@ subtest "version-negotiation" => sub { my $resp = `$cli -n -e $tempdir/events -p /12 127.0.0.1 $port 2> /dev/null`; is $resp, "hello world\n"; my $events = slurp_file("$tempdir/events"); - if ($events =~ /"type":"connect",.*"version":(\d+)(?:.|\n)*"type":"version-switch",.*"new-version":(\d+)/m) { + if ($events =~ /"type":"connect",.*"version":(\d+)(?:.|\n)*"type":"version_switch",.*"new_version":(\d+)/m) { is $2, 1; isnt $1, 1; } else { @@ -102,7 +102,7 @@ subtest "retry" => sub { my $events = slurp_file("$tempdir/events"); unlike $events, qr/version-switch/, "no version switch"; complex $events, sub { - $_ =~ qr/"type":"receive",.*"first-octet":(\d+).*\n.*"type":"stream-lost",.*"stream-id":-1,.*"off":0,/ and $1 >= 240 + $_ =~ qr/"type":"receive",.*"bytes":"([0-9A-Fa-f]{2}).*\n.*"type":"stream_lost",.*"stream_id":-1,.*"off":0,/ and hex($1) >= 240 }, "CH deemed lost in response to retry"; }; } @@ -115,7 +115,7 @@ subtest "large-client-hello" => sub { my $events = slurp_file("$tempdir/events"); complex $events, sub { my $before_receive = (split /"receive"/, $_)[0]; - $before_receive =~ /"stream-send".*?\n.*?"stream-send"/s; + $before_receive =~ /"stream_send".*?\n.*?"stream_send"/s; }; }; @@ -128,8 +128,8 @@ subtest "0-rtt" => sub { ok -e "$tempdir/session", "session saved"; system "$cli -s $tempdir/session -e $tempdir/events 127.0.0.1 $port > /dev/null 2>&1"; my $events = slurp_file("$tempdir/events"); - like $events, qr/"type":"stream-send".*"stream-id":0,(.|\n)*"type":"packet-sent".*"pn":1,/m, "stream 0 on pn 1"; - like $events, qr/"type":"cc-ack-received".*"largest-acked":1,/m, "pn 1 acked"; + like $events, qr/"type":"stream_send".*"stream_id":0,(.|\n)*"type":"packet_sent".*"pn":1,/m, "stream 0 on pn 1"; + like $events, qr/"type":"cc_ack_received".*"largest_acked":1,/m, "pn 1 acked"; }; unlink "$tempdir/session"; @@ -156,7 +156,7 @@ subtest "retry-invalid-token" => sub { $resp = `$cli -e $tempdir/events -s $tempdir/session -p /12 127.0.0.1 $port 2> /dev/null`; isnt $resp, "hello world\n", "not a valid response"; my $events = slurp_file("$tempdir/events"); - like $events, qr/"type":"transport-close-receive",.*"error-code":11,.*"reason-phrase":"token decryption failure"/m, "received token decryption failure"; + like $events, qr/"type":"transport_close_receive",.*"error_code":11,.*"reason_phrase":"token decryption failure"/m, "received token decryption failure"; }; subtest "stateless-reset" => sub { @@ -180,8 +180,8 @@ subtest "stateless-reset" => sub { } # check that the stateless reset is logged my $events = slurp_file("$tempdir/events"); - like $events, qr/"type":"stateless-reset-receive",/m, 'got stateless reset'; - unlike +($events =~ /"type":"stateless-reset-receive",.*?\n/ and $'), qr/"type":"packet-sent",/m, 'nothing sent after receiving stateless reset'; + like $events, qr/"type":"stateless_reset_receive",/m, 'got stateless reset'; + unlike +($events =~ /"type":"stateless_reset_receive",.*?\n/ and $'), qr/"type":"packet_sent",/m, 'nothing sent after receiving stateless reset'; }; subtest "no-compatible-version" => sub { @@ -222,8 +222,8 @@ subtest "idle-timeout" => sub { like $resp, qr/^hello world\n(|hello world\n|)$/s; sleep 2; undef $guard; - like slurp_file("$tempdir/client-events"), qr/"type":("idle-timeout"|"stateless-reset-receive"),/m; - like slurp_file("$tempdir/server-events"), qr/"type":"idle-timeout",/m; + like slurp_file("$tempdir/client-events"), qr/"type":("idle_timeout"|"stateless_reset_receive"),/m; + like slurp_file("$tempdir/server-events"), qr/"type":"idle_timeout",/m; }; subtest "blocked-streams" => sub { @@ -247,14 +247,14 @@ subtest "max-data-crapped" => sub { my $events = ":"; while (my $line = <$fh>) { my $event = from_json($line); - if ($event->{type} =~ /^(send|receive|max-data-receive)$/) { + if ($event->{type} =~ /^(send|receive|max_data_receive)$/) { $events .= "$event->{type}:"; - } elsif ($event->{type} eq 'stream-send') { - $events .= "stream-send\@$event->{'stream-id'}:"; + } elsif ($event->{type} eq 'stream_send') { + $events .= "stream_send\@$event->{stream_id}:"; } } # check that events are happening in expected order, without a busy loop to quicly_send - like $events, qr/:send:stream-send\@0:receive:max-data-receive:send:stream-send\@0:/; + like $events, qr/:send:stream_send\@0:receive:max_data_receive:send:stream_send\@0:/; }; unlink "$tempdir/session"; @@ -302,7 +302,7 @@ subtest "key-update" => sub { local $/; <$fh>; }; - () = $loglines =~ /{"type":"crypto-send-key-update",/sg; + () = $loglines =~ /,"type":"crypto_send_key_update",/sg; }; if ($doing_updates) { cmp_ok($num_key_updates, ">=", 4); From 27978fc363e04841eb81bd482fec0851b157fd2a Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 11 Oct 2022 10:55:36 +0900 Subject: [PATCH 277/361] merge qlog-adapter tests to e2e.t --- t/e2e.t | 17 ++++++++ t/qlog-adaprter.t | 106 ---------------------------------------------- 2 files changed, 17 insertions(+), 106 deletions(-) delete mode 100755 t/qlog-adaprter.t diff --git a/t/e2e.t b/t/e2e.t index 3fb38e41b..0b986bbb2 100755 --- a/t/e2e.t +++ b/t/e2e.t @@ -37,13 +37,30 @@ subtest "hello" => sub { my $guard = spawn_server(); my $resp = `$cli -e $tempdir/events -p /12 127.0.0.1 $port 2> /dev/null`; is $resp, "hello world\n"; + subtest "events" => sub { my $events = slurp_file("$tempdir/events"); complex $events, sub { $_ =~ /"type":"transport_close_send",.*?"type":"([^\"]*)",.*?"type":"([^\"]*)",.*?"type":"([^\"]*)",.*?"type":"([^\"]*)"/s and $1 eq 'packet_sent' and $2 eq 'send' and $3 eq 'free'; }; + + # check that the events are compatible with qlog-adapter + subtest "qlog-adapter" => sub { + plan skip_all => "python3 not found" + unless system("which python3 > /dev/null 2>&1") == 0; + my $qlog = `misc/qlog-adapter.py < $tempdir/events`; + is $?, 0, "qlog-adapter can transform raw event logs"; + diag("qlog:\n$qlog") if $ENV{TEST_DEBUG}; + my @events = map { decode_json($_) } split /\n/, $qlog; + cmp_ok scalar(@events), ">=", 2, "it has at least two events"; + + # https://github.com/quicwg/qlog/blob/main/draft-ietf-quic-qlog-main-schema.md#the-high-level-qlog-schema-top-level + ok $events[0]->{qlog_version}, "it has qlog_version"; + # TODO: validate the events according to the qlog schema + }; }; + # check if the client receives extra connection IDs subtest "initial-ncid" => sub { my $events = slurp_file("$tempdir/events"); diff --git a/t/qlog-adaprter.t b/t/qlog-adaprter.t deleted file mode 100755 index 613c9eabb..000000000 --- a/t/qlog-adaprter.t +++ /dev/null @@ -1,106 +0,0 @@ -#! /usr/bin/env perl - -use strict; -use warnings; -use Digest::MD5 qw(md5_hex); -use File::Temp qw(tempdir); -use IO::Socket::INET; -use JSON; -use Net::EmptyPort qw(empty_port); -use POSIX ":sys_wait_h"; -use Scope::Guard qw(scope_guard); -use Test::More; -use Time::HiRes qw(sleep); - -$ENV{BINARY_DIR} ||= "."; -my $cli = "$ENV{BINARY_DIR}/cli"; -my $port = empty_port({ - host => "127.0.0.1", - proto => "udp", -}); -my $tempdir = tempdir(CLEANUP => 1); - -subtest "hello" => sub { - my $guard = spawn_server(); - my $resp = `$cli -j $tempdir/events -p /12 127.0.0.1 $port 2> /dev/null`; - is $resp, "hello world\n"; - - subtest "events" => sub { - my $events_jsonl = slurp_file("$tempdir/events"); - diag("raw events:\n$events_jsonl") if $ENV{TEST_DEBUG}; - - my @events = map { decode_json($_) } split /\n/, $events_jsonl; - - my ($event) = find_event(\@events, "quicly", "connect"); - ok $event, "quicly:connect exists"; - is $event->{version}, 1; - - ($event) = find_event(\@events, "quicly", "free"); - ok $event, "quicly:free exists"; - }; - - subtest "qlog-adapter", sub { - my $qlog = `misc/qlog-adapter.py < $tempdir/events`; - is $?, 0, "qlog-adapter can transform raw event logs"; - diag("qlog:\n$qlog") if $ENV{TEST_DEBUG}; - my @events = map { decode_json($_) } split /\n/, $qlog; - cmp_ok scalar(@events), ">=", 2, "it has at least two events"; - - # https://github.com/quicwg/qlog/blob/main/draft-ietf-quic-qlog-main-schema.md#the-high-level-qlog-schema-top-level - ok $events[0]->{qlog_version}, "it has qlog_version"; - # TODO: validate the events according to the qlog schema - }; -}; - - -done_testing; - -sub find_event { - my($events, $module, $type) = @_; - - my @results; - for my $event (@$events) { - if ($event->{module} eq $module && $event->{type} eq $type) { - push @results, $event; - } - } - return @results; -} - -sub spawn_server { - my @cmd; - if (grep(/^-W$/, @_)) { - @cmd = ($cli, "-k", "t/assets/ec256-key-pair.pem", "-c", "t/assets/ec256-pub.pem", @_, "127.0.0.1", $port); - } else { - @cmd = ($cli, "-k", "t/assets/server.key", "-c", "t/assets/server.crt", @_, "127.0.0.1", $port); - } - my $pid = fork; - die "fork failed:$!" - unless defined $pid; - if ($pid == 0) { - exec @cmd; - die "failed to exec $cmd[0]:$?"; - } - while (`netstat -na` !~ /^udp.*\s127\.0\.0\.1[\.:]$port\s/m) { - if (waitpid($pid, WNOHANG) == $pid) { - die "failed to launch server"; - } - sleep 0.1; - } - return scope_guard(sub { - kill 9, $pid; - while (waitpid($pid, 0) != $pid) {} - }); -} - -sub slurp_file { - my $fn = shift; - open my $fh, "<", $fn - or die "failed to open file:$fn:$!"; - do { - local $/; - <$fh>; - }; -} - -1; From d845748959b8dedceca71b2dcced7f792b762833 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 11 Oct 2022 12:10:54 +0900 Subject: [PATCH 278/361] stream IDs are represented as `quicly_stream_id_t`, that type should be exposed in dtrace --- quicly-probes.d | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/quicly-probes.d b/quicly-probes.d index a8f688e8d..3903b78ff 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -90,10 +90,10 @@ provider quicly { probe stream_lost(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t off, size_t len); probe reset_stream_send(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint16_t error_code, uint64_t final_size); - probe reset_stream_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t stream_id, uint16_t error_code, uint64_t final_size); + probe reset_stream_receive(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint16_t error_code, uint64_t final_size); probe stop_sending_send(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint16_t error_code); - probe stop_sending_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t stream_id, uint16_t error_code); + probe stop_sending_receive(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint16_t error_code); probe max_data_send(struct st_quicly_conn_t *conn, int64_t at, uint64_t maximum); probe max_data_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t maximum); @@ -102,7 +102,7 @@ provider quicly { probe max_streams_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t maximum, int is_unidirectional); probe max_stream_data_send(struct st_quicly_conn_t *conn, int64_t at, struct st_quicly_stream_t *stream, uint64_t maximum); - probe max_stream_data_receive(struct st_quicly_conn_t *conn, int64_t at, uint64_t stream_id, uint64_t maximum); + probe max_stream_data_receive(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t maximum); probe new_token_send(struct st_quicly_conn_t *conn, int64_t at, uint8_t *token, size_t token_len, uint64_t generation); probe new_token_acked(struct st_quicly_conn_t *conn, int64_t at, uint64_t generation); From 00db816ef72eac7891fd7b06e542daf71f2faef6 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 11 Oct 2022 12:17:35 +0900 Subject: [PATCH 279/361] use type consistent with probes --- lib/quicly.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index c83bac9e3..722de0574 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5114,7 +5114,7 @@ static int handle_reset_stream_frame(quicly_conn_t *conn, struct st_quicly_handl QUICLY_PROBE(RESET_STREAM_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.app_error_code, frame.final_size); QUICLY_LOG_CONN(reset_stream_receive, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(stream_id, frame.stream_id); + PTLSLOG_ELEMENT_SIGNED(stream_id, (quicly_stream_id_t)frame.stream_id); PTLSLOG_ELEMENT_UNSIGNED(app_error_code, frame.app_error_code); PTLSLOG_ELEMENT_UNSIGNED(final_size, frame.final_size); }); @@ -5309,7 +5309,7 @@ static int handle_max_stream_data_frame(quicly_conn_t *conn, struct st_quicly_ha QUICLY_PROBE(MAX_STREAM_DATA_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.max_stream_data); QUICLY_LOG_CONN(max_stream_data_receive, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(stream_id, frame.stream_id); + PTLSLOG_ELEMENT_SIGNED(stream_id, (quicly_stream_id_t)frame.stream_id); PTLSLOG_ELEMENT_UNSIGNED(max_stream_data, frame.max_stream_data); }); @@ -5479,7 +5479,7 @@ static int handle_stop_sending_frame(quicly_conn_t *conn, struct st_quicly_handl QUICLY_PROBE(STOP_SENDING_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.app_error_code); QUICLY_LOG_CONN(stop_sending_receive, conn, { PTLSLOG_ELEMENT_SIGNED(time, conn->stash.now); - PTLSLOG_ELEMENT_UNSIGNED(stream_id, frame.stream_id); + PTLSLOG_ELEMENT_SIGNED(stream_id, (quicly_stream_id_t)frame.stream_id); PTLSLOG_ELEMENT_UNSIGNED(error_code, frame.app_error_code); }); From d8767a1a8c2df3bcdabcfc1b76d8a3b485298d5c Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 11 Oct 2022 11:16:05 +0900 Subject: [PATCH 280/361] get rid of embedded-probes now `cli -e` using the new logging mechanism --- CMakeLists.txt | 12 +++--------- lib/quicly.c | 10 ++++------ 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fe05fe682..4ad9e2879 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,11 +99,6 @@ IF (WITH_DTRACE) ENDIF () ENDIF () -ADD_CUSTOM_COMMAND( - OUTPUT embedded-probes.h - COMMAND ${PROJECT_SOURCE_DIR}/misc/probe2trace.pl -a embedded < ${PROJECT_SOURCE_DIR}/quicly-probes.d > ${CMAKE_CURRENT_BINARY_DIR}/embedded-probes.h - DEPENDS quicly-probes.d misc/probe2trace.pl - VERBATIM) ADD_CUSTOM_COMMAND( OUTPUT quicly-tracer.h COMMAND ${PROJECT_SOURCE_DIR}/misc/probe2trace.pl -a tracer < ${PROJECT_SOURCE_DIR}/quicly-probes.d > ${CMAKE_CURRENT_BINARY_DIR}/quicly-tracer.h @@ -113,8 +108,8 @@ ADD_CUSTOM_COMMAND( ADD_LIBRARY(quicly ${QUICLY_LIBRARY_FILES}) TARGET_LINK_LIBRARIES(quicly LINK_PUBLIC m) -SET(CLI_FILES ${PICOTLS_OPENSSL_FILES} ${QUICLY_LIBRARY_FILES} src/cli.c embedded-probes.h) -SET(CLI_COMPILE_FLAGS "-DQUICLY_USE_EMBEDDED_PROBES=1") +SET(CLI_FILES ${PICOTLS_OPENSSL_FILES} ${QUICLY_LIBRARY_FILES} src/cli.c) +SET(CLI_COMPILE_FLAGS "") IF (WITH_FUSION) LIST(APPEND CLI_FILES deps/picotls/lib/fusion.c) SET(CLI_COMPILE_FLAGS "-mavx2 -maes -mpclmul -mvaes -mvpclmulqdq -DQUICLY_HAVE_FUSION=1 ${CLI_COMPILE_FLAGS}") @@ -126,8 +121,7 @@ TARGET_LINK_LIBRARIES(cli ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS} m) ADD_EXECUTABLE(test.t ${PICOTLS_OPENSSL_FILES} ${UNITTEST_SOURCE_FILES}) TARGET_LINK_LIBRARIES(test.t quicly ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS}) -ADD_EXECUTABLE(simulator ${PICOTLS_OPENSSL_FILES} ${QUICLY_LIBRARY_FILES} t/simulator.c embedded-probes.h) -SET_TARGET_PROPERTIES(simulator PROPERTIES COMPILE_FLAGS "-DQUICLY_USE_EMBEDDED_PROBES=1") +ADD_EXECUTABLE(simulator ${PICOTLS_OPENSSL_FILES} ${QUICLY_LIBRARY_FILES} t/simulator.c) TARGET_LINK_LIBRARIES(simulator ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS} m) ADD_EXECUTABLE(examples-echo ${PICOTLS_OPENSSL_FILES} examples/echo.c) diff --git a/lib/quicly.c b/lib/quicly.c index c4b673198..78fcf6e78 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -35,9 +35,7 @@ #include "quicly/frame.h" #include "quicly/streambuf.h" #include "quicly/cc.h" -#if QUICLY_USE_EMBEDDED_PROBES -#include "embedded-probes.h" -#elif QUICLY_USE_DTRACE +#if QUICLY_USE_DTRACE #include "quicly-probes.h" #endif #include "quicly/retire_cid.h" @@ -82,7 +80,7 @@ KHASH_MAP_INIT_INT64(quicly_stream_t, quicly_stream_t *) #define QUICLY_TRACER(...) #endif -#if QUICLY_USE_EMBEDDED_PROBES || QUICLY_USE_DTRACE +#if QUICLY_USE_DTRACE #define QUICLY_PROBE(label, conn, ...) \ do { \ quicly_conn_t *_conn = (conn); \ @@ -1593,7 +1591,7 @@ void quicly_free(quicly_conn_t *conn) QUICLY_PROBE(FREE, conn, conn->stash.now); QUICLY_LOG_CONN(free, conn, {}); -#if QUICLY_USE_EMBEDDED_PROBES || QUICLY_USE_DTRACE +#if QUICLY_USE_DTRACE if (QUICLY_CONN_STATS_ENABLED()) { quicly_stats_t stats; quicly_get_stats(conn, &stats); @@ -6777,7 +6775,7 @@ const quicly_stream_callbacks_t quicly_stream_noop_callbacks = { void quicly__debug_printf(quicly_conn_t *conn, const char *function, int line, const char *fmt, ...) { -#if QUICLY_USE_EMBEDDED_PROBES || QUICLY_USE_DTRACE +#if QUICLY_USE_DTRACE char buf[1024]; va_list args; From 8816110f40146e821a18af575e5030057be9a6ca Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 11 Oct 2022 12:34:46 +0900 Subject: [PATCH 281/361] xcode follow up of d8767a1 --- quicly.xcodeproj/project.pbxproj | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/quicly.xcodeproj/project.pbxproj b/quicly.xcodeproj/project.pbxproj index 03b64b8aa..a58df4c93 100644 --- a/quicly.xcodeproj/project.pbxproj +++ b/quicly.xcodeproj/project.pbxproj @@ -35,6 +35,7 @@ 0829878F26E03D4D0053638F /* rate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0829878D26E03D4D0053638F /* rate.c */; }; 0829879026E03D4D0053638F /* rate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0829878D26E03D4D0053638F /* rate.c */; }; 0829879226E0A9DF0053638F /* rate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0829879126E0A9DF0053638F /* rate.c */; }; + 085125F828F51BA20074C124 /* quicly-probes.d in Sources */ = {isa = PBXBuildFile; fileRef = E95EBCCD227EC13F0022C32D /* quicly-probes.d */; }; 086001CB273271E80043886F /* rate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0829878D26E03D4D0053638F /* rate.c */; }; E904233D24AED0410072C5B7 /* loss.c in Sources */ = {isa = PBXBuildFile; fileRef = E904233C24AED0410072C5B7 /* loss.c */; }; E904233E24AED0410072C5B7 /* loss.c in Sources */ = {isa = PBXBuildFile; fileRef = E904233C24AED0410072C5B7 /* loss.c */; }; @@ -621,7 +622,6 @@ isa = PBXNativeTarget; buildConfigurationList = E98448371EA48D6B00390927 /* Build configuration list for PBXNativeTarget "cli" */; buildPhases = ( - E941428B23B0B70F002D3CE0 /* ShellScript */, E984482F1EA48D6B00390927 /* Sources */, E98448301EA48D6B00390927 /* Frameworks */, E98448311EA48D6B00390927 /* CopyFiles */, @@ -749,25 +749,6 @@ shellPath = /bin/sh; shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\nexec $SRCROOT/misc/probe2trace.pl -a tracer < $SRCROOT/quicly-probes.d > $DERIVED_FILES_DIR/quicly-tracer.h\n"; }; - E941428B23B0B70F002D3CE0 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "$(SRCROOT)/quicly-probes.d", - ); - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILES_DIR)/embedded-probes.h", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\nexec $SRCROOT/misc/probe2trace.pl -a embedded < $SRCROOT/quicly-probes.d > $DERIVED_FILES_DIR/embedded-probes.h\n"; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -862,6 +843,7 @@ E941428A23B0B454002D3CE0 /* quicly.c in Sources */, E941429323B0B879002D3CE0 /* sentmap.c in Sources */, E984483C1EA48DD300390927 /* picotls.c in Sources */, + 085125F828F51BA20074C124 /* quicly-probes.d in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 3feb205a4bd1172f3287bbe99b67eefcf74fa6fc Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 11 Oct 2022 13:49:46 +0900 Subject: [PATCH 282/361] use PTLSLOG_APPDATA_ELEMENT_* --- deps/picotls | 2 +- lib/quicly.c | 26 ++++++++++++++++++-------- src/cli.c | 1 + 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/deps/picotls b/deps/picotls index aa08aa501..8c633b7c3 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit aa08aa501238f0e0bd2e78238fa9bd0f46466b55 +Subproject commit 8c633b7c391dd4aab9cd844618c84383546f32ac diff --git a/lib/quicly.c b/lib/quicly.c index 83cd805c1..04a75b8e3 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1552,7 +1552,10 @@ static int update_1rtt_egress_key(quicly_conn_t *conn) QUICLY_PROBE(CRYPTO_SEND_KEY_UPDATE, conn, conn->stash.now, space->cipher.egress.key_phase, QUICLY_PROBE_HEXDUMP(space->cipher.egress.secret, cipher->hash->digest_size)); - QUICLY_LOG_CONN(crypto_send_key_update, conn, { PTLS_LOG_ELEMENT_UNSIGNED(phase, space->cipher.egress.key_phase); }); + QUICLY_LOG_CONN(crypto_send_key_update, conn, { + PTLS_LOG_ELEMENT_UNSIGNED(phase, space->cipher.egress.key_phase); + PTLS_LOG_APPDATA_ELEMENT_HEXDUMP(secret, space->cipher.egress.secret, cipher->hash->digest_size); + }); return 0; } @@ -1568,8 +1571,11 @@ static int received_key_update(quicly_conn_t *conn, uint64_t newly_decrypted_key QUICLY_PROBE(CRYPTO_RECEIVE_KEY_UPDATE, conn, conn->stash.now, space->cipher.ingress.key_phase.decrypted, QUICLY_PROBE_HEXDUMP(space->cipher.ingress.secret, ptls_get_cipher(conn->crypto.tls)->hash->digest_size)); - QUICLY_LOG_CONN(crypto_receive_key_update, conn, - { PTLS_LOG_ELEMENT_UNSIGNED(phase, space->cipher.ingress.key_phase.decrypted); }); + QUICLY_LOG_CONN(crypto_receive_key_update, conn, { + PTLS_LOG_ELEMENT_UNSIGNED(phase, space->cipher.ingress.key_phase.decrypted); + PTLS_LOG_APPDATA_ELEMENT_HEXDUMP(secret, space->cipher.ingress.secret, + ptls_get_cipher(conn->crypto.tls)->hash->digest_size); + }); if (space->cipher.egress.key_phase < space->cipher.ingress.key_phase.decrypted) { return update_1rtt_egress_key(conn); @@ -1749,7 +1755,7 @@ static int apply_stream_frame(quicly_stream_t *stream, quicly_stream_frame_t *fr QUICLY_LOG_CONN(stream_on_receive, stream->conn, { PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); PTLS_LOG_ELEMENT_UNSIGNED(off, buf_offset); - PTLS_LOG_ELEMENT_UNSIGNED(src_len, apply_len); + PTLS_LOG_APPDATA_ELEMENT_HEXDUMP(src, apply_src, apply_len); }); stream->callbacks->on_receive(stream, (size_t)buf_offset, apply_src, apply_len); if (stream->conn->super.state >= QUICLY_STATE_CLOSING) @@ -2466,8 +2472,10 @@ static int aead_decrypt_1rtt(void *ctx, uint64_t pn, quicly_decoded_packet_t *pa ++space->cipher.ingress.key_phase.prepared; QUICLY_PROBE(CRYPTO_RECEIVE_KEY_UPDATE_PREPARE, conn, conn->stash.now, space->cipher.ingress.key_phase.prepared, QUICLY_PROBE_HEXDUMP(space->cipher.ingress.secret, cipher->hash->digest_size)); - QUICLY_LOG_CONN(crypto_receive_key_update_prepare, conn, - { PTLS_LOG_ELEMENT_UNSIGNED(phase, space->cipher.ingress.key_phase.prepared); }); + QUICLY_LOG_CONN(crypto_receive_key_update_prepare, conn, { + PTLS_LOG_ELEMENT_UNSIGNED(phase, space->cipher.ingress.key_phase.prepared); + PTLS_LOG_APPDATA_ELEMENT_HEXDUMP(secret, space->cipher.ingress.secret, cipher->hash->digest_size); + }); } } @@ -4388,6 +4396,7 @@ static int update_traffic_key_cb(ptls_update_traffic_key_t *self, ptls_t *tls, i PTLS_LOG_ELEMENT_BOOL(is_enc, is_enc); PTLS_LOG_ELEMENT_UNSIGNED(epoch, epoch); PTLS_LOG_ELEMENT_SAFESTR(label, log_label); + PTLS_LOG_APPDATA_ELEMENT_HEXDUMP(secret, secret, cipher->hash->digest_size); }); if (tlsctx->log_event != NULL) { @@ -4569,7 +4578,8 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) if (s->dst_end - s->dst >= required_space) { s->dst = quicly_encode_datagram_frame(s->dst, *payload); QUICLY_PROBE(DATAGRAM_SEND, conn, conn->stash.now, payload->base, payload->len); - QUICLY_LOG_CONN(datagram_send, conn, { PTLS_LOG_ELEMENT_UNSIGNED(payload_len, payload->len); }); + QUICLY_LOG_CONN(datagram_send, conn, + { PTLS_LOG_APPDATA_ELEMENT_HEXDUMP(payload, payload->base, payload->len); }); } else { /* FIXME: At the moment, we add a padding because we do not have a way to reclaim allocated space, and because * it is forbidden to send an empty QUIC packet. */ @@ -6035,7 +6045,7 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * QUICLY_PROBE(PACKET_RECEIVED, *conn, (*conn)->stash.now, pn, payload.base, payload.len, get_epoch(packet->octets.base[0])); QUICLY_LOG_CONN(packet_received, *conn, { PTLS_LOG_ELEMENT_UNSIGNED(pn, pn); - PTLS_LOG_ELEMENT_UNSIGNED(decrypted_len, payload.len); + PTLS_LOG_APPDATA_ELEMENT_HEXDUMP(decrypted, payload.base, payload.len); PTLS_LOG_ELEMENT_UNSIGNED(packet_type, get_epoch(packet->octets.base[0])); }); diff --git a/src/cli.c b/src/cli.c index 6152047cd..d3a6d48e3 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1156,6 +1156,7 @@ int main(int argc, char **argv) exit(1); } ptls_log_add_fd(fd); + ptls_log.include_appdata = 1; } break; case 'f': { double fraction; From 2afb5104dab4321bb8398dda111aa223e2f31168 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Thu, 13 Oct 2022 02:44:30 +0000 Subject: [PATCH 283/361] update picotls --- deps/picotls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/picotls b/deps/picotls index 8c633b7c3..d059ccb76 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit 8c633b7c391dd4aab9cd844618c84383546f32ac +Subproject commit d059ccb76059e75109eb358e169cfaa80193937d From ce4aeb7ec7d7c564ecfeb8264fb6e712b4c15673 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Thu, 13 Oct 2022 02:54:29 +0000 Subject: [PATCH 284/361] older cmake (e.g. one installed on Ubuntu 16.04) requires it to be quoted --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fe05fe682..44c2df0ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,7 +120,7 @@ IF (WITH_FUSION) SET(CLI_COMPILE_FLAGS "-mavx2 -maes -mpclmul -mvaes -mvpclmulqdq -DQUICLY_HAVE_FUSION=1 ${CLI_COMPILE_FLAGS}") ENDIF () ADD_EXECUTABLE(cli ${CLI_FILES}) -SET_TARGET_PROPERTIES(cli PROPERTIES COMPILE_FLAGS ${CLI_COMPILE_FLAGS}) +SET_TARGET_PROPERTIES(cli PROPERTIES COMPILE_FLAGS "${CLI_COMPILE_FLAGS}") TARGET_LINK_LIBRARIES(cli ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS} m) ADD_EXECUTABLE(test.t ${PICOTLS_OPENSSL_FILES} ${UNITTEST_SOURCE_FILES}) From e5208a2a8e7f789c5bb6893138cd38318c8e45a0 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Thu, 13 Oct 2022 02:54:29 +0000 Subject: [PATCH 285/361] older cmake (e.g. one installed on Ubuntu 16.04) requires it to be quoted --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ad9e2879..a27657951 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,7 +115,7 @@ IF (WITH_FUSION) SET(CLI_COMPILE_FLAGS "-mavx2 -maes -mpclmul -mvaes -mvpclmulqdq -DQUICLY_HAVE_FUSION=1 ${CLI_COMPILE_FLAGS}") ENDIF () ADD_EXECUTABLE(cli ${CLI_FILES}) -SET_TARGET_PROPERTIES(cli PROPERTIES COMPILE_FLAGS ${CLI_COMPILE_FLAGS}) +SET_TARGET_PROPERTIES(cli PROPERTIES COMPILE_FLAGS "${CLI_COMPILE_FLAGS}") TARGET_LINK_LIBRARIES(cli ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS} m) ADD_EXECUTABLE(test.t ${PICOTLS_OPENSSL_FILES} ${UNITTEST_SOURCE_FILES}) From da099ecbf0c75078285fe334fdb490f55e1d7273 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Mon, 17 Oct 2022 05:18:31 +0000 Subject: [PATCH 286/361] update picotls and use the new API --- deps/picotls | 2 +- include/quicly.h | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/deps/picotls b/deps/picotls index d059ccb76..cea1531ca 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit d059ccb76059e75109eb358e169cfaa80193937d +Subproject commit cea1531caaa4feb6d9a253502f2a50f315f6ee16 diff --git a/include/quicly.h b/include/quicly.h index cd77a0a71..4dde704b4 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -1246,15 +1246,18 @@ extern const quicly_stream_callbacks_t quicly_stream_noop_callbacks; #define QUICLY_LOG_CONN(_type, _conn, _block) \ do { \ + if (!ptls_log.is_active) \ + break; \ quicly_conn_t *_c = (_conn); \ - if (!ptls_skip_tracing(_c->crypto.tls)) \ - PTLS_LOG(quicly, _type, { \ - PTLS_LOG_ELEMENT_PTR(conn, _c); \ - PTLS_LOG_ELEMENT_SIGNED(time, _c->stash.now); \ - do { \ - _block \ - } while (0); \ - }); \ + if (ptls_skip_tracing(_c->crypto.tls)) \ + break; \ + PTLS_LOG__DO_LOG(quicly, _type, { \ + PTLS_LOG_ELEMENT_PTR(conn, _c); \ + PTLS_LOG_ELEMENT_SIGNED(time, _c->stash.now); \ + do { \ + _block \ + } while (0); \ + }); \ } while (0) /* inline definitions */ From b6233bee49847ccaa303571959b8a20f99df3607 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Tue, 18 Oct 2022 02:56:32 +0000 Subject: [PATCH 287/361] use c++(1) instead of g++(1) since g++ is not installed --- t/cplusplus.t | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/cplusplus.t b/t/cplusplus.t index ad6085312..a195da79d 100755 --- a/t/cplusplus.t +++ b/t/cplusplus.t @@ -4,9 +4,9 @@ use strict; use warnings; use Test::More; -plan skip_all => "g++ not found" - unless system("which g++ > /dev/null 2>&1") == 0; +plan skip_all => "c++ not found" + unless system("which c++ > /dev/null 2>&1") == 0; -is system(qw(g++ -Iinclude -Ideps/picotls/include --include quicly.h -c -x c++ -Wall /dev/null)), 0; +is system(qw(c++ -Iinclude -Ideps/picotls/include --include quicly.h -c -x c++ -Wall /dev/null)), 0; done_testing; From 18c814caaa2b21fc2dae5ffc0c8088811cdc7af2 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 18 Oct 2022 16:39:14 +0900 Subject: [PATCH 288/361] update picotls --- deps/picotls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/picotls b/deps/picotls index cea1531ca..14c40d875 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit cea1531caaa4feb6d9a253502f2a50f315f6ee16 +Subproject commit 14c40d8751014a1b124318f72687c76d552ebe7a From 115499ef44d5810a517c7d708e0419e32af6d02a Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 7 Dec 2022 16:00:25 +0900 Subject: [PATCH 289/361] follow the changes due to addition of ECH --- CMakeLists.txt | 1 + deps/picotls | 2 +- quicly.xcodeproj/project.pbxproj | 10 ++++++++++ t/test.c | 2 +- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a27657951..3fab895d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,7 @@ INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR}) SET(PICOTLS_OPENSSL_FILES + deps/picotls/lib/hpke.c deps/picotls/lib/openssl.c deps/picotls/lib/pembase64.c deps/picotls/lib/picotls.c) diff --git a/deps/picotls b/deps/picotls index 14c40d875..4fe18f3da 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit 14c40d8751014a1b124318f72687c76d552ebe7a +Subproject commit 4fe18f3da54cde9200838f2664649c0dc148fde9 diff --git a/quicly.xcodeproj/project.pbxproj b/quicly.xcodeproj/project.pbxproj index a58df4c93..5ebfc50d7 100644 --- a/quicly.xcodeproj/project.pbxproj +++ b/quicly.xcodeproj/project.pbxproj @@ -37,6 +37,10 @@ 0829879226E0A9DF0053638F /* rate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0829879126E0A9DF0053638F /* rate.c */; }; 085125F828F51BA20074C124 /* quicly-probes.d in Sources */ = {isa = PBXBuildFile; fileRef = E95EBCCD227EC13F0022C32D /* quicly-probes.d */; }; 086001CB273271E80043886F /* rate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0829878D26E03D4D0053638F /* rate.c */; }; + 08B3297A29407097009D6766 /* hpke.c in Sources */ = {isa = PBXBuildFile; fileRef = 08B3297929407096009D6766 /* hpke.c */; }; + 08B3297B29407097009D6766 /* hpke.c in Sources */ = {isa = PBXBuildFile; fileRef = 08B3297929407096009D6766 /* hpke.c */; }; + 08B3297C29407097009D6766 /* hpke.c in Sources */ = {isa = PBXBuildFile; fileRef = 08B3297929407096009D6766 /* hpke.c */; }; + 08B3297D29407097009D6766 /* hpke.c in Sources */ = {isa = PBXBuildFile; fileRef = 08B3297929407096009D6766 /* hpke.c */; }; E904233D24AED0410072C5B7 /* loss.c in Sources */ = {isa = PBXBuildFile; fileRef = E904233C24AED0410072C5B7 /* loss.c */; }; E904233E24AED0410072C5B7 /* loss.c in Sources */ = {isa = PBXBuildFile; fileRef = E904233C24AED0410072C5B7 /* loss.c */; }; E904233F24AED0410072C5B7 /* loss.c in Sources */ = {isa = PBXBuildFile; fileRef = E904233C24AED0410072C5B7 /* loss.c */; }; @@ -187,6 +191,7 @@ 0829878D26E03D4D0053638F /* rate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = rate.c; sourceTree = ""; }; 0829879126E0A9DF0053638F /* rate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = rate.c; sourceTree = ""; }; 085125F728EFC0480074C124 /* cplusplus.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = cplusplus.t; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.perl; }; + 08B3297929407096009D6766 /* hpke.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hpke.c; sourceTree = ""; }; E904233C24AED0410072C5B7 /* loss.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = loss.c; sourceTree = ""; }; E904234024AEFB980072C5B7 /* loss.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = loss.c; sourceTree = ""; }; E9056C071F56965300E2B96C /* linklist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = linklist.h; sourceTree = ""; }; @@ -439,6 +444,7 @@ isa = PBXGroup; children = ( E9B43E11246943D300824E51 /* fusion.c */, + 08B3297929407096009D6766 /* hpke.c */, E98448271EA48D0000390927 /* openssl.c */, E93E54681F663849001C50FE /* pembase64.c */, E98448281EA48D0000390927 /* picotls.c */, @@ -769,6 +775,7 @@ 0829878326D37E370053638F /* simulator.c in Sources */, 0829877126D372B70053638F /* frame.c in Sources */, 0829877226D372B70053638F /* recvstate.c in Sources */, + 08B3297D29407097009D6766 /* hpke.c in Sources */, 0829877326D372B70053638F /* fusion.c in Sources */, 0829877426D372B70053638F /* defaults.c in Sources */, 086001CB273271E80043886F /* rate.c in Sources */, @@ -790,6 +797,7 @@ E980421F223952FD008B9745 /* pembase64.c in Sources */, E98042292239533A008B9745 /* echo.c in Sources */, E9804220223952FD008B9745 /* picotls.c in Sources */, + 08B3297C29407097009D6766 /* hpke.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -844,6 +852,7 @@ E941429323B0B879002D3CE0 /* sentmap.c in Sources */, E984483C1EA48DD300390927 /* picotls.c in Sources */, 085125F828F51BA20074C124 /* quicly-probes.d in Sources */, + 08B3297A29407097009D6766 /* hpke.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -889,6 +898,7 @@ E9CC441C1EC195DF00DC7D3E /* picotls.c in Sources */, E904233F24AED0410072C5B7 /* loss.c in Sources */, E9DF012624E4BACA0002EEC7 /* cc-cubic.c in Sources */, + 08B3297B29407097009D6766 /* hpke.c in Sources */, E98042372244A5D7008B9745 /* defaults.c in Sources */, E99F8C271F4E9F5D00C26B3D /* frame.c in Sources */, E9736536246FD3DA0039AA49 /* local_cid.c in Sources */, diff --git a/t/test.c b/t/test.c index 9340665a5..ac249b35a 100644 --- a/t/test.c +++ b/t/test.c @@ -708,7 +708,7 @@ int main(int argc, char **argv) ptls_openssl_key_exchanges, ptls_openssl_cipher_suites, {&cert, 1}, - NULL, + {{NULL}}, NULL, NULL, &cert_signer.super, From 91189a06d9c9cca5e74025b1852c7c3882096baa Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 7 Dec 2022 21:00:39 +0900 Subject: [PATCH 290/361] add support for async signature generation --- include/quicly.h | 13 +++++ lib/quicly.c | 122 ++++++++++++++++++++++++++++++++--------------- 2 files changed, 97 insertions(+), 38 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index 4dde704b4..aefa242d8 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -161,6 +161,11 @@ QUICLY_CALLBACK_TYPE(void, init_cc, quicly_cc_t *cc, uint32_t initcwnd, int64_t * delta must be either 1 or -1. */ QUICLY_CALLBACK_TYPE(void, update_open_count, ssize_t delta); +/** + * Called when picotls return PTLS_ERROR_ASYNC_OPERATION. The application must call `ptls_resume_handshake` once the async operation + * is complete. + */ +QUICLY_CALLBACK_TYPE(void, async_handshake, ptls_t *tls); /** * crypto offload API @@ -369,6 +374,10 @@ struct st_quicly_context_t { * optional refcount callback */ quicly_update_open_count_t *update_open_count; + /** + * + */ + quicly_async_handshake_t *async_handshake; }; /** @@ -1087,6 +1096,10 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * * */ ptls_t *quicly_get_tls(quicly_conn_t *conn); +/** + * resumes an async TLS handshake; see `quicly_async_handshake_t` + */ +void quicly_resume_handshake(ptls_t *tls); /** * */ diff --git a/lib/quicly.c b/lib/quicly.c index 04a75b8e3..63a3968d3 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -362,6 +362,7 @@ struct st_quicly_conn_t { ptls_raw_extension_t ext[3]; ptls_buffer_t buf; } transport_params; + unsigned async_in_progress : 1; } crypto; /** * token (if the token is a Retry token can be determined by consulting the length of retry_scid) @@ -961,58 +962,98 @@ static int write_crypto_data(quicly_conn_t *conn, ptls_buffer_t *tlsbuf, size_t return 0; } -void crypto_stream_receive(quicly_stream_t *stream, size_t off, const void *src, size_t len) +static void crypto_handshake(quicly_conn_t *conn, size_t in_epoch, ptls_iovec_t input) { - quicly_conn_t *conn = stream->conn; - size_t in_epoch = -(1 + stream->stream_id), epoch_offsets[5] = {0}; - ptls_iovec_t input; ptls_buffer_t output; + size_t epoch_offsets[5] = {0}; - if (quicly_streambuf_ingress_receive(stream, off, src, len) != 0) - return; + assert(!conn->crypto.async_in_progress); ptls_buffer_init(&output, "", 0); - /* send handshake messages to picotls, and let it fill in the response */ - while ((input = quicly_streambuf_ingress_get(stream)).len != 0) { - int handshake_result = ptls_handle_message(conn->crypto.tls, &output, epoch_offsets, in_epoch, input.base, input.len, - &conn->crypto.handshake_properties); - quicly_streambuf_ingress_shift(stream, input.len); - QUICLY_PROBE(CRYPTO_HANDSHAKE, conn, conn->stash.now, handshake_result); - QUICLY_LOG_CONN(crypto_handshake, conn, { PTLS_LOG_ELEMENT_SIGNED(ret, handshake_result); }); - switch (handshake_result) { - case 0: - case PTLS_ERROR_IN_PROGRESS: - break; - default: - initiate_close(conn, - PTLS_ERROR_GET_CLASS(handshake_result) == PTLS_ERROR_CLASS_SELF_ALERT ? handshake_result - : QUICLY_TRANSPORT_ERROR_INTERNAL, - QUICLY_FRAME_TYPE_CRYPTO, NULL); - goto Exit; - } - /* drop 0-RTT write key if 0-RTT is rejected by remote peer */ - if (conn->application != NULL && !conn->application->one_rtt_writable && - conn->application->cipher.egress.key.aead != NULL) { - assert(quicly_is_client(conn)); - if (conn->crypto.handshake_properties.client.early_data_acceptance == PTLS_EARLY_DATA_REJECTED) { - dispose_cipher(&conn->application->cipher.egress.key); - conn->application->cipher.egress.key = (struct st_quicly_cipher_context_t){NULL}; - /* retire all packets with ack_epoch == 3; they are all 0-RTT packets */ - int ret; - if ((ret = discard_sentmap_by_epoch(conn, 1u << QUICLY_EPOCH_1RTT)) != 0) { - initiate_close(conn, ret, QUICLY_FRAME_TYPE_CRYPTO, NULL); - goto Exit; - } + int handshake_result = ptls_handle_message(conn->crypto.tls, &output, epoch_offsets, in_epoch, input.base, input.len, + &conn->crypto.handshake_properties); + QUICLY_PROBE(CRYPTO_HANDSHAKE, conn, conn->stash.now, handshake_result); + QUICLY_LOG_CONN(crypto_handshake, conn, { PTLS_LOG_ELEMENT_SIGNED(ret, handshake_result); }); + switch (handshake_result) { + case 0: + case PTLS_ERROR_IN_PROGRESS: + break; + case PTLS_ERROR_ASYNC_OPERATION: + assert(conn->super.ctx->async_handshake != NULL && + "async handshake is used but the quicly_context_t::async_handshake is NULL"); + conn->crypto.async_in_progress = 1; + conn->super.ctx->async_handshake->cb(conn->super.ctx->async_handshake, conn->crypto.tls); + break; + default: + initiate_close(conn, + PTLS_ERROR_GET_CLASS(handshake_result) == PTLS_ERROR_CLASS_SELF_ALERT ? handshake_result + : QUICLY_TRANSPORT_ERROR_INTERNAL, + QUICLY_FRAME_TYPE_CRYPTO, NULL); + goto Exit; + } + /* drop 0-RTT write key if 0-RTT is rejected by remote peer */ + if (conn->application != NULL && !conn->application->one_rtt_writable && + conn->application->cipher.egress.key.aead != NULL) { + assert(quicly_is_client(conn)); + if (conn->crypto.handshake_properties.client.early_data_acceptance == PTLS_EARLY_DATA_REJECTED) { + dispose_cipher(&conn->application->cipher.egress.key); + conn->application->cipher.egress.key = (struct st_quicly_cipher_context_t){NULL}; + /* retire all packets with ack_epoch == 3; they are all 0-RTT packets */ + int ret; + if ((ret = discard_sentmap_by_epoch(conn, 1u << QUICLY_EPOCH_1RTT)) != 0) { + initiate_close(conn, ret, QUICLY_FRAME_TYPE_CRYPTO, NULL); + goto Exit; } } } + write_crypto_data(conn, &output, epoch_offsets); Exit: ptls_buffer_dispose(&output); } +void crypto_stream_receive(quicly_stream_t *stream, size_t off, const void *src, size_t len) +{ + quicly_conn_t *conn = stream->conn; + ptls_iovec_t input; + + /* store input */ + if (quicly_streambuf_ingress_receive(stream, off, src, len) != 0) + return; + + /* When async operation is in progress, input must be buffered and be provided to TLS after the async operation is complete. */ + if (conn->crypto.async_in_progress) + return; + + /* feed the input into TLS, send result */ + if ((input = quicly_streambuf_ingress_get(stream)).len != 0) { + size_t in_epoch = -(1 + stream->stream_id); + crypto_handshake(conn, in_epoch, input); + quicly_streambuf_ingress_shift(stream, input.len); + } +} + +void quicly_resume_handshake(ptls_t *tls) +{ + quicly_conn_t *conn; + + if ((conn = *ptls_get_data_ptr(tls)) == NULL) { + /* QUIC connection has been closed while TLS async operation was inflight. */ + ptls_free(tls); + return; + } + + assert(conn->crypto.async_in_progress); + conn->crypto.async_in_progress = 0; + + if (conn->super.state >= QUICLY_STATE_CLOSING) + return; + + crypto_handshake(conn, 0, ptls_iovec_init(NULL, 0)); +} + static void init_stream_properties(quicly_stream_t *stream, uint32_t initial_max_stream_data_local, uint64_t initial_max_stream_data_remote) { @@ -1632,7 +1673,12 @@ void quicly_free(quicly_conn_t *conn) free_application_space(&conn->application); ptls_buffer_dispose(&conn->crypto.transport_params.buf); - ptls_free(conn->crypto.tls); + if (conn->crypto.async_in_progress) { + /* When async signature generation is inflight, `ptls_free` will be called from `quicly_resume_handshake` laterwards. */ + *ptls_get_data_ptr(conn->crypto.tls) = NULL; + } else { + ptls_free(conn->crypto.tls); + } unlock_now(conn); From 22b26a015ec9b107c035e4d2aaa9c7e3a300e36d Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 7 Dec 2022 21:05:03 +0900 Subject: [PATCH 291/361] be strict to avoid the fuss of handling buffered input when the async operation completes --- lib/quicly.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 63a3968d3..adfae4144 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1023,9 +1023,12 @@ void crypto_stream_receive(quicly_stream_t *stream, size_t off, const void *src, if (quicly_streambuf_ingress_receive(stream, off, src, len) != 0) return; - /* When async operation is in progress, input must be buffered and be provided to TLS after the async operation is complete. */ - if (conn->crypto.async_in_progress) + /* While the server generates the handshake signature asynchronously, clients would not send additional messages. They cannot + * generate Finished. They would not send Certificate / CertificateVerify before authenticating the server identity. */ + if (conn->crypto.async_in_progress) { + initiate_close(conn, PTLS_ALERT_UNEXPECTED_MESSAGE, QUICLY_FRAME_TYPE_CRYPTO, NULL); return; + } /* feed the input into TLS, send result */ if ((input = quicly_streambuf_ingress_get(stream)).len != 0) { From ef639f30c0073484f74d4901bbdfabe382a51d7c Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 8 Dec 2022 09:56:38 +0900 Subject: [PATCH 292/361] return `quicly_conn_t *` so that the application can schedule packet emission --- include/quicly.h | 5 +++-- lib/quicly.c | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index aefa242d8..e800e6df7 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -1097,9 +1097,10 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * */ ptls_t *quicly_get_tls(quicly_conn_t *conn); /** - * resumes an async TLS handshake; see `quicly_async_handshake_t` + * Resumes an async TLS handshake, and returns a pointer to the QUIC connection or NULL if the corresponding QUIC connection has + * been discarded. See `quicly_async_handshake_t`. */ -void quicly_resume_handshake(ptls_t *tls); +quicly_conn_t *quicly_resume_handshake(ptls_t *tls); /** * */ diff --git a/lib/quicly.c b/lib/quicly.c index adfae4144..b6280424b 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1038,23 +1038,24 @@ void crypto_stream_receive(quicly_stream_t *stream, size_t off, const void *src, } } -void quicly_resume_handshake(ptls_t *tls) +quicly_conn_t *quicly_resume_handshake(ptls_t *tls) { quicly_conn_t *conn; if ((conn = *ptls_get_data_ptr(tls)) == NULL) { /* QUIC connection has been closed while TLS async operation was inflight. */ ptls_free(tls); - return; + return NULL; } assert(conn->crypto.async_in_progress); conn->crypto.async_in_progress = 0; if (conn->super.state >= QUICLY_STATE_CLOSING) - return; + return conn; crypto_handshake(conn, 0, ptls_iovec_init(NULL, 0)); + return conn; } static void init_stream_properties(quicly_stream_t *stream, uint32_t initial_max_stream_data_local, From 1f2c6c6b31f9a70be1f5f63bd2ea7eacb7e043ce Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 9 Dec 2022 16:35:42 +0900 Subject: [PATCH 293/361] [cli] add support for ECH --- deps/picotls | 2 +- src/cli.c | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/deps/picotls b/deps/picotls index 4fe18f3da..4e57e9b09 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit 4fe18f3da54cde9200838f2664649c0dc148fde9 +Subproject commit 4e57e9b09ebac4da4c28433e20e5a88ffa972a08 diff --git a/src/cli.c b/src/cli.c index d3a6d48e3..27f9a58ab 100644 --- a/src/cli.c +++ b/src/cli.c @@ -91,6 +91,7 @@ static ptls_context_t tlsctx = {.random_bytes = ptls_openssl_random_bytes, .get_time = &ptls_get_time, .key_exchanges = key_exchanges, .cipher_suites = cipher_suites, + .ech.client = {ptls_openssl_hpke_cipher_suites, ptls_openssl_hpke_kems}, .require_dhe_on_psk = 1, .save_ticket = &save_session_ticket, .on_client_hello = &on_client_hello}; @@ -608,6 +609,7 @@ static int run_client(int fd, struct sockaddr *sa, const char *host) if (conn != NULL) { ret = send_pending(fd, conn); if (ret != 0) { + ech_save_retry_configs(); quicly_free(conn); conn = NULL; if (ret == QUICLY_ERROR_FREE_CONNECTION) { @@ -1073,7 +1075,7 @@ int main(int argc, char **argv) struct sockaddr_storage sa; socklen_t salen; unsigned udpbufsize = 0; - int ch, fd; + int ch, opt_index, fd; reqs = malloc(sizeof(*reqs)); memset(reqs, 0, sizeof(*reqs)); @@ -1094,8 +1096,20 @@ int main(int argc, char **argv) address_token_aead.dec = ptls_aead_new(&ptls_openssl_aes128gcm, &ptls_openssl_sha256, 0, secret, ""); } - while ((ch = getopt(argc, argv, "a:b:B:c:C:Dd:k:Ee:f:Gi:I:K:l:M:m:NnOp:P:Rr:S:s:u:U:Vvw:W:x:X:y:h")) != -1) { + static const struct option longopts[] = { + {"ech-key", required_argument, NULL, 0}, {"ech-configs", required_argument, NULL, 0}, {NULL}}; + while ((ch = getopt_long(argc, argv, "a:b:B:c:C:Dd:k:Ee:f:Gi:I:K:l:M:m:NnOp:P:Rr:S:s:u:U:Vvw:W:x:X:y:h", longopts, + &opt_index)) != -1) { switch (ch) { + case 0: /* longopts */ + if (strcmp(longopts[opt_index].name, "ech-key") == 0) { + ech_setup_key(&tlsctx, optarg); + } else if (strcmp(longopts[opt_index].name, "ech-configs") == 0) { + ech_setup_configs(optarg); + } else { + assert(!"unexpected longname"); + } + break; case 'a': assert(negotiated_protocols.count < PTLS_ELEMENTSOF(negotiated_protocols.list)); negotiated_protocols.list[negotiated_protocols.count++] = ptls_iovec_init(optarg, strlen(optarg)); @@ -1401,6 +1415,8 @@ int main(int argc, char **argv) hs_properties.client.negotiated_protocols.count = negotiated_protocols.count; if (session_file != NULL) load_session(); + hs_properties.client.ech.configs = ech.config_list; + hs_properties.client.ech.retry_configs = &ech.retry.configs; } if (argc != 2) { fprintf(stderr, "missing host and port\n"); From 6385851f33500ea6926b0c36c3842246138ee60a Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 9 Dec 2022 17:35:50 +0900 Subject: [PATCH 294/361] update help --- src/cli.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cli.c b/src/cli.c index 27f9a58ab..bac223718 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1022,6 +1022,11 @@ static void usage(const char *cmd) " 29)\n" " -e event-log-file file to log events\n" " -E expand Client Hello (sends multiple client Initials)\n" + " --ech-config file that contains ECHConfigList or an empty file to\n" + " grease ECH; will be overwritten when receiving\n" + " retry_configs from the server\n" + " --ech-key ECH private key for each ECH config provided by\n" + " --ech-config\n" " -f fraction increases the induced ack frequency to specified\n" " fraction of CWND (default: 0)\n" " -G enable UDP generic segmentation offload\n" From b8f189fa48dddd783a72cb503e61d292ad7a2060 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:11 -0500 Subject: [PATCH 295/361] spelling: acquiring Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- src/cli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli.c b/src/cli.c index bac223718..a480209bf 100644 --- a/src/cli.c +++ b/src/cli.c @@ -808,7 +808,7 @@ static int run_server(int fd, struct sockaddr *sa, socklen_t salen) } else if (enforce_retry && (ret == QUICLY_TRANSPORT_ERROR_INVALID_TOKEN || (ret == 0 && token_buf.type == QUICLY_ADDRESS_TOKEN_TYPE_RETRY))) { /* Token that looks like retry was unusable, and we require retry. There's no chance of the - * handshake succeeding. Therefore, send close without aquiring state. */ + * handshake succeeding. Therefore, send close without acquiring state. */ uint8_t payload[ctx.transport_params.max_udp_payload_size]; size_t payload_len = quicly_send_close_invalid_token(&ctx, packet.version, packet.cid.src, packet.cid.dest.encrypted, err_desc, payload); From 23d04fbc2679a0fbb23370186cbf08b356be21b8 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:10 -0500 Subject: [PATCH 296/361] spelling: adapter Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- misc/quictrace-adapter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/quictrace-adapter.py b/misc/quictrace-adapter.py index 9b40a6f00..7c7954b3e 100755 --- a/misc/quictrace-adapter.py +++ b/misc/quictrace-adapter.py @@ -12,7 +12,7 @@ def usage(): print(r""" Usage: quictrace-adapter.py inTrace.jsonl outTrace.json cid - quictrace-adatper.py inTrace.jsonl outTraceDir + quictrace-adapter.py inTrace.jsonl outTraceDir """.strip()) From 65c67f613b8e1aaadfab94ba2dd7f3f0448f89e8 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:10 -0500 Subject: [PATCH 297/361] spelling: alternative Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index b6280424b..f3c000744 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3674,7 +3674,7 @@ int quicly_can_send_data(quicly_conn_t *conn, quicly_send_context_t *s) } /** - * If necessary, changes the frame representation from one without length field to one that has if necessary. Or, as an alternaive, + * If necessary, changes the frame representation from one without length field to one that has if necessary. Or, as an alternative, * prepends PADDING frames. Upon return, `dst` points to the end of the frame being built. `*len`, `*wrote_all`, `*frame_type_at` * are also updated reflecting their values post-adjustment. */ From c47a9fc9d72ccc0e419848d687dcfc8506c5d5be Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:11 -0500 Subject: [PATCH 298/361] spelling: available Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- include/quicly/loss.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/quicly/loss.h b/include/quicly/loss.h index cbc307a5c..adf79f82c 100644 --- a/include/quicly/loss.h +++ b/include/quicly/loss.h @@ -72,7 +72,7 @@ typedef struct quicly_loss_conf_t { /** * Holds RTT variables. We use this structure differently from the specification: * * if the first sample has been obtained should be checked by doing: `latest != 0` - * * smoothed and variance are avaiable even before the first RTT sample is obtained + * * smoothed and variance are available even before the first RTT sample is obtained */ typedef struct quicly_rtt_t { /** From 1c9eb57dc7654bfc9d57015fe0f9805d100fb962 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:52:46 -0500 Subject: [PATCH 299/361] spelling: datagram Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- src/cli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli.c b/src/cli.c index a480209bf..4cb85c3d3 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1047,7 +1047,7 @@ static void usage(const char *cmd) " -S [num-speculative-ptos] number of speculative PTOs\n" " -s session-file file to load / store the session ticket\n" " -u size initial size of UDP datagram payload\n" - " -U size maximum size of UDP datagarm payload\n" + " -U size maximum size of UDP datagram payload\n" " -V verify peer using the default certificates\n" " -v verbose mode (-vv emits packet dumps as well)\n" " -w packets initial congestion window (default: 10)\n" From 9865ff12487df1d45abfa0d0aa312f63c6a3696a Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:12 -0500 Subject: [PATCH 300/361] spelling: deactivate Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- lib/defaults.c | 2 +- lib/quicly.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/defaults.c b/lib/defaults.c index 1d0691251..5599f9934 100644 --- a/lib/defaults.c +++ b/lib/defaults.c @@ -341,7 +341,7 @@ static int default_stream_scheduler_update_state(quicly_stream_scheduler_t *self /* activate if not */ link_stream(sched, stream, quicly_is_blocked(stream->conn)); } else { - /* disactivate if active */ + /* deactivate if active */ if (quicly_linklist_is_linked(&stream->_send_aux.pending_link.default_scheduler)) quicly_linklist_unlink(&stream->_send_aux.pending_link.default_scheduler); } diff --git a/lib/quicly.c b/lib/quicly.c index f3c000744..22b987655 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3028,7 +3028,7 @@ static size_t calc_send_window(quicly_conn_t *conn, size_t min_bytes_to_send, ui } /** - * Checks if the server is waiting for ClientFinished. When that is the case, the loss timer is disactivated, to avoid repeatedly + * Checks if the server is waiting for ClientFinished. When that is the case, the loss timer is deactivated, to avoid repeatedly * sending 1-RTT packets while the client spends time verifying the certificate chain at the same time buffering 1-RTT packets. */ static int is_point5rtt_with_no_handshake_data_to_send(quicly_conn_t *conn) From 85fd84c28a8f633385a2344421f160519f2a3eef Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:13 -0500 Subject: [PATCH 301/361] spelling: equivalent Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- include/quicly.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/quicly.h b/include/quicly.h index e800e6df7..2a60a9c4e 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -560,7 +560,7 @@ struct _st_quicly_conn_public_t { */ quicly_address_t address; /** - * the SCID used in long header packets. Equiavalent to local_cid[seq=0]. Retaining the value separately is the easiest way + * the SCID used in long header packets. Equivalent to local_cid[seq=0]. Retaining the value separately is the easiest way * of staying away from the complexity caused by remote peer sending RCID frames before the handshake concludes. */ quicly_cid_t long_header_src_cid; From ba1bb12f90148425a36a18d8a3b72e3ab84f99fa Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:13 -0500 Subject: [PATCH 302/361] spelling: granularity Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 22b987655..5da5dcf29 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3433,7 +3433,7 @@ static int send_ack(quicly_conn_t *conn, struct st_quicly_pn_space_t *space, qui /* calc ack_delay */ if (space->largest_pn_received_at < conn->stash.now) { /* We underreport ack_delay up to 1 milliseconds assuming that QUICLY_LOCAL_ACK_DELAY_EXPONENT is 10. It's considered a - * non-issue because our time measurement is at millisecond granurality anyways. */ + * non-issue because our time measurement is at millisecond granularity anyways. */ ack_delay = ((conn->stash.now - space->largest_pn_received_at) * 1000) >> QUICLY_LOCAL_ACK_DELAY_EXPONENT; } else { ack_delay = 0; From e21dda4a7b585a5177fefb5b8289685d7a6ee1a2 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:14 -0500 Subject: [PATCH 303/361] spelling: guaranteed Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 5da5dcf29..fed0438e2 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -2254,7 +2254,7 @@ static int client_collected_extensions(ptls_t *tls, ptls_handshake_properties_t quicly_transport_parameters_t params; quicly_cid_t original_dcid, initial_scid, retry_scid = {}; - /* obtain pointer to initial CID of the peer. It is guaranteeed to exist in the first slot, as TP is received before any frame + /* obtain pointer to initial CID of the peer. It is guaranteed to exist in the first slot, as TP is received before any frame * that updates the CID set. */ quicly_remote_cid_t *remote_cid = &conn->super.remote.cid_set.cids[0]; assert(remote_cid->sequence == 0); From 3b4e1adb5d7c99460298ed3199ac7f63aa094257 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:14 -0500 Subject: [PATCH 304/361] spelling: happens Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- lib/defaults.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/defaults.c b/lib/defaults.c index 5599f9934..4a3aeded2 100644 --- a/lib/defaults.c +++ b/lib/defaults.c @@ -313,7 +313,7 @@ static int default_stream_scheduler_do_send(quicly_stream_scheduler_t *self, qui } /* send! */ if ((ret = quicly_send_stream(stream, s)) != 0) { - /* FIXME Stop quicly_send_stream emitting SENDBUF_FULL (happpens when CWND is congested). Otherwise, we need to make + /* FIXME Stop quicly_send_stream emitting SENDBUF_FULL (happens when CWND is congested). Otherwise, we need to make * adjustments to the scheduler after popping a stream */ if (ret == QUICLY_ERROR_SENDBUF_FULL) { assert(quicly_stream_can_send(stream, 1)); From e379e3cae91bca7127cd77f293599719f3071836 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:15 -0500 Subject: [PATCH 305/361] spelling: immediately Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- include/quicly/loss.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/quicly/loss.h b/include/quicly/loss.h index adf79f82c..6beec6c8b 100644 --- a/include/quicly/loss.h +++ b/include/quicly/loss.h @@ -180,7 +180,7 @@ static void quicly_loss_on_ack_received(quicly_loss_t *r, uint64_t largest_newly uint64_t ack_delay_encoded, quicly_loss_ack_received_kind_t kind); /* This function updates the loss detection timer and indicates to the caller how many packets should be sent. * After calling this function, app should: - * * send min_packets_to_send number of packets immmediately. min_packets_to_send should never be 0. + * * send min_packets_to_send number of packets immediately. min_packets_to_send should never be 0. * * if restrict_sending is true, limit sending to min_packets_to_send, otherwise as limited by congestion/flow control * and then call quicly_loss_update_alarm and update the alarm */ From f20e28f0dbf39c35a5c008ee4cb58a116993bcf0 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:15 -0500 Subject: [PATCH 306/361] spelling: initializes Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- include/quicly/streambuf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/quicly/streambuf.h b/include/quicly/streambuf.h index e7aa60293..40313972f 100644 --- a/include/quicly/streambuf.h +++ b/include/quicly/streambuf.h @@ -72,7 +72,7 @@ typedef struct st_quicly_sendbuf_t { } quicly_sendbuf_t; /** - * Inilializes the send buffer. + * Initializes the send buffer. */ static void quicly_sendbuf_init(quicly_sendbuf_t *sb); /** From a8bf7242aee44432e9293a7ac798e9dba05abc43 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:16 -0500 Subject: [PATCH 307/361] spelling: instantiating Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index fed0438e2..4d982cf47 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1473,7 +1473,7 @@ static int setup_cipher(quicly_conn_t *conn, size_t epoch, int is_enc, ptls_ciph ptls_aead_context_t **aead_ctx, ptls_aead_algorithm_t *aead, ptls_hash_algorithm_t *hash, const void *secret) { - /* quicly_accept builds cipher before instantitating a connection. In such case, we use the default crypto engine */ + /* quicly_accept builds cipher before instantiating a connection. In such case, we use the default crypto engine */ quicly_crypto_engine_t *engine = conn != NULL ? conn->super.ctx->crypto_engine : &quicly_default_crypto_engine; return engine->setup_cipher(engine, conn, epoch, is_enc, hp_ctx, aead_ctx, aead, hash, secret); From 98af7ba6e3a4f33f576de851c4bfe93eb323f55e Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:16 -0500 Subject: [PATCH 308/361] spelling: length Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 4d982cf47..6d1720fa9 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3691,7 +3691,7 @@ static inline void adjust_stream_frame_layout(uint8_t **dst, uint8_t *const dst_ } } else { /* STREAM frame: insert length if space can be left for more frames. Otherwise, retain STREAM frame header omitting the - * lengh field, prepending PADDING if necessary. */ + * length field, prepending PADDING if necessary. */ if (space_left <= len_of_len) { if (space_left != 0) { memmove(*frame_at + space_left, *frame_at, *dst + *len - *frame_at); From 924b388d125cb08eb32fbda41b693e9bae8864d2 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:17 -0500 Subject: [PATCH 309/361] spelling: necessary Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 6d1720fa9..29265bdcc 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3537,7 +3537,7 @@ static int send_control_frames_of_stream(quicly_stream_t *stream, quicly_send_co { int ret; - /* send STOP_SENDING if necessray */ + /* send STOP_SENDING if necessary */ if (stream->_send_aux.stop_sending.sender_state == QUICLY_SENDER_STATE_SEND) { /* FIXME also send an empty STREAM frame */ if ((ret = prepare_stream_state_sender(stream, &stream->_send_aux.stop_sending.sender_state, s, From 406c3d6a11d49bb8e35decd3b95bc31e9ccdec6b Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:17 -0500 Subject: [PATCH 310/361] spelling: number Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- lib/sendstate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sendstate.c b/lib/sendstate.c index 96cde7696..d9ee1e777 100644 --- a/lib/sendstate.c +++ b/lib/sendstate.c @@ -90,7 +90,7 @@ void quicly_sendstate_reset(quicly_sendstate_t *state) state->final_size = state->size_inflight; ret = quicly_ranges_add(&state->acked, 0, state->final_size + 1); - assert(ret == 0 && "guaranteed to succeed, because the numebr of ranges never increases"); + assert(ret == 0 && "guaranteed to succeed, because the number of ranges never increases"); quicly_ranges_clear(&state->pending); } From a31e13ead9d30c1335c30f2cb4bde8fbb055b031 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:18 -0500 Subject: [PATCH 311/361] spelling: outstanding Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- include/quicly/loss.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/quicly/loss.h b/include/quicly/loss.h index 6beec6c8b..de6d15a5f 100644 --- a/include/quicly/loss.h +++ b/include/quicly/loss.h @@ -271,7 +271,7 @@ inline void quicly_loss_update_alarm(quicly_loss_t *r, int64_t now, int64_t last int is_after_send) { if (!has_outstanding) { - /* Do not set alarm if there's no data oustanding */ + /* Do not set alarm if there's no data outstanding */ r->alarm_at = INT64_MAX; r->loss_time = INT64_MAX; return; From 7339aad3d69d2e345d48f4ea40388b893e02641e Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:18 -0500 Subject: [PATCH 312/361] spelling: proportional Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- include/quicly.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/quicly.h b/include/quicly.h index 2a60a9c4e..095e8dedf 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -747,7 +747,7 @@ struct st_quicly_stream_t { uint32_t window; /** * Maximum number of ranges (i.e. gaps + 1) permitted in `recvstate.ranges`. - * As discussed in https://github.com/h2o/quicly/issues/278, this value should be propotional to the size of the receive + * As discussed in https://github.com/h2o/quicly/issues/278, this value should be proportional to the size of the receive * window, so that the receive window can be maintained even in the worst case, where every one of the two packets being * sent are received. */ From 9eb661be24d3c06f9a21efdb6f8bd64f2febc4f0 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:19 -0500 Subject: [PATCH 313/361] spelling: receive Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- include/quicly.h | 2 +- t/simple.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index 095e8dedf..43e1d17a4 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -958,7 +958,7 @@ static quicly_tracer_t *quicly_get_tracer(quicly_conn_t *conn); void quicly_free(quicly_conn_t *conn); /** * closes the connection. `err` is the application error code using the coalesced scheme (see QUICLY_ERROR_* macros), or zero (no - * error; indicating idle close). An application should continue calling quicly_recieve and quicly_send, until they return + * error; indicating idle close). An application should continue calling quicly_receive and quicly_send, until they return * QUICLY_ERROR_FREE_CONNECTION. At this point, it is should call quicly_free. */ int quicly_close(quicly_conn_t *conn, int err, const char *reason_phrase); diff --git a/t/simple.c b/t/simple.c index 6f69fd0a8..4f2c7927d 100644 --- a/t/simple.c +++ b/t/simple.c @@ -362,7 +362,7 @@ static void tiny_stream_window(void) quic_now += QUICLY_DELAYED_ACK_TIMEOUT; transmit(client, server); - /* server should have recieved ACK to the RESET_STREAM it has sent */ + /* server should have received ACK to the RESET_STREAM it has sent */ ok(server_streambuf->is_detached); ok(quicly_num_streams(server) == 0); From d1794a80c613567d8f3cf02e9d17a5cb20eb84e6 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:55:08 -0500 Subject: [PATCH 314/361] spelling: represents Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- include/quicly.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/quicly.h b/include/quicly.h index 43e1d17a4..1502eaf82 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -1018,7 +1018,7 @@ size_t quicly_send_retry(quicly_context_t *ctx, ptls_aead_context_t *token_encry * Builds UDP datagrams to be sent for given connection. * @param [out] dest destination address * @param [out] src source address - * @param [out] datagrams vector of iovecs pointing to the payloads of UDP datagrams. Each iovec represens a single UDP + * @param [out] datagrams vector of iovecs pointing to the payloads of UDP datagrams. Each iovec represents a single UDP * datagram. * @param [in,out] num_datagrams Upon entry, the application provides the number of entries that the `packets` vector can contain. * Upon return, contains the number of packet vectors emitted by `quicly_send`. From a82a72e25fb5ef8ddf5ec84c2f57ed4ec4657d35 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:20 -0500 Subject: [PATCH 315/361] spelling: responsibility Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- include/quicly.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/quicly.h b/include/quicly.h index 1502eaf82..035dd16e9 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -988,7 +988,7 @@ int quicly_stream_can_send(quicly_stream_t *stream, int at_stream_level); int quicly_can_send_data(quicly_conn_t *conn, quicly_send_context_t *s); /** * Sends data of given stream. Called by stream scheduler. Only streams that can send some data or EOS should be specified. It is - * the responsibilty of the stream scheduler to maintain a list of such streams. + * the responsibility of the stream scheduler to maintain a list of such streams. */ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s); /** From ecb49f0349c2c2e65bc67706914bc9d26e4e5d52 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:20 -0500 Subject: [PATCH 316/361] spelling: should Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 29265bdcc..7512b3ad4 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3106,7 +3106,7 @@ struct st_quicly_send_context_t { */ uint8_t ack_eliciting : 1; /** - * if the target datagram sholud be padded to full size + * if the target datagram should be padded to full size */ uint8_t full_size : 1; } target; From e9fd29dc74f29ba6de8dfd37803ad98e689eeb16 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:21 -0500 Subject: [PATCH 317/361] spelling: successful Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- include/quicly/ranges.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/quicly/ranges.h b/include/quicly/ranges.h index 724f1238c..2e2bf9519 100644 --- a/include/quicly/ranges.h +++ b/include/quicly/ranges.h @@ -58,7 +58,7 @@ static void quicly_ranges_clear(quicly_ranges_t *ranges); */ int quicly_ranges_add(quicly_ranges_t *ranges, uint64_t start, uint64_t end); /** - * subtracts given range, returns 0 if sucessful + * subtracts given range, returns 0 if successful */ int quicly_ranges_subtract(quicly_ranges_t *ranges, uint64_t start, uint64_t end); /** From 6e130c496dfa2aed443e75d7ba46b70cb42bbd4f Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:56:10 -0500 Subject: [PATCH 318/361] spelling: transport Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 7512b3ad4..6106ffb0b 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -2098,7 +2098,7 @@ int quicly_decode_transport_parameter_list(quicly_transport_parameters_t *params }); } - /* check consistency between the transpart parameters */ + /* check consistency between the transport parameters */ if (params->min_ack_delay_usec != UINT64_MAX) { if (params->min_ack_delay_usec > params->max_ack_delay * 1000) { ret = QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; From 25d7523efcf5a74519184014e285c55f91dd0332 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:41:21 -0500 Subject: [PATCH 319/361] spelling: unsupported Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 6106ffb0b..906338be3 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -6612,7 +6612,7 @@ int quicly_encrypt_address_token(void (*random_bytes)(void *, size_t), ptls_aead port = ntohs(plaintext->remote.sin6.sin6_port); break; default: - assert(!"unspported address type"); + assert(!"unsupported address type"); break; } }); From da71507e18dc7d3bb055361763898fc6466ca44f Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 18 Jan 2023 14:24:11 +0900 Subject: [PATCH 320/361] Provide way to set appdata at the moment `quicly_conn_t` is instantiated. This is useful when you need to implement callbacks that deal with application data before `quicly_accept` returns (e.g., on_client_hello) --- include/quicly.h | 8 +++++--- lib/quicly.c | 12 +++++++----- src/cli.c | 4 ++-- t/lossy.c | 8 ++++---- t/simple.c | 8 ++++---- t/stream-concurrency.c | 4 ++-- t/test.c | 4 ++-- 7 files changed, 26 insertions(+), 22 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index 035dd16e9..9ddbdb2cb 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -1075,11 +1075,12 @@ int quicly_decode_transport_parameter_list(quicly_transport_parameters_t *params /** * Initiates a new connection. * @param new_cid the CID to be used for the connection. path_id is ignored. + * @param appdata initial value to be set to `*quicly_get_data(conn)` */ int quicly_connect(quicly_conn_t **conn, quicly_context_t *ctx, const char *server_name, struct sockaddr *dest_addr, struct sockaddr *src_addr, const quicly_cid_plaintext_t *new_cid, ptls_iovec_t address_token, ptls_handshake_properties_t *handshake_properties, - const quicly_transport_parameters_t *resumed_transport_params); + const quicly_transport_parameters_t *resumed_transport_params, void *appdata); /** * accepts a new connection * @param new_cid The CID to be used for the connection. When an error is being returned, the application can reuse the CID @@ -1087,11 +1088,12 @@ int quicly_connect(quicly_conn_t **conn, quicly_context_t *ctx, const char *serv * @param address_token An validated address validation token, if any. Applications MUST validate the address validation token * before calling this function, dropping the ones that failed to validate. When a token is supplied, * `quicly_accept` will consult the values being supplied assuming that the remote peer's address has been - * validated. + * validated. + * @param appdata initial value to be set to `*quicly_get_data(conn)` */ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr *dest_addr, struct sockaddr *src_addr, quicly_decoded_packet_t *packet, quicly_address_token_plaintext_t *address_token, - const quicly_cid_plaintext_t *new_cid, ptls_handshake_properties_t *handshake_properties); + const quicly_cid_plaintext_t *new_cid, ptls_handshake_properties_t *handshake_properties, void *appdata); /** * */ diff --git a/lib/quicly.c b/lib/quicly.c index 906338be3..32a3470b1 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -2143,7 +2143,7 @@ static int collect_transport_parameters(ptls_t *tls, struct st_ptls_handshake_pr static quicly_conn_t *create_connection(quicly_context_t *ctx, uint32_t protocol_version, const char *server_name, struct sockaddr *remote_addr, struct sockaddr *local_addr, ptls_iovec_t *remote_cid, const quicly_cid_plaintext_t *local_cid, ptls_handshake_properties_t *handshake_properties, - uint32_t initcwnd) + void *appdata, uint32_t initcwnd) { ptls_t *tls = NULL; quicly_conn_t *conn; @@ -2168,6 +2168,7 @@ static quicly_conn_t *create_connection(quicly_context_t *ctx, uint32_t protocol } memset(conn, 0, sizeof(*conn)); conn->super.ctx = ctx; + conn->super.data = appdata; lock_now(conn, 0); conn->created_at = conn->stash.now; conn->super.stats.handshake_confirmed_msec = UINT64_MAX; @@ -2311,7 +2312,8 @@ static int client_collected_extensions(ptls_t *tls, ptls_handshake_properties_t int quicly_connect(quicly_conn_t **_conn, quicly_context_t *ctx, const char *server_name, struct sockaddr *dest_addr, struct sockaddr *src_addr, const quicly_cid_plaintext_t *new_cid, ptls_iovec_t address_token, - ptls_handshake_properties_t *handshake_properties, const quicly_transport_parameters_t *resumed_transport_params) + ptls_handshake_properties_t *handshake_properties, const quicly_transport_parameters_t *resumed_transport_params, + void *appdata) { const struct st_ptls_salt_t *salt; quicly_conn_t *conn = NULL; @@ -2335,7 +2337,7 @@ int quicly_connect(quicly_conn_t **_conn, quicly_context_t *ctx, const char *ser } if ((conn = create_connection( - ctx, ctx->initial_version, server_name, dest_addr, src_addr, NULL, new_cid, handshake_properties, + ctx, ctx->initial_version, server_name, dest_addr, src_addr, NULL, new_cid, handshake_properties, appdata, quicly_cc_calc_initial_cwnd(ctx->initcwnd_packets, ctx->transport_params.max_udp_payload_size))) == NULL) { ret = PTLS_ERROR_NO_MEMORY; goto Exit; @@ -6020,7 +6022,7 @@ static int validate_retry_tag(quicly_decoded_packet_t *packet, quicly_cid_t *odc int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr *dest_addr, struct sockaddr *src_addr, quicly_decoded_packet_t *packet, quicly_address_token_plaintext_t *address_token, - const quicly_cid_plaintext_t *new_cid, ptls_handshake_properties_t *handshake_properties) + const quicly_cid_plaintext_t *new_cid, ptls_handshake_properties_t *handshake_properties, void *appdata) { const struct st_ptls_salt_t *salt; struct { @@ -6063,7 +6065,7 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * /* create connection */ if ((*conn = create_connection( - ctx, packet->version, NULL, src_addr, dest_addr, &packet->cid.src, new_cid, handshake_properties, + ctx, packet->version, NULL, src_addr, dest_addr, &packet->cid.src, new_cid, handshake_properties, appdata, quicly_cc_calc_initial_cwnd(ctx->initcwnd_packets, ctx->transport_params.max_udp_payload_size))) == NULL) { ret = PTLS_ERROR_NO_MEMORY; goto Exit; diff --git a/src/cli.c b/src/cli.c index 4cb85c3d3..eed2cc783 100644 --- a/src/cli.c +++ b/src/cli.c @@ -539,7 +539,7 @@ static int run_client(int fd, struct sockaddr *sa, const char *host) perror("bind(2) failed"); return 1; } - ret = quicly_connect(&conn, &ctx, host, sa, NULL, &next_cid, resumption_token, &hs_properties, &resumed_transport_params); + ret = quicly_connect(&conn, &ctx, host, sa, NULL, &next_cid, resumption_token, &hs_properties, &resumed_transport_params, NULL); assert(ret == 0); ++next_cid.master_id; enqueue_requests(conn); @@ -832,7 +832,7 @@ static int run_server(int fd, struct sockaddr *sa, socklen_t salen) break; } else { /* new connection */ - int ret = quicly_accept(&conn, &ctx, NULL, &remote.sa, &packet, token, &next_cid, NULL); + int ret = quicly_accept(&conn, &ctx, NULL, &remote.sa, &packet, token, &next_cid, NULL, NULL); if (ret == 0) { assert(conn != NULL); ++next_cid.master_id; diff --git a/t/lossy.c b/t/lossy.c index 012c36b92..194e6106d 100644 --- a/t/lossy.c +++ b/t/lossy.c @@ -176,7 +176,7 @@ static void test_even(void) quicly_decoded_packet_t decoded; ret = quicly_connect(&client, &quic_ctx, "example.com", &fake_address.sa, NULL, new_master_id(), ptls_iovec_init(NULL, 0), - NULL, NULL); + NULL, NULL, NULL); ok(ret == 0); num_packets = 1; ret = quicly_send(client, &destaddr, &srcaddr, &raw, &num_packets, rawbuf, sizeof(rawbuf)); @@ -184,7 +184,7 @@ static void test_even(void) ok(num_packets == 1); decode_packets(&decoded, &raw, 1); ok(num_packets == 1); - ret = quicly_accept(&server, &quic_ctx, NULL, &fake_address.sa, &decoded, NULL, new_master_id(), NULL); + ret = quicly_accept(&server, &quic_ctx, NULL, &fake_address.sa, &decoded, NULL, new_master_id(), NULL, NULL); ok(ret == 0); cond_up.cb(&cond_up); } @@ -283,7 +283,7 @@ static void loss_core(void) quicly_decoded_packet_t decoded; ret = quicly_connect(&client, &quic_ctx, "example.com", &fake_address.sa, NULL, new_master_id(), ptls_iovec_init(NULL, 0), - NULL, NULL); + NULL, NULL, NULL); ok(ret == 0); num_packets = 1; ret = quicly_send(client, &destaddr, &srcaddr, &raw, &num_packets, rawbuf, sizeof(rawbuf)); @@ -292,7 +292,7 @@ static void loss_core(void) quic_now += 10; decode_packets(&decoded, &raw, 1); ok(num_packets == 1); - ret = quicly_accept(&server, &quic_ctx, NULL, &fake_address.sa, &decoded, NULL, new_master_id(), NULL); + ret = quicly_accept(&server, &quic_ctx, NULL, &fake_address.sa, &decoded, NULL, new_master_id(), NULL, NULL); ok(ret == 0); quic_now += 10; } diff --git a/t/simple.c b/t/simple.c index 4f2c7927d..40b70b69c 100644 --- a/t/simple.c +++ b/t/simple.c @@ -36,7 +36,7 @@ static void test_handshake(void) /* send CH */ ret = quicly_connect(&client, &quic_ctx, "example.com", &fake_address.sa, NULL, new_master_id(), ptls_iovec_init(NULL, 0), NULL, - NULL); + NULL, NULL); ok(ret == 0); num_packets = PTLS_ELEMENTSOF(packets); ret = quicly_send(client, &dest, &src, packets, &num_packets, packetsbuf, sizeof(packetsbuf)); @@ -47,7 +47,7 @@ static void test_handshake(void) /* receive CH, send handshake upto ServerFinished */ num_decoded = decode_packets(decoded, packets, num_packets); ok(num_decoded == 1); - ret = quicly_accept(&server, &quic_ctx, NULL, &fake_address.sa, decoded, NULL, new_master_id(), NULL); + ret = quicly_accept(&server, &quic_ctx, NULL, &fake_address.sa, decoded, NULL, new_master_id(), NULL, NULL); ok(ret == 0); ok(quicly_get_state(server) == QUICLY_STATE_CONNECTED); ok(quicly_connection_is_ready(server)); @@ -548,7 +548,7 @@ static void tiny_connection_window(void) quicly_decoded_packet_t decoded; ret = quicly_connect(&client, &quic_ctx, "example.com", &fake_address.sa, NULL, new_master_id(), ptls_iovec_init(NULL, 0), - NULL, NULL); + NULL, NULL, NULL); ok(ret == 0); num_packets = 1; ret = quicly_send(client, &dest, &src, &raw, &num_packets, rawbuf, sizeof(rawbuf)); @@ -557,7 +557,7 @@ static void tiny_connection_window(void) ok(quicly_get_first_timeout(client) > quic_ctx.now->cb(quic_ctx.now)); decode_packets(&decoded, &raw, 1); ok(num_packets == 1); - ret = quicly_accept(&server, &quic_ctx, NULL, &fake_address.sa, &decoded, NULL, new_master_id(), NULL); + ret = quicly_accept(&server, &quic_ctx, NULL, &fake_address.sa, &decoded, NULL, new_master_id(), NULL, NULL); ok(ret == 0); } diff --git a/t/stream-concurrency.c b/t/stream-concurrency.c index adec375ba..fc4f534d6 100644 --- a/t/stream-concurrency.c +++ b/t/stream-concurrency.c @@ -40,7 +40,7 @@ void test_stream_concurrency(void) quicly_decoded_packet_t decoded; ret = quicly_connect(&client, &quic_ctx, "example.com", &fake_address.sa, NULL, new_master_id(), ptls_iovec_init(NULL, 0), - NULL, NULL); + NULL, NULL, NULL); ok(ret == 0); num_packets = 1; ret = quicly_send(client, &dest, &src, &raw, &num_packets, rawbuf, sizeof(rawbuf)); @@ -48,7 +48,7 @@ void test_stream_concurrency(void) ok(num_packets == 1); ok(decode_packets(&decoded, &raw, 1) == 1); ok(num_packets == 1); - ret = quicly_accept(&server, &quic_ctx, NULL, &fake_address.sa, &decoded, NULL, new_master_id(), NULL); + ret = quicly_accept(&server, &quic_ctx, NULL, &fake_address.sa, &decoded, NULL, new_master_id(), NULL, NULL); ok(ret == 0); transmit(server, client); } diff --git a/t/test.c b/t/test.c index ac249b35a..99edb8043 100644 --- a/t/test.c +++ b/t/test.c @@ -625,7 +625,7 @@ static void test_nondecryptable_initial(void) ok(num_decoded == 1); /* decryption should fail */ - ret = quicly_accept(&server, &quic_ctx, NULL, &fake_address.sa, &decoded, NULL, new_master_id(), NULL); + ret = quicly_accept(&server, &quic_ctx, NULL, &fake_address.sa, &decoded, NULL, new_master_id(), NULL, NULL); ok(ret == QUICLY_ERROR_DECRYPTION_FAILED); #undef PACKET_LEN #undef HEADER_LEN @@ -639,7 +639,7 @@ static void test_set_cc(void) int ret; ret = quicly_connect(&conn, &quic_ctx, "example.com", &fake_address.sa, NULL, new_master_id(), ptls_iovec_init(NULL, 0), NULL, - NULL); + NULL, NULL); ok(ret == 0); quicly_stats_t stats; From 19ffcf8a2499557c7e23644c342f366b38af75dd Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 18 Jan 2023 16:00:35 +0900 Subject: [PATCH 321/361] adjust here too --- examples/echo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/echo.c b/examples/echo.c index a6723a0a1..3c368938a 100644 --- a/examples/echo.c +++ b/examples/echo.c @@ -175,7 +175,7 @@ static void process_msg(int is_client, quicly_conn_t **conns, struct msghdr *msg quicly_receive(conns[i], NULL, msg->msg_name, &decoded); } else if (!is_client) { /* assume that the packet is a new connection */ - quicly_accept(conns + i, &ctx, NULL, msg->msg_name, &decoded, NULL, &next_cid, NULL); + quicly_accept(conns + i, &ctx, NULL, msg->msg_name, &decoded, NULL, &next_cid, NULL, NULL); } } } @@ -386,7 +386,7 @@ int main(int argc, char **argv) /* initiate a connection, and open a stream */ int ret; if ((ret = quicly_connect(&client, &ctx, host, (struct sockaddr *)&sa, NULL, &next_cid, ptls_iovec_init(NULL, 0), NULL, - NULL)) != 0) { + NULL, NULL)) != 0) { fprintf(stderr, "quicly_connect failed:%d\n", ret); exit(1); } From 7ffab368ed4391d8908af34fa77b6d3c19597a29 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 18 Jan 2023 16:04:28 +0900 Subject: [PATCH 322/361] and here --- t/simulator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/simulator.c b/t/simulator.c index 9c58e2754..73a18dc12 100644 --- a/t/simulator.c +++ b/t/simulator.c @@ -309,7 +309,7 @@ static void net_endpoint_forward(struct net_node *_self, struct net_packet *pack } else { assert(self->accept_ctx != NULL && "a packet for which we do not have state must be a new connection request"); if (quicly_accept(&conn->quic, self->accept_ctx, &packet->dest.sa, &packet->src->addr.sa, &qp, NULL, &next_quic_cid, - NULL) == 0) { + NULL, NULL) == 0) { assert(conn->quic != NULL); ++next_quic_cid.master_id; conn->egress = &packet->src->super; @@ -598,7 +598,7 @@ int main(int argc, char **argv) net_endpoint_init(client_node); client_node->start_at = now + start; int ret = quicly_connect(&client_node->conns[0].quic, &quicctx, "hello.example.com", &server_node.node.addr.sa, - &client_node->addr.sa, &next_quic_cid, ptls_iovec_init(NULL, 0), NULL, NULL); + &client_node->addr.sa, &next_quic_cid, ptls_iovec_init(NULL, 0), NULL, NULL, NULL); ++next_quic_cid.master_id; assert(ret == 0); quicly_stream_t *stream; From 2c633eabda308ccef8139ebe705c77d05ce54488 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 13 Feb 2023 14:34:08 +0900 Subject: [PATCH 323/361] [cli] in OpenSSL 3.0, load legacy provider for blowfish --- src/cli.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/cli.c b/src/cli.c index eed2cc783..55bc96b74 100644 --- a/src/cli.c +++ b/src/cli.c @@ -31,6 +31,10 @@ #include #include #include +#include +#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#endif #if QUICLY_HAVE_FUSION #include "picotls/fusion.h" #endif @@ -1082,6 +1086,14 @@ int main(int argc, char **argv) unsigned udpbufsize = 0; int ch, opt_index, fd; + ERR_load_crypto_strings(); + OpenSSL_add_all_algorithms(); +#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L + /* Explicitly load the legacy provider in addition to default, as we test Blowfish in one of the tests. */ + (void)OSSL_PROVIDER_load(NULL, "legacy"); + (void)OSSL_PROVIDER_load(NULL, "default"); +#endif + reqs = malloc(sizeof(*reqs)); memset(reqs, 0, sizeof(*reqs)); ctx = quicly_spec_context; From 748ac1967a7b43f71e7fef9ac40a8467a1c04da9 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 13 Feb 2023 14:38:57 +0900 Subject: [PATCH 324/361] add CI using OpenSSL 3.0 --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 467afa5be..ac78d308c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,8 @@ jobs: include: - name: default command: make -f misc/docker-ci.mk + - name: openssl-3.0 + command: make -f misc/docker-ci.mk CONTAINER_NAME=h2oserver/h2o-ci:ubuntu2204 - name: asan command: make -f misc/docker-ci.mk CMAKE_ARGS='-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_FLAGS=-fsanitize=address -DCMAKE_CXX_FLAGS=-fsanitize=address' CHECK_ENVS='ASAN_OPTIONS=detect_leaks=0' From 3055ee3bc46e9d7b96220bf6a888341f47043805 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 10 Feb 2023 23:32:50 +0900 Subject: [PATCH 325/361] [picotls] switch to boringssl branch --- deps/picotls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/picotls b/deps/picotls index 4e57e9b09..fc455f9f1 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit 4e57e9b09ebac4da4c28433e20e5a88ffa972a08 +Subproject commit fc455f9f1d521c77a7e50e99c1c1b63121ce3498 From 0f96a938fd0789214936e7b7801d2955a7de0eed Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sat, 11 Feb 2023 01:03:29 +0900 Subject: [PATCH 326/361] support boringssl --- CMakeLists.txt | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3fab895d6..d9948535f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,9 +5,11 @@ PROJECT(quicly) INCLUDE(CMakePushCheckState) INCLUDE(CheckCSourceCompiles) +INCLUDE(deps/picotls/cmake/boringssl-adjust.cmake) INCLUDE(deps/picotls/cmake/dtrace-utils.cmake) FIND_PACKAGE(OpenSSL REQUIRED) +BORINGSSL_ADJUST() IF (OPENSSL_FOUND AND (OPENSSL_VERSION VERSION_LESS "1.0.2")) MESSAGE(FATAL "OpenSSL 1.0.2 or above is missing") ENDIF () @@ -117,16 +119,16 @@ IF (WITH_FUSION) ENDIF () ADD_EXECUTABLE(cli ${CLI_FILES}) SET_TARGET_PROPERTIES(cli PROPERTIES COMPILE_FLAGS "${CLI_COMPILE_FLAGS}") -TARGET_LINK_LIBRARIES(cli ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS} m) +TARGET_LINK_LIBRARIES(cli ${OPENSSL_CRYPTO_LIBRARIES} ${CMAKE_DL_LIBS} m) ADD_EXECUTABLE(test.t ${PICOTLS_OPENSSL_FILES} ${UNITTEST_SOURCE_FILES}) -TARGET_LINK_LIBRARIES(test.t quicly ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS}) +TARGET_LINK_LIBRARIES(test.t quicly ${OPENSSL_CRYPTO_LIBRARIES} ${CMAKE_DL_LIBS}) ADD_EXECUTABLE(simulator ${PICOTLS_OPENSSL_FILES} ${QUICLY_LIBRARY_FILES} t/simulator.c) -TARGET_LINK_LIBRARIES(simulator ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS} m) +TARGET_LINK_LIBRARIES(simulator ${OPENSSL_CRYPTO_LIBRARIES} ${CMAKE_DL_LIBS} m) ADD_EXECUTABLE(examples-echo ${PICOTLS_OPENSSL_FILES} examples/echo.c) -TARGET_LINK_LIBRARIES(examples-echo quicly ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS}) +TARGET_LINK_LIBRARIES(examples-echo quicly ${OPENSSL_CRYPTO_LIBRARIES} ${CMAKE_DL_LIBS}) ADD_EXECUTABLE(udpfw t/udpfw.c) @@ -152,17 +154,17 @@ IF (BUILD_FUZZER) SET(LIB_FUZZER FuzzingEngine) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer") - TARGET_LINK_LIBRARIES(quicly-fuzzer-packet quicly ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS}) + TARGET_LINK_LIBRARIES(quicly-fuzzer-packet quicly ${OPENSSL_CRYPTO_LIBRARIES} ${CMAKE_DL_LIBS}) ELSEIF (USE_CLANG_RT) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer -fsanitize=fuzzer,address,undefined -fsanitize-coverage=edge,indirect-calls") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fno-omit-frame-pointer -fsanitize=fuzzer,address,undefined -fsanitize-coverage=edge,indirect-calls") - TARGET_LINK_LIBRARIES(quicly-fuzzer-packet quicly ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS}) + TARGET_LINK_LIBRARIES(quicly-fuzzer-packet quicly ${OPENSSL_CRYPTO_LIBRARIES} ${CMAKE_DL_LIBS}) ELSE() SET(LIB_FUZZER "${CMAKE_CURRENT_BINARY_DIR}/libFuzzer.a") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer -fsanitize=address -fsanitize-address-use-after-scope -fsanitize=fuzzer-no-link") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fno-omit-frame-pointer -fsanitize=address -fsanitize-address-use-after-scope -fsanitize=fuzzer-no-link") ADD_CUSTOM_TARGET(libFuzzer ${CMAKE_CURRENT_SOURCE_DIR}/misc/build_libFuzzer.sh WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) ADD_DEPENDENCIES(quicly-fuzzer-packet libFuzzer) - TARGET_LINK_LIBRARIES(quicly-fuzzer-packet quicly ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS} ${LIB_FUZZER}) + TARGET_LINK_LIBRARIES(quicly-fuzzer-packet quicly ${OPENSSL_CRYPTO_LIBRARIES} ${CMAKE_DL_LIBS} ${LIB_FUZZER}) ENDIF(OSS_FUZZ) ENDIF() From 88308ea459339e8068cd4b8e6f1e5f64c46f39e1 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sat, 11 Feb 2023 01:03:53 +0900 Subject: [PATCH 327/361] upper-case version installs only the CRYPTO portion of libcrypto --- t/simulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/simulator.c b/t/simulator.c index 73a18dc12..7714167c6 100644 --- a/t/simulator.c +++ b/t/simulator.c @@ -518,7 +518,7 @@ static void usage(const char *cmd) int main(int argc, char **argv) { - ERR_load_CRYPTO_strings(); + ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); ptls_iovec_t cert = {}; From da3dc1dfee430c5dc147a98421315499d20cf75e Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 13 Feb 2023 16:43:22 +0900 Subject: [PATCH 328/361] update picotls --- deps/picotls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/picotls b/deps/picotls index 4e57e9b09..3a1c90cb6 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit 4e57e9b09ebac4da4c28433e20e5a88ffa972a08 +Subproject commit 3a1c90cb646679217f364d5971fd4daf703ea07d From 3a3fa878de055ada84e75fed0261e191aefb5b2e Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 13 Feb 2023 16:43:54 +0900 Subject: [PATCH 329/361] use the new `ptls_aead_set_iv` --- lib/quicly.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 32a3470b1..da0baaa22 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -6638,10 +6638,10 @@ int quicly_encrypt_address_token(void (*random_bytes)(void *, size_t), ptls_aead } ptls_buffer_push_block(buf, 1, { ptls_buffer_pushv(buf, plaintext->appdata.bytes, plaintext->appdata.len); }); - /* encrypt, abusing the internal API to supply full IV */ + /* encrypt, supplying full IV */ if ((ret = ptls_buffer_reserve(buf, aead->algo->tag_size)) != 0) goto Exit; - aead->algo->setup_crypto(aead, 1, NULL, buf->base + enc_start - aead->algo->iv_size); + ptls_aead_set_iv(aead, buf->base + enc_start - aead->algo->iv_size); ptls_aead_encrypt(aead, buf->base + enc_start, buf->base + enc_start, buf->off - enc_start, 0, buf->base + start_off, enc_start - start_off); buf->off += aead->algo->tag_size; @@ -6686,7 +6686,7 @@ int quicly_decrypt_address_token(ptls_aead_context_t *aead, quicly_address_token int ret; /* decrypt */ - aead->algo->setup_crypto(aead, 0, NULL, token + prefix_len + 1); + ptls_aead_set_iv(aead, token + prefix_len + 1); if ((ptlen = ptls_aead_decrypt(aead, ptbuf, token + prefix_len + 1 + aead->algo->iv_size, len - (prefix_len + 1 + aead->algo->iv_size), 0, token, prefix_len + 1 + aead->algo->iv_size)) == SIZE_MAX) { From 9482376c0cc59a02ba80d154126f866b5ddea086 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 13 Feb 2023 21:05:30 +0900 Subject: [PATCH 330/361] update picotls --- deps/picotls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/picotls b/deps/picotls index 3a1c90cb6..db826507e 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit 3a1c90cb646679217f364d5971fd4daf703ea07d +Subproject commit db826507e55cfaad9603864efac51a409e8495df From fe1fdd0bddbfec51563961de52db839ea87f703c Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 13 Feb 2023 23:14:29 +0900 Subject: [PATCH 331/361] add test vector generated using old code --- t/test.c | 49 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/t/test.c b/t/test.c index 99edb8043..aae052611 100644 --- a/t/test.c +++ b/t/test.c @@ -440,15 +440,47 @@ static void test_next_packet_number(void) ok(n == 65567); } +static void test_address_token_codec_decode(ptls_aead_context_t *dec, const void *encrypted, size_t encrypted_len) +{ + quicly_address_token_plaintext_t output; + const char *err_desc; + + ptls_openssl_random_bytes(&output, sizeof(output)); + + ok(quicly_decrypt_address_token(dec, &output, encrypted, encrypted_len, 0, &err_desc) == 0); + ok(output.type == QUICLY_ADDRESS_TOKEN_TYPE_RETRY); + ok(output.issued_at == 234); + ok(output.remote.sa.sa_family == AF_INET); + ok(output.remote.sin.sin_addr.s_addr == htonl(0x7f000001)); + ok(output.remote.sin.sin_port == htons(443)); + ok(quicly_cid_is_equal(&output.retry.original_dcid, ptls_iovec_init("abcdefgh", 8))); + ok(quicly_cid_is_equal(&output.retry.client_cid, ptls_iovec_init("01234", 5))); + ok(quicly_cid_is_equal(&output.retry.server_cid, ptls_iovec_init("abcdef0123456789", 16))); + ok(output.appdata.len == 11); + ok(memcmp(output.appdata.bytes, "hello world", 11) == 0); +} + static void test_address_token_codec(void) { static const uint8_t zero_key[PTLS_MAX_SECRET_SIZE] = {0}; ptls_aead_context_t *enc = ptls_aead_new(&ptls_openssl_aes128gcm, &ptls_openssl_sha256, 1, zero_key, ""), *dec = ptls_aead_new(&ptls_openssl_aes128gcm, &ptls_openssl_sha256, 0, zero_key, ""); + quicly_address_token_plaintext_t input, output; ptls_buffer_t buf; const char *err_desc; + { /* test hard-coded sample */ + static const uint8_t sample[] = {0x00, 0x39, 0xef, 0x13, 0x9a, 0xe1, 0xaa, 0x28, 0x51, 0x62, 0xf6, 0xd8, 0xc8, 0x93, 0x6a, + 0xdf, 0xd1, 0xbe, 0xa4, 0xb5, 0x99, 0xb9, 0xd7, 0x99, 0x02, 0xe3, 0x9e, 0xf2, 0xd0, 0x30, + 0x0b, 0x80, 0xcf, 0x66, 0xc4, 0x69, 0xc3, 0x86, 0x69, 0x92, 0xef, 0x3f, 0xd9, 0x64, 0x4b, + 0x6e, 0x9e, 0x16, 0x3a, 0x4d, 0xb6, 0x2c, 0xfc, 0x99, 0xe4, 0x46, 0x88, 0x7a, 0x73, 0x0d, + 0x69, 0x0e, 0xfb, 0xbf, 0x0e, 0x7c, 0xe3, 0x2d, 0x78, 0xf3, 0x90, 0xf6, 0xfd, 0xa4, 0x5e, + 0x71, 0x23, 0x3a, 0x15, 0xf2, 0x5f, 0xa6, 0x9e, 0x36, 0x13, 0x69, 0x53, 0xc1}; + test_address_token_codec_decode(dec, sample, sizeof(sample)); + } + + /* encrypt and decrypt */ input = (quicly_address_token_plaintext_t){QUICLY_ADDRESS_TOKEN_TYPE_RETRY, 234}; input.remote.sin.sin_family = AF_INET; input.remote.sin.sin_addr.s_addr = htonl(0x7f000001); @@ -459,23 +491,8 @@ static void test_address_token_codec(void) strcpy((char *)input.appdata.bytes, "hello world"); input.appdata.len = strlen((char *)input.appdata.bytes); ptls_buffer_init(&buf, "", 0); - ok(quicly_encrypt_address_token(ptls_openssl_random_bytes, enc, &buf, 0, &input) == 0); - - /* check that the output is ok */ - ptls_openssl_random_bytes(&output, sizeof(output)); - ok(quicly_decrypt_address_token(dec, &output, buf.base, buf.off, 0, &err_desc) == 0); - ok(input.type == output.type); - ok(input.issued_at == output.issued_at); - ok(input.remote.sa.sa_family == output.remote.sa.sa_family); - ok(input.remote.sin.sin_addr.s_addr == output.remote.sin.sin_addr.s_addr); - ok(input.remote.sin.sin_port == output.remote.sin.sin_port); - ok(quicly_cid_is_equal(&output.retry.original_dcid, - ptls_iovec_init(input.retry.original_dcid.cid, input.retry.original_dcid.len))); - ok(quicly_cid_is_equal(&output.retry.client_cid, ptls_iovec_init(input.retry.client_cid.cid, input.retry.client_cid.len))); - ok(quicly_cid_is_equal(&output.retry.server_cid, ptls_iovec_init(input.retry.server_cid.cid, input.retry.server_cid.len))); - ok(input.appdata.len == output.appdata.len); - ok(memcmp(input.appdata.bytes, output.appdata.bytes, input.appdata.len) == 0); + test_address_token_codec_decode(dec, buf.base, buf.off); /* failure to decrypt a Retry token is a hard error */ ptls_openssl_random_bytes(&output, sizeof(output)); From ecabba57879f8fbc60e632f41bb0a7564218483a Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 14 Feb 2023 00:03:15 +0900 Subject: [PATCH 332/361] update picotls --- deps/picotls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/picotls b/deps/picotls index db826507e..2f371d122 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit db826507e55cfaad9603864efac51a409e8495df +Subproject commit 2f371d1227e5e928046602ec18c92999c761ed80 From 43e1a7c11acc7dca2cf750b0e38fb781b1a417c2 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 14 Feb 2023 00:13:37 +0900 Subject: [PATCH 333/361] update picotls --- deps/picotls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/picotls b/deps/picotls index fc455f9f1..c142d8518 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit fc455f9f1d521c77a7e50e99c1c1b63121ce3498 +Subproject commit c142d851807f150afc863e92c13809760e0c7983 From 88df74127667847618f80b47d3b8f467ddf20e8f Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 14 Feb 2023 00:19:54 +0900 Subject: [PATCH 334/361] add boringssl to CI matrix --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ac78d308c..e45e21af7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,8 @@ jobs: command: make -f misc/docker-ci.mk - name: openssl-3.0 command: make -f misc/docker-ci.mk CONTAINER_NAME=h2oserver/h2o-ci:ubuntu2204 + - name: boringssl + command: make -f misc/docker-ci.mk CONTAINER_NAME=h2oserver/h2o-ci:ubuntu2204 CMAKE_ARGS='-DOPENSSL_ROOT_DIR=/opt/boringssl' - name: asan command: make -f misc/docker-ci.mk CMAKE_ARGS='-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_FLAGS=-fsanitize=address -DCMAKE_CXX_FLAGS=-fsanitize=address' CHECK_ENVS='ASAN_OPTIONS=detect_leaks=0' From e70e10ef48f538977b70bcd6c652f5504b35ba27 Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Wed, 19 Oct 2022 06:03:20 +0000 Subject: [PATCH 335/361] it's better to use a newler clang when using sanitizers --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ac78d308c..08cd9758d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: - name: openssl-3.0 command: make -f misc/docker-ci.mk CONTAINER_NAME=h2oserver/h2o-ci:ubuntu2204 - name: asan - command: make -f misc/docker-ci.mk CMAKE_ARGS='-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_FLAGS=-fsanitize=address -DCMAKE_CXX_FLAGS=-fsanitize=address' CHECK_ENVS='ASAN_OPTIONS=detect_leaks=0' + command: make -f misc/docker-ci.mk CONTAINER_NAME=h2oserver/h2o-ci:ubuntu2204 CMAKE_ARGS='-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_FLAGS=-fsanitize=address -DCMAKE_CXX_FLAGS=-fsanitize=address' CHECK_ENVS='ASAN_OPTIONS=detect_leaks=0' timeout-minutes: 10 steps: From af64fe4e583218f66d10ba586e8d1a589345c69b Mon Sep 17 00:00:00 2001 From: Goro Fuji Date: Wed, 19 Oct 2022 06:04:28 +0000 Subject: [PATCH 336/361] don't much care about the dist of host machine as long as we use docker --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 08cd9758d..15f4f7778 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,7 @@ on: [push, pull_request] jobs: build: name: "${{ matrix.name }}" - runs-on: [ubuntu-20.04] + runs-on: [ubuntu-latest] # We want to run on external PRs, but not on our own internal PRs as they'll be run # by the push to the branch. From a47fd4900f2ab69a7a0f8620c2b86777a7dea5a8 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 17 Feb 2023 12:26:18 +0900 Subject: [PATCH 337/361] update picotls --- deps/picotls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/picotls b/deps/picotls index c142d8518..3b3a910c5 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit c142d851807f150afc863e92c13809760e0c7983 +Subproject commit 3b3a910c5cad139e3ac3ebca1a4b93604263e6c8 From 1701c4865489f6faa9e7d80a042a355a73f61036 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 17 Feb 2023 14:23:45 +0900 Subject: [PATCH 338/361] NEW_TOKEN from a client is PROTOCOL_VIOLATION --- lib/quicly.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/quicly.c b/lib/quicly.c index da0baaa22..ad8ce5189 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5439,6 +5439,8 @@ static int handle_new_token_frame(quicly_conn_t *conn, struct st_quicly_handle_p quicly_new_token_frame_t frame; int ret; + if (!quicly_is_client(conn)) + return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; if ((ret = quicly_decode_new_token_frame(&state->src, state->end, &frame)) != 0) return ret; QUICLY_PROBE(NEW_TOKEN_RECEIVE, conn, conn->stash.now, frame.token.base, frame.token.len); From 3f9166c8ec86c531b8b8d911d8f53956efe13fea Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Fri, 17 Feb 2023 17:16:55 -0800 Subject: [PATCH 339/361] quicly_stats: count out of order packets --- include/quicly.h | 4 ++++ lib/quicly.c | 14 ++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index 9ddbdb2cb..1c63bcfe2 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -450,6 +450,10 @@ struct st_quicly_conn_streamgroup_state_t { * Total number of Initial and Handshake packets sent. \ */ \ uint64_t initial_handshake_sent; \ + /** \ + * Total number of packets received out of order. \ + */ \ + uint64_t received_out_of_order; \ } num_packets; \ struct { \ /** \ diff --git a/lib/quicly.c b/lib/quicly.c index ad8ce5189..05d01f7b9 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1426,11 +1426,15 @@ static int record_pn(quicly_ranges_t *ranges, uint64_t pn, int *is_out_of_order) return 0; } -static int record_receipt(struct st_quicly_pn_space_t *space, uint64_t pn, int is_ack_only, int64_t now, int64_t *send_ack_at) +static int record_receipt(struct st_quicly_pn_space_t *space, uint64_t pn, int is_ack_only, int64_t now, int64_t *send_ack_at, + uint64_t *received_out_of_order) { int ret, ack_now, is_out_of_order; - if ((ret = record_pn(&space->ack_queue, pn, &is_out_of_order)) != 0) + ret = record_pn(&space->ack_queue, pn, &is_out_of_order); + if (is_out_of_order) + *received_out_of_order += 1; + if (ret != 0) goto Exit; ack_now = is_out_of_order && !space->ignore_order && !is_ack_only; @@ -6108,7 +6112,8 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * (*conn)->super.stats.num_bytes.received += packet->datagram_size; if ((ret = handle_payload(*conn, QUICLY_EPOCH_INITIAL, payload.base, payload.len, &offending_frame_type, &is_ack_only)) != 0) goto Exit; - if ((ret = record_receipt(&(*conn)->initial->super, pn, 0, (*conn)->stash.now, &(*conn)->egress.send_ack_at)) != 0) + if ((ret = record_receipt(&(*conn)->initial->super, pn, 0, (*conn)->stash.now, &(*conn)->egress.send_ack_at, + &(*conn)->super.stats.num_packets.received_out_of_order)) != 0) goto Exit; Exit: @@ -6345,7 +6350,8 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka if ((ret = handle_payload(conn, epoch, payload.base, payload.len, &offending_frame_type, &is_ack_only)) != 0) goto Exit; if (*space != NULL && conn->super.state < QUICLY_STATE_CLOSING) { - if ((ret = record_receipt(*space, pn, is_ack_only, conn->stash.now, &conn->egress.send_ack_at)) != 0) + if ((ret = record_receipt(*space, pn, is_ack_only, conn->stash.now, &conn->egress.send_ack_at, + &conn->super.stats.num_packets.received_out_of_order)) != 0) goto Exit; } From bc9f104d67ae97ad9f9f6f7b2e3a2cf52dc16b41 Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Fri, 17 Feb 2023 17:31:54 -0800 Subject: [PATCH 340/361] Only count out of order in cases where record_pn returned 0 --- lib/quicly.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 05d01f7b9..2ef1d4d15 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1431,11 +1431,10 @@ static int record_receipt(struct st_quicly_pn_space_t *space, uint64_t pn, int i { int ret, ack_now, is_out_of_order; - ret = record_pn(&space->ack_queue, pn, &is_out_of_order); + if ((ret = record_pn(&space->ack_queue, pn, &is_out_of_order)) != 0) + goto Exit; if (is_out_of_order) *received_out_of_order += 1; - if (ret != 0) - goto Exit; ack_now = is_out_of_order && !space->ignore_order && !is_ack_only; From ec4da46c3f412e3cccf8bd50efa91c64504ebfb9 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sun, 19 Feb 2023 10:54:15 +0900 Subject: [PATCH 341/361] update tests --- t/test.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/t/test.c b/t/test.c index aae052611..1f34b1f2d 100644 --- a/t/test.c +++ b/t/test.c @@ -515,20 +515,20 @@ static void do_test_record_receipt(size_t epoch) { struct st_quicly_pn_space_t *space = alloc_pn_space(sizeof(*space), epoch == QUICLY_EPOCH_1RTT ? QUICLY_DEFAULT_PACKET_TOLERANCE : 1); - uint64_t pn = 0; + uint64_t pn = 0, out_of_order_cnt = 0; int64_t now = 12345, send_ack_at = INT64_MAX; if (epoch == QUICLY_EPOCH_1RTT) { /* 2nd packet triggers an ack */ - ok(record_receipt(space, pn++, 0, now, &send_ack_at) == 0); + ok(record_receipt(space, pn++, 0, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == now + QUICLY_DELAYED_ACK_TIMEOUT); now += 1; - ok(record_receipt(space, pn++, 0, now, &send_ack_at) == 0); + ok(record_receipt(space, pn++, 0, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == now); now += 1; } else { /* every packet triggers an ack */ - ok(record_receipt(space, pn++, 0, now, &send_ack_at) == 0); + ok(record_receipt(space, pn++, 0, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == now); now += 1; } @@ -538,23 +538,23 @@ static void do_test_record_receipt(size_t epoch) send_ack_at = INT64_MAX; /* ack-only packets do not elicit an ack */ - ok(record_receipt(space, pn++, 1, now, &send_ack_at) == 0); + ok(record_receipt(space, pn++, 1, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == INT64_MAX); now += 1; - ok(record_receipt(space, pn++, 1, now, &send_ack_at) == 0); + ok(record_receipt(space, pn++, 1, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == INT64_MAX); now += 1; pn++; /* gap */ - ok(record_receipt(space, pn++, 1, now, &send_ack_at) == 0); + ok(record_receipt(space, pn++, 1, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == INT64_MAX); now += 1; - ok(record_receipt(space, pn++, 1, now, &send_ack_at) == 0); + ok(record_receipt(space, pn++, 1, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == INT64_MAX); now += 1; /* gap triggers an ack */ pn += 1; /* gap */ - ok(record_receipt(space, pn++, 0, now, &send_ack_at) == 0); + ok(record_receipt(space, pn++, 0, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == now); now += 1; @@ -566,10 +566,10 @@ static void do_test_record_receipt(size_t epoch) if (epoch == QUICLY_EPOCH_1RTT) { space->ignore_order = 1; pn++; /* gap */ - ok(record_receipt(space, pn++, 0, now, &send_ack_at) == 0); + ok(record_receipt(space, pn++, 0, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == now + QUICLY_DELAYED_ACK_TIMEOUT); now += 1; - ok(record_receipt(space, pn++, 0, now, &send_ack_at) == 0); + ok(record_receipt(space, pn++, 0, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == now); now += 1; } From 80b1766a3636cec7190fe783689674eec6e69813 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 8 Jun 2023 14:20:51 +0900 Subject: [PATCH 342/361] Make certain MAX_DATA and MAX_STREAMS frames are be sent. Up until now, * MAX_DATA * MAX_STREAMS as response to STREAMS_BLOCKED have been scheduled by setting `send_ack_at` to zero. This becomes a problem when CWND is full. After sending an ack-only packet, quicly will not send MAX_DATA or MAX_STREAMS at the moment CWND becomes available, as `quicly_get_first_timeout` will return a large value once the ack-only packet has been sent. This commit address the issue by consolidating when connection-level control information to the `pending_flow` flag. The seventh bit that previously carried the information for NEW_CONNECTION_ID / RETIRE_CONNECTION_ID frames now carry information for other frames too. --- lib/quicly.c | 215 ++++++++++++++++++++++++++++----------------------- 1 file changed, 117 insertions(+), 98 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 2ef1d4d15..2a084196b 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -325,17 +325,13 @@ struct st_quicly_conn_t { /** * bit vector indicating if there's any pending crypto data (the insignificant 4 bits), or other non-stream data */ - uint8_t pending_flows; + uint16_t pending_flows; #define QUICLY_PENDING_FLOW_NEW_TOKEN_BIT (1 << 5) #define QUICLY_PENDING_FLOW_HANDSHAKE_DONE_BIT (1 << 6) -/** - * is there a pending NEW_CONNECTION_ID or RETIRE_CONNECTION_ID frame? - * - * This single bit represents two frame types, to keep `pending_flows` within 8 bits, and to reduce `if` branch in `do_send` - * function. If we had two separate bits, we would have to check each bit separately in `do_send` function. Given NEW_CONNECTION_ID - * and RETIRE_CONNECTION_ID frames are expected to be rarely sent, folding two types into a single bit makes sense. - */ -#define QUICLY_PENDING_FLOW_CID_FRAME_BIT (1 << 7) +/* Indicates that PATH_CHALLENGE, PATH_RESPONSE, MAX_STREAMS, MAX_DATA, DATA_BLOCKED, STREAMS_BLOCKED, NEW_CONNECTION_ID _might_ + * have to be sent. Contrary to NEW_TOKEN_BIT and HANDSHAKE_DONE_BIT, there could be false positives; logic for sending each of + * these frames have the capability of detecting such false positives. This bit consolidates the information as an optimization. */ +#define QUICLY_PENDING_FLOW_OTHERS_BIT (1 << 7) /** * pending RETIRE_CONNECTION_ID frames to be sent */ @@ -912,6 +908,9 @@ static int schedule_path_challenge_frame(quicly_conn_t *conn, int is_response, c *conn->egress.path_challenge.tail_ref = pending; conn->egress.path_challenge.tail_ref = &pending->next; + + conn->egress.pending_flows |= QUICLY_PENDING_FLOW_OTHERS_BIT; + return 0; } @@ -938,7 +937,7 @@ static size_t local_cid_size(const quicly_conn_t *conn) static void schedule_retire_connection_id_frame(quicly_conn_t *conn, uint64_t sequence) { quicly_retire_cid_push(&conn->egress.retire_cid, sequence); - conn->egress.pending_flows |= QUICLY_PENDING_FLOW_CID_FRAME_BIT; + conn->egress.pending_flows |= QUICLY_PENDING_FLOW_OTHERS_BIT; } static int write_crypto_data(quicly_conn_t *conn, ptls_buffer_t *tlsbuf, size_t epoch_offsets[5]) @@ -993,8 +992,7 @@ static void crypto_handshake(quicly_conn_t *conn, size_t in_epoch, ptls_iovec_t goto Exit; } /* drop 0-RTT write key if 0-RTT is rejected by remote peer */ - if (conn->application != NULL && !conn->application->one_rtt_writable && - conn->application->cipher.egress.key.aead != NULL) { + if (conn->application != NULL && !conn->application->one_rtt_writable && conn->application->cipher.egress.key.aead != NULL) { assert(quicly_is_client(conn)); if (conn->crypto.handshake_properties.client.early_data_acceptance == PTLS_EARLY_DATA_REJECTED) { dispose_cipher(&conn->application->cipher.egress.key); @@ -1196,14 +1194,8 @@ static void destroy_stream(quicly_stream_t *stream, int err) dispose_stream_properties(stream); - if (conn->application != NULL) { - /* The function is normally invoked when receiving a packet, therefore just setting send_ack_at to zero is sufficient to - * trigger the emission of the MAX_STREAMS frame. FWIW, the only case the function is invoked when not receiving a packet is - * when the connection is being closed. In such case, the change will not have any bad side effects. - */ - if (should_send_max_streams(conn, quicly_stream_is_unidirectional(stream->stream_id))) - conn->egress.send_ack_at = 0; - } + if (conn->application != NULL && should_send_max_streams(conn, quicly_stream_is_unidirectional(stream->stream_id))) + conn->egress.pending_flows |= QUICLY_PENDING_FLOW_OTHERS_BIT; free(stream); } @@ -2911,6 +2903,7 @@ static int on_ack_data_blocked(quicly_sentmap_t *map, const quicly_sent_packet_t conn->egress.data_blocked = QUICLY_SENDER_STATE_ACKED; } else if (packet->frames_in_flight && conn->egress.data_blocked == QUICLY_SENDER_STATE_UNACKED) { conn->egress.data_blocked = QUICLY_SENDER_STATE_SEND; + conn->egress.pending_flows |= QUICLY_PENDING_FLOW_OTHERS_BIT; } } @@ -2954,7 +2947,7 @@ static int on_ack_new_token(quicly_sentmap_t *map, const quicly_sent_packet_t *p } if (conn->egress.new_token.num_inflight == 0 && conn->egress.new_token.max_acked < conn->egress.new_token.generation) - conn->egress.pending_flows |= QUICLY_PENDING_FLOW_NEW_TOKEN_BIT; + conn->egress.pending_flows |= QUICLY_PENDING_FLOW_OTHERS_BIT; return 0; } @@ -2968,7 +2961,7 @@ static int on_ack_new_connection_id(quicly_sentmap_t *map, const quicly_sent_pac quicly_local_cid_on_acked(&conn->super.local.cid_set, sequence); } else { if (quicly_local_cid_on_lost(&conn->super.local.cid_set, sequence)) - conn->egress.pending_flows |= QUICLY_PENDING_FLOW_CID_FRAME_BIT; + conn->egress.pending_flows |= QUICLY_PENDING_FLOW_OTHERS_BIT; } return 0; @@ -3641,8 +3634,10 @@ int quicly_is_blocked(quicly_conn_t *conn) return 0; /* schedule the transmission of DATA_BLOCKED frame, if it's new information */ - if (conn->egress.data_blocked == QUICLY_SENDER_STATE_NONE) + if (conn->egress.data_blocked == QUICLY_SENDER_STATE_NONE) { conn->egress.data_blocked = QUICLY_SENDER_STATE_SEND; + conn->egress.pending_flows = QUICLY_PENDING_FLOW_OTHERS_BIT; + } return 1; } @@ -4526,7 +4521,90 @@ static int update_traffic_key_cb(ptls_update_traffic_key_t *self, ptls_t *tls, i /* schedule NEW_CONNECTION_IDs */ size_t size = local_cid_size(conn); if (quicly_local_cid_set_size(&conn->super.local.cid_set, size)) - conn->egress.pending_flows |= QUICLY_PENDING_FLOW_CID_FRAME_BIT; + conn->egress.pending_flows |= QUICLY_PENDING_FLOW_OTHERS_BIT; + } + + return 0; +} + +static int send_other_control_frames(quicly_conn_t *conn, quicly_send_context_t *s) +{ + int ret; + + /* respond to all pending received PATH_CHALLENGE frames */ + if (conn->egress.path_challenge.head != NULL) { + do { + struct st_quicly_pending_path_challenge_t *c = conn->egress.path_challenge.head; + if ((ret = do_allocate_frame(conn, s, QUICLY_PATH_CHALLENGE_FRAME_CAPACITY, ALLOCATE_FRAME_TYPE_NON_ACK_ELICITING)) != + 0) + return ret; + s->dst = quicly_encode_path_challenge_frame(s->dst, c->is_response, c->data); + if (c->is_response) { + ++conn->super.stats.num_frames_sent.path_response; + } else { + ++conn->super.stats.num_frames_sent.path_challenge; + } + conn->egress.path_challenge.head = c->next; + free(c); + } while (conn->egress.path_challenge.head != NULL); + conn->egress.path_challenge.tail_ref = &conn->egress.path_challenge.head; + s->target.full_size = 1; /* datagrams carrying PATH_CHALLENGE / PATH_RESPONSE have to be full-sized */ + } + + /* MAX_STREAMS */ + if ((ret = send_max_streams(conn, 1, s)) != 0) + return ret; + if ((ret = send_max_streams(conn, 0, s)) != 0) + return ret; + + /* MAX_DATA */ + if (should_send_max_data(conn)) { + quicly_sent_t *sent; + if ((ret = allocate_ack_eliciting_frame(conn, s, QUICLY_MAX_DATA_FRAME_CAPACITY, &sent, on_ack_max_data)) != 0) + return ret; + uint64_t new_value = conn->ingress.max_data.bytes_consumed + conn->super.ctx->transport_params.max_data; + s->dst = quicly_encode_max_data_frame(s->dst, new_value); + quicly_maxsender_record(&conn->ingress.max_data.sender, new_value, &sent->data.max_data.args); + ++conn->super.stats.num_frames_sent.max_data; + QUICLY_PROBE(MAX_DATA_SEND, conn, conn->stash.now, new_value); + QUICLY_LOG_CONN(max_data_send, conn, { PTLS_LOG_ELEMENT_UNSIGNED(maximum, new_value); }); + } + + /* DATA_BLOCKED */ + if (conn->egress.data_blocked == QUICLY_SENDER_STATE_SEND && (ret = send_data_blocked(conn, s)) != 0) + return ret; + + /* STREAMS_BLOCKED */ + if ((ret = send_streams_blocked(conn, 1, s)) != 0) + return ret; + if ((ret = send_streams_blocked(conn, 0, s)) != 0) + return ret; + + { /* NEW_CONNECTION_ID */ + size_t i, size = quicly_local_cid_get_size(&conn->super.local.cid_set); + for (i = 0; i < size; i++) { + /* PENDING CIDs are located at the front */ + struct st_quicly_local_cid_t *c = &conn->super.local.cid_set.cids[i]; + if (c->state != QUICLY_LOCAL_CID_STATE_PENDING) + break; + if ((ret = send_new_connection_id(conn, s, c)) != 0) + break; + } + quicly_local_cid_on_sent(&conn->super.local.cid_set, i); + if (ret != 0) + return ret; + } + + { /* RETIRE_CONNECTION_ID */ + size_t i, size = quicly_retire_cid_get_num_pending(&conn->egress.retire_cid); + for (i = 0; i < size; i++) { + uint64_t sequence = conn->egress.retire_cid.sequences[i]; + if ((ret = send_retire_connection_id(conn, s, sequence)) != 0) + break; + } + quicly_retire_cid_shift(&conn->egress.retire_cid, i); + if (ret != 0) + return ret; } return 0; @@ -4666,80 +4744,15 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) goto Exit; resched_stream_data(stream); } - /* respond to all pending received PATH_CHALLENGE frames */ - if (conn->egress.path_challenge.head != NULL) { - do { - struct st_quicly_pending_path_challenge_t *c = conn->egress.path_challenge.head; - if ((ret = do_allocate_frame(conn, s, QUICLY_PATH_CHALLENGE_FRAME_CAPACITY, - ALLOCATE_FRAME_TYPE_NON_ACK_ELICITING)) != 0) - goto Exit; - s->dst = quicly_encode_path_challenge_frame(s->dst, c->is_response, c->data); - if (c->is_response) { - ++conn->super.stats.num_frames_sent.path_response; - } else { - ++conn->super.stats.num_frames_sent.path_challenge; - } - conn->egress.path_challenge.head = c->next; - free(c); - } while (conn->egress.path_challenge.head != NULL); - conn->egress.path_challenge.tail_ref = &conn->egress.path_challenge.head; - s->target.full_size = 1; /* datagrams carrying PATH_CHALLENGE / PATH_RESPONSE have to be full-sized */ - } - /* send max_streams frames */ - if ((ret = send_max_streams(conn, 1, s)) != 0) - goto Exit; - if ((ret = send_max_streams(conn, 0, s)) != 0) - goto Exit; - /* send connection-level flow control frames */ - if (should_send_max_data(conn)) { - quicly_sent_t *sent; - if ((ret = allocate_ack_eliciting_frame(conn, s, QUICLY_MAX_DATA_FRAME_CAPACITY, &sent, on_ack_max_data)) != 0) - goto Exit; - uint64_t new_value = conn->ingress.max_data.bytes_consumed + conn->super.ctx->transport_params.max_data; - s->dst = quicly_encode_max_data_frame(s->dst, new_value); - quicly_maxsender_record(&conn->ingress.max_data.sender, new_value, &sent->data.max_data.args); - ++conn->super.stats.num_frames_sent.max_data; - QUICLY_PROBE(MAX_DATA_SEND, conn, conn->stash.now, new_value); - QUICLY_LOG_CONN(max_data_send, conn, { PTLS_LOG_ELEMENT_UNSIGNED(maximum, new_value); }); - } - if (conn->egress.data_blocked == QUICLY_SENDER_STATE_SEND && (ret = send_data_blocked(conn, s)) != 0) - goto Exit; - /* send streams_blocked frames */ - if ((ret = send_streams_blocked(conn, 1, s)) != 0) - goto Exit; - if ((ret = send_streams_blocked(conn, 0, s)) != 0) + /* send other connection-level control frames, and iff we succeed in sending all of them, clear OTHERS_BIT to + * disable `quicly_send` being called right again to send more control frames */ + if ((ret = send_other_control_frames(conn, s)) != 0) goto Exit; + conn->egress.pending_flows &= ~QUICLY_PENDING_FLOW_OTHERS_BIT; /* send NEW_TOKEN */ if ((conn->egress.pending_flows & QUICLY_PENDING_FLOW_NEW_TOKEN_BIT) != 0 && (ret = send_resumption_token(conn, s)) != 0) goto Exit; - if ((conn->egress.pending_flows & QUICLY_PENDING_FLOW_CID_FRAME_BIT) != 0) { - /* send NEW_CONNECTION_ID */ - size_t i; - size_t size = quicly_local_cid_get_size(&conn->super.local.cid_set); - for (i = 0; i < size; i++) { - /* PENDING CIDs are located at the front */ - struct st_quicly_local_cid_t *c = &conn->super.local.cid_set.cids[i]; - if (c->state != QUICLY_LOCAL_CID_STATE_PENDING) - break; - if ((ret = send_new_connection_id(conn, s, c)) != 0) - break; - } - quicly_local_cid_on_sent(&conn->super.local.cid_set, i); - if (ret != 0) - goto Exit; - /* send RETIRE_CONNECTION_ID */ - size = quicly_retire_cid_get_num_pending(&conn->egress.retire_cid); - for (i = 0; i < size; i++) { - uint64_t sequence = conn->egress.retire_cid.sequences[i]; - if ((ret = send_retire_connection_id(conn, s, sequence)) != 0) - break; - } - quicly_retire_cid_shift(&conn->egress.retire_cid, i); - if (ret != 0) - goto Exit; - conn->egress.pending_flows &= ~QUICLY_PENDING_FLOW_CID_FRAME_BIT; - } } /* send stream-level control frames */ if ((ret = send_stream_control_frames(conn, s)) != 0) @@ -4747,9 +4760,14 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) /* send STREAM frames */ if ((ret = conn->super.ctx->stream_scheduler->do_send(conn->super.ctx->stream_scheduler, conn, s)) != 0) goto Exit; - /* once more, send stream-level control frames, as the state might have changed */ + /* once more, send control frames related to streams, as the state might have changed */ if ((ret = send_stream_control_frames(conn, s)) != 0) goto Exit; + if ((conn->egress.pending_flows & QUICLY_PENDING_FLOW_OTHERS_BIT) != 0) { + if ((ret = send_other_control_frames(conn, s)) != 0) + goto Exit; + conn->egress.pending_flows &= ~QUICLY_PENDING_FLOW_OTHERS_BIT; + } } } @@ -5335,7 +5353,7 @@ static int handle_data_blocked_frame(quicly_conn_t *conn, struct st_quicly_handl quicly_maxsender_request_transmit(&conn->ingress.max_data.sender); if (should_send_max_data(conn)) - conn->egress.send_ack_at = 0; + conn->egress.pending_flows |= QUICLY_PENDING_FLOW_OTHERS_BIT; return 0; } @@ -5384,7 +5402,7 @@ static int handle_streams_blocked_frame(quicly_conn_t *conn, struct st_quicly_ha if (should_send_max_streams(conn, uni)) { quicly_maxsender_t *maxsender = uni ? &conn->ingress.max_streams.uni : &conn->ingress.max_streams.bidi; quicly_maxsender_request_transmit(maxsender); - conn->egress.send_ack_at = 0; + conn->egress.pending_flows |= QUICLY_PENDING_FLOW_OTHERS_BIT; } return 0; @@ -5793,7 +5811,7 @@ static int handle_retire_connection_id_frame(quicly_conn_t *conn, struct st_quic if ((ret = quicly_local_cid_retire(&conn->super.local.cid_set, frame.sequence, &has_pending)) != 0) return ret; if (has_pending) - conn->egress.pending_flows |= QUICLY_PENDING_FLOW_CID_FRAME_BIT; + conn->egress.pending_flows |= QUICLY_PENDING_FLOW_OTHERS_BIT; return 0; } @@ -6385,7 +6403,7 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka break; case QUICLY_EPOCH_1RTT: if (!is_ack_only && should_send_max_data(conn)) - conn->egress.send_ack_at = 0; + conn->egress.pending_flows |= QUICLY_PENDING_FLOW_OTHERS_BIT; break; default: break; @@ -6450,6 +6468,7 @@ int quicly_open_stream(quicly_conn_t *conn, quicly_stream_t **_stream, int uni) stream->streams_blocked = 1; quicly_linklist_insert((uni ? &conn->egress.pending_streams.blocked.uni : &conn->egress.pending_streams.blocked.bidi)->prev, &stream->_send_aux.pending_link.control); + conn->egress.pending_flows |= QUICLY_PENDING_FLOW_OTHERS_BIT; } /* application-layer initialization */ From 0943c9c7646c4ea3593bf48054beddd81d0a6e33 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 8 Jun 2023 14:53:02 +0900 Subject: [PATCH 343/361] oops --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 2a084196b..4491892bd 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -325,7 +325,7 @@ struct st_quicly_conn_t { /** * bit vector indicating if there's any pending crypto data (the insignificant 4 bits), or other non-stream data */ - uint16_t pending_flows; + uint8_t pending_flows; #define QUICLY_PENDING_FLOW_NEW_TOKEN_BIT (1 << 5) #define QUICLY_PENDING_FLOW_HANDSHAKE_DONE_BIT (1 << 6) /* Indicates that PATH_CHALLENGE, PATH_RESPONSE, MAX_STREAMS, MAX_DATA, DATA_BLOCKED, STREAMS_BLOCKED, NEW_CONNECTION_ID _might_ From 8084955393d09307a5a933d37d206dd7c8ef580b Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 8 Jun 2023 14:59:37 +0900 Subject: [PATCH 344/361] reclaim unused bit --- lib/quicly.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index 4491892bd..9b625f0a3 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -326,12 +326,13 @@ struct st_quicly_conn_t { * bit vector indicating if there's any pending crypto data (the insignificant 4 bits), or other non-stream data */ uint8_t pending_flows; -#define QUICLY_PENDING_FLOW_NEW_TOKEN_BIT (1 << 5) -#define QUICLY_PENDING_FLOW_HANDSHAKE_DONE_BIT (1 << 6) +/* The flags below indicate if the respective frames have to be sent or not. There are no false positives. */ +#define QUICLY_PENDING_FLOW_NEW_TOKEN_BIT (1 << 4) +#define QUICLY_PENDING_FLOW_HANDSHAKE_DONE_BIT (1 << 5) /* Indicates that PATH_CHALLENGE, PATH_RESPONSE, MAX_STREAMS, MAX_DATA, DATA_BLOCKED, STREAMS_BLOCKED, NEW_CONNECTION_ID _might_ - * have to be sent. Contrary to NEW_TOKEN_BIT and HANDSHAKE_DONE_BIT, there could be false positives; logic for sending each of - * these frames have the capability of detecting such false positives. This bit consolidates the information as an optimization. */ -#define QUICLY_PENDING_FLOW_OTHERS_BIT (1 << 7) + * have to be sent. There could be false positives; logic for sending each of these frames have the capability of detecting such + * false positives. The purpose of this bit is to consolidate information as an optimization. */ +#define QUICLY_PENDING_FLOW_OTHERS_BIT (1 << 6) /** * pending RETIRE_CONNECTION_ID frames to be sent */ @@ -843,6 +844,8 @@ static void resched_stream_data(quicly_stream_t *stream) if (stream->stream_id < 0) { assert(-4 <= stream->stream_id); uint8_t mask = 1 << -(1 + stream->stream_id); + assert((mask & (QUICLY_PENDING_FLOW_NEW_TOKEN_BIT | QUICLY_PENDING_FLOW_HANDSHAKE_DONE_BIT | + QUICLY_PENDING_FLOW_OTHERS_BIT)) == 0); if (stream->sendstate.pending.num_ranges != 0) { stream->conn->egress.pending_flows |= mask; } else { From 83da103754a371a4542a5a8db3a09f8ddfac95ee Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Wed, 19 Jul 2023 16:21:43 +0900 Subject: [PATCH 345/361] immediate means now, not 1 second later --- examples/echo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/echo.c b/examples/echo.c index 3c368938a..a740e4879 100644 --- a/examples/echo.c +++ b/examples/echo.c @@ -215,7 +215,7 @@ static int run_loop(int fd, quicly_conn_t *client) tv.tv_sec = delta / 1000; tv.tv_usec = (delta % 1000) * 1000; } else { - tv.tv_sec = 1000; + tv.tv_sec = 0; tv.tv_usec = 0; } FD_ZERO(&readfds); From 11f698e9bacd6ce14ed2434174dcca2e171537c4 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 12 Oct 2023 09:46:25 +0900 Subject: [PATCH 346/361] record receive of ECN, send ACK_ECN --- include/quicly.h | 4 ++++ include/quicly/frame.h | 2 +- lib/frame.c | 17 +++++++++++++++-- lib/quicly.c | 38 ++++++++++++++++++++++++++++++++------ 4 files changed, 52 insertions(+), 9 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index 1c63bcfe2..5ddafb255 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -818,6 +818,10 @@ typedef struct st_quicly_decoded_packet_t { uint64_t pn; uint64_t key_phase; } decrypted; + /** + * ECN bits + */ + uint8_t ecn : 2; /** * */ diff --git a/include/quicly/frame.h b/include/quicly/frame.h index 04afd0b7c..6539e5fc7 100644 --- a/include/quicly/frame.h +++ b/include/quicly/frame.h @@ -234,7 +234,7 @@ typedef struct st_quicly_stop_sending_frame_t { static int quicly_decode_stop_sending_frame(const uint8_t **src, const uint8_t *end, quicly_stop_sending_frame_t *frame); -uint8_t *quicly_encode_ack_frame(uint8_t *dst, uint8_t *dst_end, quicly_ranges_t *ranges, uint64_t ack_delay); +uint8_t *quicly_encode_ack_frame(uint8_t *dst, uint8_t *dst_end, quicly_ranges_t *ranges, uint64_t *ecn_counts, uint64_t ack_delay); typedef struct st_quicly_ack_frame_t { uint64_t largest_acknowledged; diff --git a/lib/frame.c b/lib/frame.c index bfcec178c..ddc81eecb 100644 --- a/lib/frame.c +++ b/lib/frame.c @@ -31,7 +31,7 @@ uint8_t *quicly_encode_path_challenge_frame(uint8_t *dst, int is_response, const return dst; } -uint8_t *quicly_encode_ack_frame(uint8_t *dst, uint8_t *dst_end, quicly_ranges_t *ranges, uint64_t ack_delay) +uint8_t *quicly_encode_ack_frame(uint8_t *dst, uint8_t *dst_end, quicly_ranges_t *ranges, uint64_t *ecn_counts, uint64_t ack_delay) { #define WRITE_BLOCK(start, end) \ do { \ @@ -42,12 +42,14 @@ uint8_t *quicly_encode_ack_frame(uint8_t *dst, uint8_t *dst_end, quicly_ranges_t dst = quicly_encodev(dst, _end - _start - 1); \ } while (0) + /* emit ACK_ECN frame if any of the three ECN counts are non-zero */ + uint8_t frame_type = (ecn_counts[0] | ecn_counts[1] | ecn_counts[2]) != 0 ? QUICLY_FRAME_TYPE_ACK_ECN : QUICLY_FRAME_TYPE_ACK; size_t range_index = ranges->num_ranges - 1; assert(ranges->num_ranges != 0); /* number of bytes being emitted without space check are 1 + 8 + 8 + 1 bytes (as defined in QUICLY_ACK_FRAME_CAPACITY) */ - *dst++ = QUICLY_FRAME_TYPE_ACK; + *dst++ = frame_type; dst = quicly_encodev(dst, ranges->ranges[range_index].end - 1); /* largest acknowledged */ dst = quicly_encodev(dst, ack_delay); /* ack delay */ PTLS_BUILD_ASSERT(QUICLY_MAX_ACK_BLOCKS - 1 <= 63); @@ -60,6 +62,17 @@ uint8_t *quicly_encode_ack_frame(uint8_t *dst, uint8_t *dst_end, quicly_ranges_t WRITE_BLOCK(ranges->ranges[range_index].end, ranges->ranges[range_index + 1].start); } + if (frame_type == QUICLY_FRAME_TYPE_ACK_ECN) { + uint8_t buf[24], *p = buf; + for (size_t i = 0; i < 3; ++i) + p = quicly_encodev(p, ecn_counts[i]); + size_t len = p - buf; + if (dst_end - dst < len) + return NULL; + memcpy(dst, buf, len); + dst += len; + } + return dst; #undef WRITE_BLOCK diff --git a/lib/quicly.c b/lib/quicly.c index 2ef1d4d15..649f660f7 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -130,6 +131,10 @@ struct st_quicly_pn_space_t { * number of ACK-eliciting packets that have not been ACKed yet */ uint32_t unacked_count; + /** + * ECN in the order of ECT(0), ECT(1), CE + */ + uint64_t ecn_counts[3]; /** * maximum number of ACK-eliciting packets to be queued before sending an ACK */ @@ -628,6 +633,7 @@ size_t quicly_decode_packet(quicly_context_t *ctx, quicly_decoded_packet_t *pack packet->datagram_size = *off == 0 ? datagram_size : 0; packet->token = ptls_iovec_init(NULL, 0); packet->decrypted.pn = UINT64_MAX; + packet->ecn = 0; /* non-ECT */ /* move the cursor to the second byte */ src += *off + 1; @@ -1388,6 +1394,8 @@ static struct st_quicly_pn_space_t *alloc_pn_space(size_t sz, uint32_t packet_to space->largest_pn_received_at = INT64_MAX; space->next_expected_packet_number = 0; space->unacked_count = 0; + for (size_t i = 0; i < PTLS_ELEMENTSOF(space->ecn_counts); ++i) + space->ecn_counts[i] = 0; space->packet_tolerance = packet_tolerance; space->ignore_order = 0; if (sz != sizeof(*space)) @@ -1426,8 +1434,8 @@ static int record_pn(quicly_ranges_t *ranges, uint64_t pn, int *is_out_of_order) return 0; } -static int record_receipt(struct st_quicly_pn_space_t *space, uint64_t pn, int is_ack_only, int64_t now, int64_t *send_ack_at, - uint64_t *received_out_of_order) +static int record_receipt(struct st_quicly_pn_space_t *space, uint64_t pn, uint8_t ecn, int is_ack_only, int64_t now, + int64_t *send_ack_at, uint64_t *received_out_of_order) { int ret, ack_now, is_out_of_order; @@ -1436,12 +1444,30 @@ static int record_receipt(struct st_quicly_pn_space_t *space, uint64_t pn, int i if (is_out_of_order) *received_out_of_order += 1; - ack_now = is_out_of_order && !space->ignore_order && !is_ack_only; + ack_now = !is_ack_only && ((is_out_of_order && !space->ignore_order) || ecn == IPTOS_ECN_CE); /* update largest_pn_received_at (TODO implement deduplication at an earlier moment?) */ if (space->ack_queue.ranges[space->ack_queue.num_ranges - 1].end == pn + 1) space->largest_pn_received_at = now; + /* ecn */ + switch (ecn) { + case 0: /* NOT-ECT */ + break; + case 1: /* ECT(1) */ + space->ecn_counts[1] += 1; + break; + case 2: /* ECT(0) */ + space->ecn_counts[0] += 1; + break; + case 3: /* CE */ + space->ecn_counts[2] += 1; + break; + default: + assert(!"unexpected ecn flag"); + break; + } + /* if the received packet is ack-eliciting, update / schedule transmission of ACK */ if (!is_ack_only) { space->unacked_count++; @@ -3448,7 +3474,7 @@ static int send_ack(quicly_conn_t *conn, struct st_quicly_pn_space_t *space, qui if ((ret = do_allocate_frame(conn, s, QUICLY_ACK_FRAME_CAPACITY, ALLOCATE_FRAME_TYPE_NON_ACK_ELICITING)) != 0) return ret; uint8_t *dst = s->dst; - dst = quicly_encode_ack_frame(dst, s->dst_end, &space->ack_queue, ack_delay); + dst = quicly_encode_ack_frame(dst, s->dst_end, &space->ack_queue, space->ecn_counts, ack_delay); /* when there's no space, retry with a new MTU-sized packet */ if (dst == NULL) { @@ -6111,7 +6137,7 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * (*conn)->super.stats.num_bytes.received += packet->datagram_size; if ((ret = handle_payload(*conn, QUICLY_EPOCH_INITIAL, payload.base, payload.len, &offending_frame_type, &is_ack_only)) != 0) goto Exit; - if ((ret = record_receipt(&(*conn)->initial->super, pn, 0, (*conn)->stash.now, &(*conn)->egress.send_ack_at, + if ((ret = record_receipt(&(*conn)->initial->super, pn, packet->ecn, 0, (*conn)->stash.now, &(*conn)->egress.send_ack_at, &(*conn)->super.stats.num_packets.received_out_of_order)) != 0) goto Exit; @@ -6349,7 +6375,7 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka if ((ret = handle_payload(conn, epoch, payload.base, payload.len, &offending_frame_type, &is_ack_only)) != 0) goto Exit; if (*space != NULL && conn->super.state < QUICLY_STATE_CLOSING) { - if ((ret = record_receipt(*space, pn, is_ack_only, conn->stash.now, &conn->egress.send_ack_at, + if ((ret = record_receipt(*space, pn, packet->ecn, is_ack_only, conn->stash.now, &conn->egress.send_ack_at, &conn->super.stats.num_packets.received_out_of_order)) != 0) goto Exit; } From da0e57bb8ba1fa5eab55f0322a7d5ea9f0850a31 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 12 Oct 2023 09:36:39 +0900 Subject: [PATCH 347/361] [cli] recognize ECN --- src/cli.c | 88 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 28 deletions(-) diff --git a/src/cli.c b/src/cli.c index 55bc96b74..f2f881af8 100644 --- a/src/cli.c +++ b/src/cli.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -416,6 +417,50 @@ static int on_generate_resumption_token(quicly_generate_resumption_token_t *self static quicly_generate_resumption_token_t generate_resumption_token = {&on_generate_resumption_token}; +/* buf should be ctx.transport_params.max_udp_payload_size bytes long */ +static ssize_t receive_datagram(int fd, void *buf, quicly_address_t *src, uint8_t *ecn) +{ + struct iovec vec = {.iov_base = buf, .iov_len = ctx.transport_params.max_udp_payload_size}; + char cmsgbuf[CMSG_SPACE(sizeof(int) /* == max(V4_TOS, V6_TCLASS) */)] = {}; + struct msghdr mess = { + .msg_name = &src->sa, + .msg_namelen = sizeof(*src), + .msg_iov = &vec, + .msg_iovlen = 1, + .msg_control = cmsgbuf, + .msg_controllen = sizeof(cmsgbuf), + }; + quicly_address_t localaddr = {}; + socklen_t localaddrlen = sizeof(localaddr); + ssize_t rret; + + if (getsockname(fd, &localaddr.sa, &localaddrlen) != 0) + perror("getsockname failed"); + + while ((rret = recvmsg(fd, &mess, 0)) == -1 && errno == EINTR) + ; + + if (rret >= 0) { + *ecn = 0; + for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&mess); cmsg != NULL; cmsg = CMSG_NXTHDR(&mess, cmsg)) { +#ifdef IP_RECVTOS + if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == +#ifdef __APPLE__ + IP_RECVTOS +#else + IP_TOS +#endif + ) { + assert(cmsg->cmsg_len == 1); + *ecn = *(uint8_t *)CMSG_DATA(cmsg) & IPTOS_ECN_MASK; + } +#endif + } + } + + return rret; +} + static void send_packets_default(int fd, struct sockaddr *dest, struct iovec *packets, size_t num_packets) { for (size_t i = 0; i != num_packets; ++i) { @@ -577,20 +622,9 @@ static int run_client(int fd, struct sockaddr *sa, const char *host) enqueue_requests(conn); if (FD_ISSET(fd, &readfds)) { while (1) { - uint8_t buf[ctx.transport_params.max_udp_payload_size]; - struct msghdr mess; - struct sockaddr sa; - struct iovec vec; - memset(&mess, 0, sizeof(mess)); - mess.msg_name = &sa; - mess.msg_namelen = sizeof(sa); - vec.iov_base = buf; - vec.iov_len = sizeof(buf); - mess.msg_iov = &vec; - mess.msg_iovlen = 1; - ssize_t rret; - while ((rret = recvmsg(fd, &mess, 0)) == -1 && errno == EINTR) - ; + uint8_t buf[ctx.transport_params.max_udp_payload_size], ecn; + quicly_address_t src; + ssize_t rret = receive_datagram(fd, buf, &src, &ecn); if (rret <= 0) break; if (verbosity >= 2) @@ -600,7 +634,8 @@ static int run_client(int fd, struct sockaddr *sa, const char *host) quicly_decoded_packet_t packet; if (quicly_decode_packet(&ctx, &packet, buf, rret, &off) == SIZE_MAX) break; - quicly_receive(conn, NULL, &sa, &packet); + packet.ecn = ecn; + quicly_receive(conn, NULL, &src.sa, &packet); if (send_datagram_frame && quicly_connection_is_ready(conn)) { const char *message = "hello datagram!"; ptls_iovec_t datagram = ptls_iovec_init(message, strlen(message)); @@ -751,20 +786,9 @@ static int run_server(int fd, struct sockaddr *sa, socklen_t salen) } while (select(fd + 1, &readfds, NULL, NULL, tv) == -1 && errno == EINTR); if (FD_ISSET(fd, &readfds)) { while (1) { - uint8_t buf[ctx.transport_params.max_udp_payload_size]; - struct msghdr mess; + uint8_t buf[ctx.transport_params.max_udp_payload_size], ecn; quicly_address_t remote; - struct iovec vec; - memset(&mess, 0, sizeof(mess)); - mess.msg_name = &remote.sa; - mess.msg_namelen = sizeof(remote); - vec.iov_base = buf; - vec.iov_len = sizeof(buf); - mess.msg_iov = &vec; - mess.msg_iovlen = 1; - ssize_t rret; - while ((rret = recvmsg(fd, &mess, 0)) == -1 && errno == EINTR) - ; + ssize_t rret = receive_datagram(fd, buf, &remote, &ecn); if (rret == -1) break; if (verbosity >= 2) @@ -774,6 +798,7 @@ static int run_server(int fd, struct sockaddr *sa, socklen_t salen) quicly_decoded_packet_t packet; if (quicly_decode_packet(&ctx, &packet, buf, rret, &off) == SIZE_MAX) break; + packet.ecn = ecn; if (QUICLY_PACKET_IS_LONG_HEADER(packet.octets.base[0])) { if (packet.version != 0 && !quicly_is_supported_version(packet.version)) { uint8_t payload[ctx.transport_params.max_udp_payload_size]; @@ -1482,6 +1507,13 @@ int main(int argc, char **argv) perror("Warning: setsockopt(IP_MTU_DISCOVER) failed"); } #endif +#ifdef IP_RECVTOS + { + int on = 1; + if (setsockopt(fd, IPPROTO_IP, IP_RECVTOS, &on, sizeof(on)) != 0) + perror("Warning: setsockopt(IP_RECVTOS) failed"); + } +#endif return ctx.tls->certificates.count != 0 ? run_server(fd, (void *)&sa, salen) : run_client(fd, (void *)&sa, host); } From 5018f2037f70ee6d7904e305ad369fe26254df50 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 12 Oct 2023 15:18:45 +0900 Subject: [PATCH 348/361] enable ECN on the send side --- include/quicly.h | 8 +++++ include/quicly/frame.h | 1 + lib/defaults.c | 2 ++ lib/frame.c | 9 ++++-- lib/quicly.c | 71 ++++++++++++++++++++++++++++++++++++------ quicly-probes.d | 3 ++ 6 files changed, 81 insertions(+), 13 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index 5ddafb255..105a42bb1 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -330,6 +330,10 @@ struct st_quicly_context_t { * expand client hello so that it does not fit into one datagram */ unsigned expand_client_hello : 1; + /** + * whether to use ECN on the send side; ECN is always on on the receive side + */ + unsigned enable_ecn : 1; /** * */ @@ -1039,6 +1043,10 @@ size_t quicly_send_retry(quicly_context_t *ctx, ptls_aead_context_t *token_encry */ int quicly_send(quicly_conn_t *conn, quicly_address_t *dest, quicly_address_t *src, struct iovec *datagrams, size_t *num_datagrams, void *buf, size_t bufsize); +/** + * returns ECN bits to be set for the packets built by the last invocation of `quicly_send` + */ +uint8_t quicly_send_get_ecn_bits(quicly_conn_t *conn); /** * */ diff --git a/include/quicly/frame.h b/include/quicly/frame.h index 6539e5fc7..6689be6e6 100644 --- a/include/quicly/frame.h +++ b/include/quicly/frame.h @@ -243,6 +243,7 @@ typedef struct st_quicly_ack_frame_t { uint64_t num_gaps; uint64_t ack_block_lengths[QUICLY_ACK_MAX_GAPS + 1]; uint64_t gaps[QUICLY_ACK_MAX_GAPS]; + uint64_t ecn_counts[3]; } quicly_ack_frame_t; int quicly_decode_ack_frame(const uint8_t **src, const uint8_t *end, quicly_ack_frame_t *frame, int is_ack_ecn); diff --git a/lib/defaults.c b/lib/defaults.c index 4a3aeded2..f57704e37 100644 --- a/lib/defaults.c +++ b/lib/defaults.c @@ -50,6 +50,7 @@ const quicly_context_t quicly_spec_context = {NULL, DEFAULT_HANDSHAKE_TIMEOUT_RTT_MULTIPLIER, DEFAULT_MAX_INITIAL_HANDSHAKE_PACKETS, 0, /* enlarge_client_hello */ + 1, /* enable_ecn */ NULL, NULL, /* on_stream_open */ &quicly_default_stream_scheduler, @@ -80,6 +81,7 @@ const quicly_context_t quicly_performant_context = {NULL, DEFAULT_HANDSHAKE_TIMEOUT_RTT_MULTIPLIER, DEFAULT_MAX_INITIAL_HANDSHAKE_PACKETS, 0, /* enlarge_client_hello */ + 1, /* enable_ecn */ NULL, NULL, /* on_stream_open */ &quicly_default_stream_scheduler, diff --git a/lib/frame.c b/lib/frame.c index ddc81eecb..dca34d416 100644 --- a/lib/frame.c +++ b/lib/frame.c @@ -113,11 +113,14 @@ int quicly_decode_ack_frame(const uint8_t **src, const uint8_t *end, quicly_ack_ } if (is_ack_ecn) { - /* just skip ECT(0), ECT(1), ECT-CE counters for the time being */ - for (i = 0; i != 3; ++i) - if (quicly_decodev(src, end) == UINT64_MAX) + for (i = 0; i < PTLS_ELEMENTSOF(frame->ecn_counts); ++i) + if ((frame->ecn_counts[i] = quicly_decodev(src, end)) == UINT64_MAX) goto Error; + } else { + for (i = 0; i < PTLS_ELEMENTSOF(frame->ecn_counts); ++i) + frame->ecn_counts[i] = 0; } + return 0; Error: return QUICLY_TRANSPORT_ERROR_FRAME_ENCODING; diff --git a/lib/quicly.c b/lib/quicly.c index 649f660f7..65a082c5e 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -307,6 +307,13 @@ struct st_quicly_conn_t { * congestion control */ quicly_cc_t cc; + /** + * ECN + */ + struct { + enum en_quicly_ecn_state { QUICLY_ECN_OFF, QUICLY_ECN_ON, QUICLY_ECN_PROBING } state; + uint64_t ce_count; + } ecn; /** * things to be sent at the stream-level, that are not governed by the stream scheduler */ @@ -614,6 +621,13 @@ static int64_t get_sentmap_expiration_time(quicly_conn_t *conn) return quicly_loss_get_sentmap_expiration_time(&conn->egress.loss, conn->super.remote.transport_params.max_ack_delay); } +static void update_ecn_state(quicly_conn_t *conn, enum en_quicly_ecn_state new_state) +{ + conn->egress.ecn.state = new_state; + QUICLY_PROBE(ECN_VALIDATION, conn, conn->stash.now, (int)new_state); + QUICLY_LOG_CONN(ecn_validation, conn, { PTLS_LOG_ELEMENT_SIGNED(state, (int)new_state); }); +} + static void ack_frequency_set_next_update_at(quicly_conn_t *conn) { if (conn->super.remote.transport_params.min_ack_delay_usec != UINT64_MAX) @@ -2239,6 +2253,7 @@ static quicly_conn_t *create_connection(quicly_context_t *ctx, uint32_t protocol conn->egress.ack_frequency.update_at = INT64_MAX; conn->egress.send_ack_at = INT64_MAX; conn->super.ctx->init_cc->cb(conn->super.ctx->init_cc, &conn->egress.cc, initcwnd, conn->stash.now); + conn->egress.ecn.state = conn->super.ctx->enable_ecn ? QUICLY_ECN_PROBING : QUICLY_ECN_OFF; quicly_retire_cid_init(&conn->egress.retire_cid); quicly_linklist_init(&conn->egress.pending_streams.blocked.uni); quicly_linklist_init(&conn->egress.pending_streams.blocked.bidi); @@ -3947,6 +3962,19 @@ static int mark_frames_on_pto(quicly_conn_t *conn, uint8_t ack_epoch, size_t *by return 0; } +static void notify_congestion_to_cc(quicly_conn_t *conn, uint16_t lost_bytes, uint64_t lost_pn) +{ + conn->egress.cc.type->cc_on_lost(&conn->egress.cc, &conn->egress.loss, lost_bytes, lost_pn, conn->egress.packet_number, + conn->stash.now, conn->egress.max_udp_payload_size); + QUICLY_PROBE(CC_CONGESTION, conn, conn->stash.now, lost_pn + 1, conn->egress.loss.sentmap.bytes_in_flight, + conn->egress.cc.cwnd); + QUICLY_LOG_CONN(cc_congestion, conn, { + PTLS_LOG_ELEMENT_UNSIGNED(max_lost_pn, lost_pn + 1); + PTLS_LOG_ELEMENT_UNSIGNED(flight, conn->egress.loss.sentmap.bytes_in_flight); + PTLS_LOG_ELEMENT_UNSIGNED(cwnd, conn->egress.cc.cwnd); + }); +} + static void on_loss_detected(quicly_loss_t *loss, const quicly_sent_packet_t *lost_packet, int is_time_threshold) { quicly_conn_t *conn = (void *)((char *)loss - offsetof(quicly_conn_t, egress.loss)); @@ -3955,21 +3983,12 @@ static void on_loss_detected(quicly_loss_t *loss, const quicly_sent_packet_t *lo if (is_time_threshold) ++conn->super.stats.num_packets.lost_time_threshold; conn->super.stats.num_bytes.lost += lost_packet->cc_bytes_in_flight; - conn->egress.cc.type->cc_on_lost(&conn->egress.cc, &conn->egress.loss, lost_packet->cc_bytes_in_flight, - lost_packet->packet_number, conn->egress.packet_number, conn->stash.now, - conn->egress.max_udp_payload_size); QUICLY_PROBE(PACKET_LOST, conn, conn->stash.now, lost_packet->packet_number, lost_packet->ack_epoch); QUICLY_LOG_CONN(packet_lost, conn, { PTLS_LOG_ELEMENT_UNSIGNED(pn, lost_packet->packet_number); PTLS_LOG_ELEMENT_UNSIGNED(packet_type, lost_packet->ack_epoch); }); - QUICLY_PROBE(CC_CONGESTION, conn, conn->stash.now, lost_packet->packet_number + 1, conn->egress.loss.sentmap.bytes_in_flight, - conn->egress.cc.cwnd); - QUICLY_LOG_CONN(cc_congestion, conn, { - PTLS_LOG_ELEMENT_UNSIGNED(max_lost_pn, lost_packet->packet_number + 1); - PTLS_LOG_ELEMENT_UNSIGNED(flight, conn->egress.loss.sentmap.bytes_in_flight); - PTLS_LOG_ELEMENT_UNSIGNED(cwnd, conn->egress.cc.cwnd); - }); + notify_congestion_to_cc(conn, lost_packet->cc_bytes_in_flight, lost_packet->packet_number); QUICLY_PROBE(QUICTRACE_CC_LOST, conn, conn->stash.now, &conn->egress.loss.rtt, conn->egress.cc.cwnd, conn->egress.loss.sentmap.bytes_in_flight); } @@ -4621,6 +4640,12 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) } } + /* disable ECN if zero packets where acked in the first 3 PTO of the connection during which all sent packets are ECT(0) */ + if (conn->egress.ecn.state == QUICLY_ECN_PROBING && conn->created_at + conn->egress.loss.rtt.smoothed * 3 < conn->stash.now) { + update_ecn_state(conn, QUICLY_ECN_OFF); + /* TODO reset CC? */ + } + s->send_window = calc_send_window(conn, min_packets_to_send * conn->egress.max_udp_payload_size, calc_amplification_limit_allowance(conn), restrict_sending); if (s->send_window == 0) @@ -4906,6 +4931,11 @@ int quicly_send(quicly_conn_t *conn, quicly_address_t *dest, quicly_address_t *s return ret; } +uint8_t quicly_send_get_ecn_bits(quicly_conn_t *conn) +{ + return conn->egress.ecn.state == QUICLY_ECN_OFF ? 0 : 2; /* NON-ECT or ECT(0) */ +} + size_t quicly_send_close_invalid_token(quicly_context_t *ctx, uint32_t protocol_version, ptls_iovec_t dest_cid, ptls_iovec_t src_cid, const char *err_desc, void *datagram) { @@ -5311,6 +5341,27 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload if ((ret = quicly_loss_detect_loss(&conn->egress.loss, conn->stash.now, conn->super.remote.transport_params.max_ack_delay, conn->initial == NULL && conn->handshake == NULL, on_loss_detected)) != 0) return ret; + + /* ECN */ + if (conn->egress.ecn.state != QUICLY_ECN_OFF && largest_newly_acked.pn != UINT64_MAX) { + /* if things look suspicious (ECT(1) count becoming non-zero), turn ECN off */ + if (frame.ecn_counts[1] != 0) + update_ecn_state(conn, QUICLY_ECN_OFF); + /* TODO: maybe compare num_packets.acked vs. sum(ecn_counts) to see if any packet has been received as NON-ECT? */ + + /* ECN validation succeeds if at least one packet is acked using one of the expected marks during the probing period */ + if (conn->egress.ecn.state == QUICLY_ECN_PROBING && frame.ecn_counts[0] + frame.ecn_counts[2] > 0) + update_ecn_state(conn, QUICLY_ECN_ON); + + /* check if ECN_CE has increased; if so, raise a congestion event */ + if (conn->egress.ecn.state != QUICLY_ECN_OFF && frame.ecn_counts[2] > conn->egress.ecn.ce_count) { + conn->egress.ecn.ce_count = frame.ecn_counts[2]; + QUICLY_PROBE(ECN_CONGESTION, conn, conn->stash.now, conn->egress.ecn.ce_count); + QUICLY_LOG_CONN(ecn_congestion, conn, { PTLS_LOG_ELEMENT_UNSIGNED(ce_count, conn->egress.ecn.ce_count); }); + notify_congestion_to_cc(conn, 0, largest_newly_acked.pn); + } + } + setup_next_send(conn); return 0; diff --git a/quicly-probes.d b/quicly-probes.d index 3903b78ff..b9ea45760 100644 --- a/quicly-probes.d +++ b/quicly-probes.d @@ -126,6 +126,9 @@ provider quicly { probe stream_data_blocked_send(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t maximum); probe stream_data_blocked_receive(struct st_quicly_conn_t *conn, int64_t at, int64_t stream_id, uint64_t maximum); + probe ecn_validation(struct st_quicly_conn_t *conn, int64_t at, int ecn_state); + probe ecn_congestion(struct st_quicly_conn_t *conn, int64_t at, uint64_t ce_count); + probe datagram_send(struct st_quicly_conn_t *conn, int64_t at, const void *payload, size_t payload_len); probe datagram_receive(struct st_quicly_conn_t *conn, int64_t at, const void *payload, size_t payload_len); From fe1bc35fbee89011c9d2f07dac4dd447f392758d Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 12 Oct 2023 19:02:59 +0900 Subject: [PATCH 349/361] [cli] enable ECN sender side --- src/cli.c | 71 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/src/cli.c b/src/cli.c index f2f881af8..61f9fa2d8 100644 --- a/src/cli.c +++ b/src/cli.c @@ -461,15 +461,36 @@ static ssize_t receive_datagram(int fd, void *buf, quicly_address_t *src, uint8_ return rret; } -static void send_packets_default(int fd, struct sockaddr *dest, struct iovec *packets, size_t num_packets) +static void set_ecn(struct msghdr *mess, int ecn) +{ + if (ecn != 0) + return; + + struct cmsghdr *cmsg = (struct cmsghdr *)((char *)mess->msg_control + mess->msg_controllen); + + cmsg->cmsg_level = IPPROTO_IP; + cmsg->cmsg_type = IP_TOS; + cmsg->cmsg_len = CMSG_LEN(sizeof(ecn)); + memcpy(CMSG_DATA(cmsg), &ecn, sizeof(ecn)); + + mess->msg_controllen += CMSG_SPACE(sizeof(ecn)); +} + +static void send_packets_default(int fd, struct sockaddr *dest, struct iovec *packets, size_t num_packets, uint8_t ecn) { for (size_t i = 0; i != num_packets; ++i) { - struct msghdr mess; - memset(&mess, 0, sizeof(mess)); - mess.msg_name = dest; - mess.msg_namelen = quicly_get_socklen(dest); - mess.msg_iov = &packets[i]; - mess.msg_iovlen = 1; + char cmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; + struct msghdr mess = { + .msg_name = dest, + .msg_namelen = quicly_get_socklen(dest), + .msg_iov = &packets[i], + .msg_iovlen = 1, + .msg_control = cmsgbuf, + }; + set_ecn(&mess, ecn); + assert(mess.msg_controllen <= sizeof(cmsgbuf)); + if (mess.msg_controllen == 0) + mess.msg_control = NULL; if (verbosity >= 2) hexdump("sendmsg", packets[i].iov_base, packets[i].iov_len); int ret; @@ -486,29 +507,27 @@ static void send_packets_default(int fd, struct sockaddr *dest, struct iovec *pa #define UDP_SEGMENT 103 #endif -static void send_packets_gso(int fd, struct sockaddr *dest, struct iovec *packets, size_t num_packets) +static void send_packets_gso(int fd, struct sockaddr *dest, struct iovec *packets, size_t num_packets, uint8_t ecn) { struct iovec vec = {.iov_base = (void *)packets[0].iov_base, .iov_len = packets[num_packets - 1].iov_base + packets[num_packets - 1].iov_len - packets[0].iov_base}; + char cmsgbuf[CMSG_SPACE(sizeof(uint16_t)) + CMSG_SPACE(sizeof(int))]; /* UDP_SEGMENT and IP_TOS */ struct msghdr mess = { .msg_name = dest, .msg_namelen = quicly_get_socklen(dest), .msg_iov = &vec, .msg_iovlen = 1, + .msg_control = cmsgbuf, }; - - union { - struct cmsghdr hdr; - char buf[CMSG_SPACE(sizeof(uint16_t))]; - } cmsg; if (num_packets != 1) { - cmsg.hdr.cmsg_level = SOL_UDP; - cmsg.hdr.cmsg_type = UDP_SEGMENT; - cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(uint16_t)); - *(uint16_t *)CMSG_DATA(&cmsg.hdr) = packets[0].iov_len; - mess.msg_control = &cmsg; - mess.msg_controllen = (socklen_t)CMSG_SPACE(sizeof(uint16_t)); + struct cmsghdr *cmsg = mess.msg_control; + cmsg->cmsg_level = SOL_UDP; + cmsg->cmsg_type = UDP_SEGMENT; + cmsg->cmsg_len = CMSG_LEN(sizeof(uint16_t)); + *(uint16_t *)CMSG_DATA(cmsg) = packets[0].iov_len; + mess.msg_controllen = CMSG_SPACE(sizeof(uint16_t)); } + set_ecn(&mess, ecn); int ret; while ((ret = sendmsg(fd, &mess, 0)) == -1 && errno == EINTR) @@ -519,12 +538,12 @@ static void send_packets_gso(int fd, struct sockaddr *dest, struct iovec *packet #endif -static void (*send_packets)(int, struct sockaddr *, struct iovec *, size_t) = send_packets_default; +static void (*send_packets)(int, struct sockaddr *, struct iovec *, size_t, uint8_t ecn) = send_packets_default; static void send_one_packet(int fd, struct sockaddr *dest, const void *payload, size_t payload_len) { struct iovec vec = {.iov_base = (void *)payload, .iov_len = payload_len}; - send_packets(fd, dest, &vec, 1); + send_packets(fd, dest, &vec, 1, 0); } static int send_pending(int fd, quicly_conn_t *conn) @@ -536,7 +555,7 @@ static int send_pending(int fd, quicly_conn_t *conn) int ret; if ((ret = quicly_send(conn, &dest, &src, packets, &num_packets, buf, sizeof(buf))) == 0 && num_packets != 0) - send_packets(fd, &dest.sa, packets, num_packets); + send_packets(fd, &dest.sa, packets, num_packets, quicly_send_get_ecn_bits(conn)); return ret; } @@ -1138,8 +1157,10 @@ int main(int argc, char **argv) address_token_aead.dec = ptls_aead_new(&ptls_openssl_aes128gcm, &ptls_openssl_sha256, 0, secret, ""); } - static const struct option longopts[] = { - {"ech-key", required_argument, NULL, 0}, {"ech-configs", required_argument, NULL, 0}, {NULL}}; + static const struct option longopts[] = {{"ech-key", required_argument, NULL, 0}, + {"ech-configs", required_argument, NULL, 0}, + {"disable-ecn", no_argument, NULL, 0}, + {NULL}}; while ((ch = getopt_long(argc, argv, "a:b:B:c:C:Dd:k:Ee:f:Gi:I:K:l:M:m:NnOp:P:Rr:S:s:u:U:Vvw:W:x:X:y:h", longopts, &opt_index)) != -1) { switch (ch) { @@ -1148,6 +1169,8 @@ int main(int argc, char **argv) ech_setup_key(&tlsctx, optarg); } else if (strcmp(longopts[opt_index].name, "ech-configs") == 0) { ech_setup_configs(optarg); + } else if (strcmp(longopts[opt_index].name, "disable-ecn") == 0) { + ctx.enable_ecn = 0; } else { assert(!"unexpected longname"); } From 37d540bcaffca8f20be89640e888e3e21f515a8b Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 13 Oct 2023 10:50:24 +0900 Subject: [PATCH 350/361] update tests --- t/frame.c | 18 ++++++++++++++---- t/test.c | 20 ++++++++++---------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/t/frame.c b/t/frame.c index 297b96149..2e53fc952 100644 --- a/t/frame.c +++ b/t/frame.c @@ -127,12 +127,13 @@ static void test_ack_encode(void) uint8_t buf[256], *end; const uint8_t *src; quicly_ack_frame_t decoded; + uint64_t ecn_counts[3] = {}; quicly_ranges_init(&ranges); quicly_ranges_add(&ranges, 0x12, 0x14); /* encode */ - end = quicly_encode_ack_frame(buf, buf + sizeof(buf), &ranges, 63); + end = quicly_encode_ack_frame(buf, buf + sizeof(buf), &ranges, ecn_counts, 63); ok(end - buf == 5); /* decode */ src = buf + 1; @@ -142,15 +143,21 @@ static void test_ack_encode(void) ok(decoded.num_gaps == 0); ok(decoded.largest_acknowledged == 0x13); ok(decoded.ack_block_lengths[0] == 2); + ok(decoded.ecn_counts[0] == 0); + ok(decoded.ecn_counts[1] == 0); + ok(decoded.ecn_counts[2] == 0); quicly_ranges_add(&ranges, 0x10, 0x11); + ecn_counts[0] = 12; + ecn_counts[1] = 34; + ecn_counts[2] = 56; /* encode */ - end = quicly_encode_ack_frame(buf, buf + sizeof(buf), &ranges, 63); - ok(end - buf == 7); + end = quicly_encode_ack_frame(buf, buf + sizeof(buf), &ranges, ecn_counts, 63); + ok(end - buf == 10); /* decode */ src = buf + 1; - ok(quicly_decode_ack_frame(&src, end, &decoded, 0) == 0); + ok(quicly_decode_ack_frame(&src, end, &decoded, 1) == 0); ok(src == end); ok(decoded.ack_delay == 63); ok(decoded.num_gaps == 1); @@ -158,6 +165,9 @@ static void test_ack_encode(void) ok(decoded.ack_block_lengths[0] == 2); ok(decoded.gaps[0] == 1); ok(decoded.ack_block_lengths[1] == 1); + ok(decoded.ecn_counts[0] == 12); + ok(decoded.ecn_counts[1] == 34); + ok(decoded.ecn_counts[2] == 56); quicly_ranges_clear(&ranges); } diff --git a/t/test.c b/t/test.c index 1f34b1f2d..71300772b 100644 --- a/t/test.c +++ b/t/test.c @@ -520,15 +520,15 @@ static void do_test_record_receipt(size_t epoch) if (epoch == QUICLY_EPOCH_1RTT) { /* 2nd packet triggers an ack */ - ok(record_receipt(space, pn++, 0, now, &send_ack_at, &out_of_order_cnt) == 0); + ok(record_receipt(space, pn++, 0, 0, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == now + QUICLY_DELAYED_ACK_TIMEOUT); now += 1; - ok(record_receipt(space, pn++, 0, now, &send_ack_at, &out_of_order_cnt) == 0); + ok(record_receipt(space, pn++, 0, 0, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == now); now += 1; } else { /* every packet triggers an ack */ - ok(record_receipt(space, pn++, 0, now, &send_ack_at, &out_of_order_cnt) == 0); + ok(record_receipt(space, pn++, 0, 0, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == now); now += 1; } @@ -538,23 +538,23 @@ static void do_test_record_receipt(size_t epoch) send_ack_at = INT64_MAX; /* ack-only packets do not elicit an ack */ - ok(record_receipt(space, pn++, 1, now, &send_ack_at, &out_of_order_cnt) == 0); + ok(record_receipt(space, pn++, 0, 1, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == INT64_MAX); now += 1; - ok(record_receipt(space, pn++, 1, now, &send_ack_at, &out_of_order_cnt) == 0); + ok(record_receipt(space, pn++, 0, 1, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == INT64_MAX); now += 1; pn++; /* gap */ - ok(record_receipt(space, pn++, 1, now, &send_ack_at, &out_of_order_cnt) == 0); + ok(record_receipt(space, pn++, 0, 1, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == INT64_MAX); now += 1; - ok(record_receipt(space, pn++, 1, now, &send_ack_at, &out_of_order_cnt) == 0); + ok(record_receipt(space, pn++, 0, 1, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == INT64_MAX); now += 1; /* gap triggers an ack */ pn += 1; /* gap */ - ok(record_receipt(space, pn++, 0, now, &send_ack_at, &out_of_order_cnt) == 0); + ok(record_receipt(space, pn++, 0, 0, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == now); now += 1; @@ -566,10 +566,10 @@ static void do_test_record_receipt(size_t epoch) if (epoch == QUICLY_EPOCH_1RTT) { space->ignore_order = 1; pn++; /* gap */ - ok(record_receipt(space, pn++, 0, now, &send_ack_at, &out_of_order_cnt) == 0); + ok(record_receipt(space, pn++, 0, 0, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == now + QUICLY_DELAYED_ACK_TIMEOUT); now += 1; - ok(record_receipt(space, pn++, 0, now, &send_ack_at, &out_of_order_cnt) == 0); + ok(record_receipt(space, pn++, 0, 0, now, &send_ack_at, &out_of_order_cnt) == 0); ok(send_ack_at == now); now += 1; } From d522c24a8f6158021183526cc4f9abd42d0bd940 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 13 Oct 2023 10:50:33 +0900 Subject: [PATCH 351/361] adjust comment --- lib/quicly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/quicly.c b/lib/quicly.c index 65a082c5e..a7c9b7f79 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -1464,7 +1464,7 @@ static int record_receipt(struct st_quicly_pn_space_t *space, uint64_t pn, uint8 if (space->ack_queue.ranges[space->ack_queue.num_ranges - 1].end == pn + 1) space->largest_pn_received_at = now; - /* ecn */ + /* increment ecn counters */ switch (ecn) { case 0: /* NOT-ECT */ break; From 5f280dacfd1ecb21442d11b2a16aa9718654a2ee Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 13 Oct 2023 12:58:43 +0900 Subject: [PATCH 352/361] ECN accounting is reported per-epoch --- lib/quicly.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index a7c9b7f79..7ce9e51b0 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -312,7 +312,7 @@ struct st_quicly_conn_t { */ struct { enum en_quicly_ecn_state { QUICLY_ECN_OFF, QUICLY_ECN_ON, QUICLY_ECN_PROBING } state; - uint64_t ce_count; + uint64_t ce_count[QUICLY_NUM_EPOCHS]; } ecn; /** * things to be sent at the stream-level, that are not governed by the stream scheduler @@ -5354,10 +5354,11 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload update_ecn_state(conn, QUICLY_ECN_ON); /* check if ECN_CE has increased; if so, raise a congestion event */ - if (conn->egress.ecn.state != QUICLY_ECN_OFF && frame.ecn_counts[2] > conn->egress.ecn.ce_count) { - conn->egress.ecn.ce_count = frame.ecn_counts[2]; - QUICLY_PROBE(ECN_CONGESTION, conn, conn->stash.now, conn->egress.ecn.ce_count); - QUICLY_LOG_CONN(ecn_congestion, conn, { PTLS_LOG_ELEMENT_UNSIGNED(ce_count, conn->egress.ecn.ce_count); }); + if (conn->egress.ecn.state != QUICLY_ECN_OFF && frame.ecn_counts[2] > conn->egress.ecn.ce_count[state->epoch]) { + conn->egress.ecn.ce_count[state->epoch] = frame.ecn_counts[2]; + QUICLY_PROBE(ECN_CONGESTION, conn, conn->stash.now, conn->egress.ecn.ce_count[state->epoch]); + QUICLY_LOG_CONN(ecn_congestion, conn, + { PTLS_LOG_ELEMENT_UNSIGNED(ce_count, conn->egress.ecn.ce_count[state->epoch]); }); notify_congestion_to_cc(conn, 0, largest_newly_acked.pn); } } From 86df55a717ffe3765ab929245adae742d4f7f5a9 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 13 Oct 2023 13:08:52 +0900 Subject: [PATCH 353/361] retain counts for ECT(0), ECT(1) too, report per-connection metrics --- include/quicly.h | 4 ++++ lib/quicly.c | 23 +++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index 105a42bb1..6b34b5948 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -458,6 +458,10 @@ struct st_quicly_conn_streamgroup_state_t { * Total number of packets received out of order. \ */ \ uint64_t received_out_of_order; \ + /** \ + * connection-wide ACK-ECN counters for ECT(0), ECT(1), CE \ + */ \ + uint64_t ack_ecn_counts[3]; \ } num_packets; \ struct { \ /** \ diff --git a/lib/quicly.c b/lib/quicly.c index 7ce9e51b0..cb40e3f3d 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -312,7 +312,7 @@ struct st_quicly_conn_t { */ struct { enum en_quicly_ecn_state { QUICLY_ECN_OFF, QUICLY_ECN_ON, QUICLY_ECN_PROBING } state; - uint64_t ce_count[QUICLY_NUM_EPOCHS]; + uint64_t counts[QUICLY_NUM_EPOCHS][3]; } ecn; /** * things to be sent at the stream-level, that are not governed by the stream scheduler @@ -5353,12 +5353,23 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload if (conn->egress.ecn.state == QUICLY_ECN_PROBING && frame.ecn_counts[0] + frame.ecn_counts[2] > 0) update_ecn_state(conn, QUICLY_ECN_ON); - /* check if ECN_CE has increased; if so, raise a congestion event */ - if (conn->egress.ecn.state != QUICLY_ECN_OFF && frame.ecn_counts[2] > conn->egress.ecn.ce_count[state->epoch]) { - conn->egress.ecn.ce_count[state->epoch] = frame.ecn_counts[2]; - QUICLY_PROBE(ECN_CONGESTION, conn, conn->stash.now, conn->egress.ecn.ce_count[state->epoch]); + /* check if congestion should be reported */ + int report_congestion = + conn->egress.ecn.state != QUICLY_ECN_OFF && frame.ecn_counts[2] > conn->egress.ecn.counts[state->epoch][2]; + + /* update counters */ + for (size_t i = 0; i < PTLS_ELEMENTSOF(frame.ecn_counts); ++i) { + if (frame.ecn_counts[i] > conn->egress.ecn.counts[state->epoch][i]) { + conn->super.stats.num_packets.ack_ecn_counts[i] = frame.ecn_counts[i] - conn->egress.ecn.counts[state->epoch][i]; + conn->egress.ecn.counts[state->epoch][i] = frame.ecn_counts[i]; + } + } + + /* report congestion */ + if (report_congestion) { + QUICLY_PROBE(ECN_CONGESTION, conn, conn->stash.now, conn->super.stats.num_packets.ack_ecn_counts[2]); QUICLY_LOG_CONN(ecn_congestion, conn, - { PTLS_LOG_ELEMENT_UNSIGNED(ce_count, conn->egress.ecn.ce_count[state->epoch]); }); + { PTLS_LOG_ELEMENT_UNSIGNED(ce_count, conn->super.stats.num_packets.ack_ecn_counts[2]); }); notify_congestion_to_cc(conn, 0, largest_newly_acked.pn); } } From addba2d71c930225a7887743ebe2d00d95259831 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 13 Oct 2023 13:29:03 +0900 Subject: [PATCH 354/361] fix length check --- src/cli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli.c b/src/cli.c index 61f9fa2d8..c5ac5ef81 100644 --- a/src/cli.c +++ b/src/cli.c @@ -451,7 +451,7 @@ static ssize_t receive_datagram(int fd, void *buf, quicly_address_t *src, uint8_ IP_TOS #endif ) { - assert(cmsg->cmsg_len == 1); + assert((char *)CMSG_DATA(cmsg) - (char *)cmsg + 1 == cmsg->cmsg_len); *ecn = *(uint8_t *)CMSG_DATA(cmsg) & IPTOS_ECN_MASK; } #endif From fd2063cbe4aed9dfc063584c71b719ce3383c027 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 13 Oct 2023 13:29:12 +0900 Subject: [PATCH 355/361] [cli] report ack-ecn numbers --- src/cli.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/cli.c b/src/cli.c index c5ac5ef81..d105ad096 100644 --- a/src/cli.c +++ b/src/cli.c @@ -143,10 +143,12 @@ static void dump_stats(FILE *fp, quicly_conn_t *conn) quicly_get_stats(conn, &stats); fprintf(fp, "packets-received: %" PRIu64 ", packets-decryption-failed: %" PRIu64 ", packets-sent: %" PRIu64 - ", packets-lost: %" PRIu64 ", ack-received: %" PRIu64 ", late-acked: %" PRIu64 ", bytes-received: %" PRIu64 - ", bytes-sent: %" PRIu64 ", srtt: %" PRIu32 "\n", + ", packets-lost: %" PRIu64 ", ack-received: %" PRIu64 ", ack-ecn-ect0: %" PRIu64 ", ack-ecn-ect1: %" PRIu64 + ", ack-ecn-ce: %" PRIu64 ", late-acked: %" PRIu64 ", bytes-received: %" PRIu64 ", bytes-sent: %" PRIu64 + ", srtt: %" PRIu32 "\n", stats.num_packets.received, stats.num_packets.decryption_failed, stats.num_packets.sent, stats.num_packets.lost, - stats.num_packets.ack_received, stats.num_packets.late_acked, stats.num_bytes.received, stats.num_bytes.sent, + stats.num_packets.ack_received, stats.num_packets.ack_ecn_counts[0], stats.num_packets.ack_ecn_counts[1], + stats.num_packets.ack_ecn_counts[2], stats.num_packets.late_acked, stats.num_bytes.received, stats.num_bytes.sent, stats.rtt.smoothed); } From 6501ed850563e5c99ecfdb6d5f324d38c60378fe Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 13 Oct 2023 13:46:38 +0900 Subject: [PATCH 356/361] oopses --- lib/quicly.c | 2 +- src/cli.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index cb40e3f3d..633512cce 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -5360,7 +5360,7 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload /* update counters */ for (size_t i = 0; i < PTLS_ELEMENTSOF(frame.ecn_counts); ++i) { if (frame.ecn_counts[i] > conn->egress.ecn.counts[state->epoch][i]) { - conn->super.stats.num_packets.ack_ecn_counts[i] = frame.ecn_counts[i] - conn->egress.ecn.counts[state->epoch][i]; + conn->super.stats.num_packets.ack_ecn_counts[i] += frame.ecn_counts[i] - conn->egress.ecn.counts[state->epoch][i]; conn->egress.ecn.counts[state->epoch][i] = frame.ecn_counts[i]; } } diff --git a/src/cli.c b/src/cli.c index d105ad096..74cf5431e 100644 --- a/src/cli.c +++ b/src/cli.c @@ -465,7 +465,7 @@ static ssize_t receive_datagram(int fd, void *buf, quicly_address_t *src, uint8_ static void set_ecn(struct msghdr *mess, int ecn) { - if (ecn != 0) + if (ecn == 0) return; struct cmsghdr *cmsg = (struct cmsghdr *)((char *)mess->msg_control + mess->msg_controllen); From 4bff19f4dc92ef9fd1c717c7ffbc934c0ff769cb Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 13 Oct 2023 16:48:20 +0900 Subject: [PATCH 357/361] count and report loss episodes due to ECN (i.e., ones did not involve packet loss) --- include/quicly/cc.h | 36 +++++++++++++++++++++++++++++++++--- lib/cc-cubic.c | 2 ++ lib/cc-pico.c | 2 ++ lib/cc-reno.c | 2 ++ lib/quicly.c | 2 ++ src/cli.c | 4 ++-- 6 files changed, 43 insertions(+), 5 deletions(-) diff --git a/include/quicly/cc.h b/include/quicly/cc.h index ca0c0f26e..bc1669c8f 100644 --- a/include/quicly/cc.h +++ b/include/quicly/cc.h @@ -61,6 +61,10 @@ typedef struct st_quicly_cc_t { * Packet number indicating end of recovery period, if in recovery. */ uint64_t recovery_end; + /** + * If the most recent loss episode was signalled by ECN only (i.e., no packet loss). + */ + unsigned episode_by_ecn : 1; /** * State information specific to the congestion controller implementation. */ @@ -130,9 +134,13 @@ typedef struct st_quicly_cc_t { */ uint32_t cwnd_maximum; /** - * Total number of number of loss episodes (congestion window reductions). + * Total number of loss episodes (congestion window reductions). */ uint32_t num_loss_episodes; + /** + * Total number of loss episodes that was reported only by ECN (hence no packet loss). + */ + uint32_t num_ecn_loss_episodes; } quicly_cc_t; struct st_quicly_cc_type_t { @@ -150,8 +158,9 @@ struct st_quicly_cc_type_t { void (*cc_on_acked)(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t largest_acked, uint32_t inflight, uint64_t next_pn, int64_t now, uint32_t max_udp_payload_size); /** - * Called when a packet is detected as lost. |next_pn| is the next unsent packet number, - * used for setting the recovery window. + * Called when a packet is detected as lost. + * @param bytes bytes declared lost, or zero iff ECN_CE is observed + * @param next_pn the next unsent packet number, used for setting the recovery window */ void (*cc_on_lost)(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t lost_pn, uint64_t next_pn, int64_t now, uint32_t max_udp_payload_size); @@ -192,6 +201,27 @@ void quicly_cc_reno_on_lost(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t int64_t now, uint32_t max_udp_payload_size); void quicly_cc_reno_on_persistent_congestion(quicly_cc_t *cc, const quicly_loss_t *loss, int64_t now); void quicly_cc_reno_on_sent(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, int64_t now); +/** + * Updates ECN counter when loss is observed. + */ +static void quicly_cc__update_ecn_episodes(quicly_cc_t *cc, uint32_t lost_bytes, uint64_t lost_pn); + +/* inline definitions */ + +inline void quicly_cc__update_ecn_episodes(quicly_cc_t *cc, uint32_t lost_bytes, uint64_t lost_pn) +{ + /* when it is a new loss episode, initially assume that all losses are due to ECN signalling ... */ + if (lost_pn >= cc->recovery_end) { + ++cc->num_ecn_loss_episodes; + cc->episode_by_ecn = 1; + } + + /* ... but if a loss is observed, decrement the ECN loss episode counter */ + if (lost_bytes != 0 && cc->episode_by_ecn) { + --cc->num_ecn_loss_episodes; + cc->episode_by_ecn = 0; + } +} #ifdef __cplusplus } diff --git a/lib/cc-cubic.c b/lib/cc-cubic.c index e1b848d8b..c1edecbd2 100644 --- a/lib/cc-cubic.c +++ b/lib/cc-cubic.c @@ -105,6 +105,8 @@ static void cubic_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t static void cubic_on_lost(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t lost_pn, uint64_t next_pn, int64_t now, uint32_t max_udp_payload_size) { + quicly_cc__update_ecn_episodes(cc, bytes, lost_pn); + /* Nothing to do if loss is in recovery window. */ if (lost_pn < cc->recovery_end) return; diff --git a/lib/cc-pico.c b/lib/cc-pico.c index 2e520829c..07a8817c2 100644 --- a/lib/cc-pico.c +++ b/lib/cc-pico.c @@ -95,6 +95,8 @@ static void pico_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t b static void pico_on_lost(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t lost_pn, uint64_t next_pn, int64_t now, uint32_t max_udp_payload_size) { + quicly_cc__update_ecn_episodes(cc, bytes, lost_pn); + /* Nothing to do if loss is in recovery window. */ if (lost_pn < cc->recovery_end) return; diff --git a/lib/cc-reno.c b/lib/cc-reno.c index 720a52699..3152d8819 100644 --- a/lib/cc-reno.c +++ b/lib/cc-reno.c @@ -53,6 +53,8 @@ static void reno_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t b void quicly_cc_reno_on_lost(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t lost_pn, uint64_t next_pn, int64_t now, uint32_t max_udp_payload_size) { + quicly_cc__update_ecn_episodes(cc, bytes, lost_pn); + /* Nothing to do if loss is in recovery window. */ if (lost_pn < cc->recovery_end) return; diff --git a/lib/quicly.c b/lib/quicly.c index 633512cce..4ac73ac3d 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3979,6 +3979,8 @@ static void on_loss_detected(quicly_loss_t *loss, const quicly_sent_packet_t *lo { quicly_conn_t *conn = (void *)((char *)loss - offsetof(quicly_conn_t, egress.loss)); + assert(lost_packet->cc_bytes_in_flight != 0); + ++conn->super.stats.num_packets.lost; if (is_time_threshold) ++conn->super.stats.num_packets.lost_time_threshold; diff --git a/src/cli.c b/src/cli.c index 74cf5431e..317360801 100644 --- a/src/cli.c +++ b/src/cli.c @@ -145,11 +145,11 @@ static void dump_stats(FILE *fp, quicly_conn_t *conn) "packets-received: %" PRIu64 ", packets-decryption-failed: %" PRIu64 ", packets-sent: %" PRIu64 ", packets-lost: %" PRIu64 ", ack-received: %" PRIu64 ", ack-ecn-ect0: %" PRIu64 ", ack-ecn-ect1: %" PRIu64 ", ack-ecn-ce: %" PRIu64 ", late-acked: %" PRIu64 ", bytes-received: %" PRIu64 ", bytes-sent: %" PRIu64 - ", srtt: %" PRIu32 "\n", + ", srtt: %" PRIu32 ", num-loss-episodes: %" PRIu32 ", num-ecn-loss-episodes: %" PRIu32 "\n", stats.num_packets.received, stats.num_packets.decryption_failed, stats.num_packets.sent, stats.num_packets.lost, stats.num_packets.ack_received, stats.num_packets.ack_ecn_counts[0], stats.num_packets.ack_ecn_counts[1], stats.num_packets.ack_ecn_counts[2], stats.num_packets.late_acked, stats.num_bytes.received, stats.num_bytes.sent, - stats.rtt.smoothed); + stats.rtt.smoothed, stats.cc.num_loss_episodes, stats.cc.num_ecn_loss_episodes); } static int validate_path(const char *path) From 089ce4fef6cf6cf2c6f3a13f672bb0b1fba4a6c4 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 16 Oct 2023 16:18:22 +0900 Subject: [PATCH 358/361] record and report ECN stats of received packets too --- include/quicly.h | 8 ++++++-- lib/quicly.c | 36 +++++++++++++++++------------------- src/cli.c | 13 ++++++++----- t/test.c | 8 ++++++++ 4 files changed, 39 insertions(+), 26 deletions(-) diff --git a/include/quicly.h b/include/quicly.h index 6b34b5948..cee1dede9 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -459,9 +459,13 @@ struct st_quicly_conn_streamgroup_state_t { */ \ uint64_t received_out_of_order; \ /** \ - * connection-wide ACK-ECN counters for ECT(0), ECT(1), CE \ + * connection-wide counters for ECT(0), ECT(1), CE \ */ \ - uint64_t ack_ecn_counts[3]; \ + uint64_t received_ecn_counts[3]; \ + /** \ + * connection-wide ack-received counters for ECT(0), ECT(1), CE \ + */ \ + uint64_t acked_ecn_counts[3]; \ } num_packets; \ struct { \ /** \ diff --git a/lib/quicly.c b/lib/quicly.c index 4ac73ac3d..cd749258a 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -621,6 +621,14 @@ static int64_t get_sentmap_expiration_time(quicly_conn_t *conn) return quicly_loss_get_sentmap_expiration_time(&conn->egress.loss, conn->super.remote.transport_params.max_ack_delay); } +static size_t get_ecn_index_from_bits(uint8_t bits) +{ + assert(1 <= bits && bits <= 3); + bits -= 1; + bits = bits < 2 ? (bits ^ 1) : bits; + return bits; +} + static void update_ecn_state(quicly_conn_t *conn, enum en_quicly_ecn_state new_state) { conn->egress.ecn.state = new_state; @@ -1465,22 +1473,8 @@ static int record_receipt(struct st_quicly_pn_space_t *space, uint64_t pn, uint8 space->largest_pn_received_at = now; /* increment ecn counters */ - switch (ecn) { - case 0: /* NOT-ECT */ - break; - case 1: /* ECT(1) */ - space->ecn_counts[1] += 1; - break; - case 2: /* ECT(0) */ - space->ecn_counts[0] += 1; - break; - case 3: /* CE */ - space->ecn_counts[2] += 1; - break; - default: - assert(!"unexpected ecn flag"); - break; - } + if (ecn != 0) + space->ecn_counts[get_ecn_index_from_bits(ecn)] += 1; /* if the received packet is ack-eliciting, update / schedule transmission of ACK */ if (!is_ack_only) { @@ -5362,16 +5356,16 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload /* update counters */ for (size_t i = 0; i < PTLS_ELEMENTSOF(frame.ecn_counts); ++i) { if (frame.ecn_counts[i] > conn->egress.ecn.counts[state->epoch][i]) { - conn->super.stats.num_packets.ack_ecn_counts[i] += frame.ecn_counts[i] - conn->egress.ecn.counts[state->epoch][i]; + conn->super.stats.num_packets.acked_ecn_counts[i] += frame.ecn_counts[i] - conn->egress.ecn.counts[state->epoch][i]; conn->egress.ecn.counts[state->epoch][i] = frame.ecn_counts[i]; } } /* report congestion */ if (report_congestion) { - QUICLY_PROBE(ECN_CONGESTION, conn, conn->stash.now, conn->super.stats.num_packets.ack_ecn_counts[2]); + QUICLY_PROBE(ECN_CONGESTION, conn, conn->stash.now, conn->super.stats.num_packets.acked_ecn_counts[2]); QUICLY_LOG_CONN(ecn_congestion, conn, - { PTLS_LOG_ELEMENT_UNSIGNED(ce_count, conn->super.stats.num_packets.ack_ecn_counts[2]); }); + { PTLS_LOG_ELEMENT_UNSIGNED(ce_count, conn->super.stats.num_packets.acked_ecn_counts[2]); }); notify_congestion_to_cc(conn, 0, largest_newly_acked.pn); } } @@ -6199,6 +6193,8 @@ int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr * /* handle the input; we ignore is_ack_only, we consult if there's any output from TLS in response to CH anyways */ (*conn)->super.stats.num_packets.received += 1; + if (packet->ecn != 0) + (*conn)->super.stats.num_packets.received_ecn_counts[get_ecn_index_from_bits(packet->ecn)] += 1; (*conn)->super.stats.num_bytes.received += packet->datagram_size; if ((ret = handle_payload(*conn, QUICLY_EPOCH_INITIAL, payload.base, payload.len, &offending_frame_type, &is_ack_only)) != 0) goto Exit; @@ -6414,6 +6410,8 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka if (conn->super.state == QUICLY_STATE_FIRSTFLIGHT) conn->super.state = QUICLY_STATE_CONNECTED; conn->super.stats.num_packets.received += 1; + if (packet->ecn != 0) + conn->super.stats.num_packets.received_ecn_counts[get_ecn_index_from_bits(packet->ecn)] += 1; /* state updates, that are triggered by the receipt of a packet */ switch (epoch) { diff --git a/src/cli.c b/src/cli.c index 317360801..373516dd9 100644 --- a/src/cli.c +++ b/src/cli.c @@ -142,14 +142,17 @@ static void dump_stats(FILE *fp, quicly_conn_t *conn) quicly_get_stats(conn, &stats); fprintf(fp, - "packets-received: %" PRIu64 ", packets-decryption-failed: %" PRIu64 ", packets-sent: %" PRIu64 + "packets-received: %" PRIu64 ", received-ecn-ect0: %" PRIu64 ", received-ecn-ect1: %" PRIu64 + ", received-ecn-ce: %" PRIu64 ", packets-decryption-failed: %" PRIu64 ", packets-sent: %" PRIu64 ", packets-lost: %" PRIu64 ", ack-received: %" PRIu64 ", ack-ecn-ect0: %" PRIu64 ", ack-ecn-ect1: %" PRIu64 ", ack-ecn-ce: %" PRIu64 ", late-acked: %" PRIu64 ", bytes-received: %" PRIu64 ", bytes-sent: %" PRIu64 ", srtt: %" PRIu32 ", num-loss-episodes: %" PRIu32 ", num-ecn-loss-episodes: %" PRIu32 "\n", - stats.num_packets.received, stats.num_packets.decryption_failed, stats.num_packets.sent, stats.num_packets.lost, - stats.num_packets.ack_received, stats.num_packets.ack_ecn_counts[0], stats.num_packets.ack_ecn_counts[1], - stats.num_packets.ack_ecn_counts[2], stats.num_packets.late_acked, stats.num_bytes.received, stats.num_bytes.sent, - stats.rtt.smoothed, stats.cc.num_loss_episodes, stats.cc.num_ecn_loss_episodes); + stats.num_packets.received, stats.num_packets.received_ecn_counts[0], stats.num_packets.received_ecn_counts[1], + stats.num_packets.received_ecn_counts[2], stats.num_packets.decryption_failed, stats.num_packets.sent, + stats.num_packets.lost, stats.num_packets.ack_received, stats.num_packets.acked_ecn_counts[0], + stats.num_packets.acked_ecn_counts[1], stats.num_packets.acked_ecn_counts[2], stats.num_packets.late_acked, + stats.num_bytes.received, stats.num_bytes.sent, stats.rtt.smoothed, stats.cc.num_loss_episodes, + stats.cc.num_ecn_loss_episodes); } static int validate_path(const char *path) diff --git a/t/test.c b/t/test.c index 71300772b..c9ba21d5c 100644 --- a/t/test.c +++ b/t/test.c @@ -716,6 +716,13 @@ static void test_set_cc(void) ok(strcmp(stats.cc.type->name, "reno") == 0); } +void test_ecn_index_from_bits(void) +{ + ok(get_ecn_index_from_bits(1) == 1); + ok(get_ecn_index_from_bits(2) == 0); + ok(get_ecn_index_from_bits(3) == 2); +} + int main(int argc, char **argv) { static ptls_iovec_t cert; @@ -791,6 +798,7 @@ int main(int argc, char **argv) subtest("lossy", test_lossy); subtest("test-nondecryptable-initial", test_nondecryptable_initial); subtest("set_cc", test_set_cc); + subtest("ecn-index-from-bits", test_ecn_index_from_bits); return done_testing(); } From 1c35a904a1389c1cc5e09c6350ce33f0d8543861 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Mon, 16 Oct 2023 18:52:05 +0900 Subject: [PATCH 359/361] fast conversion as suggested by https://twitter.com/kamedo2/status/1713850668631654472 --- lib/quicly.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index cd749258a..f82084773 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -621,12 +621,13 @@ static int64_t get_sentmap_expiration_time(quicly_conn_t *conn) return quicly_loss_get_sentmap_expiration_time(&conn->egress.loss, conn->super.remote.transport_params.max_ack_delay); } +/** + * converts ECN bits to index in the order of ACK-ECN field (i.e., ECT(0) -> 0, ECT(1) -> 1, CE -> 2) + */ static size_t get_ecn_index_from_bits(uint8_t bits) { assert(1 <= bits && bits <= 3); - bits -= 1; - bits = bits < 2 ? (bits ^ 1) : bits; - return bits; + return (18 >> bits) & 3; } static void update_ecn_state(quicly_conn_t *conn, enum en_quicly_ecn_state new_state) From 418623314e247eaf7bc4c6732542048b2a0a89a8 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Tue, 17 Oct 2023 10:53:23 +0900 Subject: [PATCH 360/361] report number of paths that were ECN-(in)capable; `quicly_stats_t::num_paths` is used in the anticipation of merging multipath #559 --- include/quicly.h | 10 ++++++++++ lib/quicly.c | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/include/quicly.h b/include/quicly.h index cee1dede9..6e54bc2a0 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -493,6 +493,16 @@ struct st_quicly_conn_streamgroup_state_t { */ \ uint64_t stream_data_resent; \ } num_bytes; \ + struct { \ + /** \ + * number of paths that were ECN-capable \ + */ \ + uint64_t ecn_validated; \ + /** \ + * number of paths that were deemed as ECN black holes \ + */ \ + uint64_t ecn_failed; \ + } num_paths; \ /** \ * Total number of each frame being sent / received. \ */ \ diff --git a/lib/quicly.c b/lib/quicly.c index f82084773..d0a00441a 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -632,7 +632,15 @@ static size_t get_ecn_index_from_bits(uint8_t bits) static void update_ecn_state(quicly_conn_t *conn, enum en_quicly_ecn_state new_state) { + assert(new_state == QUICLY_ECN_ON || new_state == QUICLY_ECN_OFF); + conn->egress.ecn.state = new_state; + if (new_state == QUICLY_ECN_ON) { + ++conn->super.stats.num_paths.ecn_validated; + } else { + ++conn->super.stats.num_paths.ecn_failed; + } + QUICLY_PROBE(ECN_VALIDATION, conn, conn->stash.now, (int)new_state); QUICLY_LOG_CONN(ecn_validation, conn, { PTLS_LOG_ELEMENT_SIGNED(state, (int)new_state); }); } From bfca5defc17921291131bc5f24f2270955579488 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 19 Oct 2023 14:06:42 +0900 Subject: [PATCH 361/361] Fix entering hot loop if app opens a stream before the handshake is complete. H2O opens the HTTP/3 control stream when the connection is created. As that happens before the peer grants any stream credit, QUICLY_PENDING_FLOW_OTHERS_BITgets set, and that leads to `quicly_get_first_timeout` return zero whenever there is space in CWND. But because write keys for the application packet number space is unavailable, `quicly_send` cannot make progress. Hence the hot loop. This PR fixes `quicly_get_first_timeout`. The function no longer returns `0` (indicating now) when the write keys for the application packet number space is available. --- lib/quicly.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/quicly.c b/lib/quicly.c index b6a7613a4..920d04b88 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -3097,8 +3097,14 @@ int64_t quicly_get_first_timeout(quicly_conn_t *conn) uint64_t amp_window = calc_amplification_limit_allowance(conn); if (calc_send_window(conn, 0, amp_window, 0) > 0) { - if (conn->egress.pending_flows != 0) - return 0; + if (conn->egress.pending_flows != 0) { + /* crypto streams (as indicated by lower 4 bits) can be sent whenever CWND is available; other flows need application + * packet number space */ + if (conn->application != NULL && conn->application->cipher.egress.key.header_protection != NULL) + return 0; + if ((conn->egress.pending_flows & 0xf) != 0) + return 0; + } if (quicly_linklist_is_linked(&conn->egress.pending_streams.control)) return 0; if (scheduler_can_send(conn))