summaryrefslogtreecommitdiff
path: root/chromium/net/third_party
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/third_party')
-rw-r--r--chromium/net/third_party/mozilla_security_manager/nsNSSCertificateDB.cpp1
-rw-r--r--chromium/net/third_party/quiche/BUILD.gn62
-rw-r--r--chromium/net/third_party/quiche/src/common/platform/api/quiche_optional.h3
-rw-r--r--chromium/net/third_party/quiche/src/common/platform/api/quiche_time_utils.h31
-rw-r--r--chromium/net/third_party/quiche/src/common/platform/api/quiche_time_utils_test.cc53
-rw-r--r--chromium/net/third_party/quiche/src/common/quiche_data_reader.cc10
-rw-r--r--chromium/net/third_party/quiche/src/common/quiche_data_reader.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc177
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h149
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.cc154
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h95
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer_test.cc281
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_test.cc78
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_test.h284
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.cc122
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.h114
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer_test.cc461
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.cc83
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.h35
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer_test.cc15
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc27
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler_test.cc57
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc19
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc38
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc87
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc118
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc24
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc30
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.cc31
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h19
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc140
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc101
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.h14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_test.cc67
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h13
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc29
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc38
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h32
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config_test.cc48
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc12
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.cc22
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc464
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h36
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc390
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.cc20
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h45
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc23
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc23
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h17
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc609
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/http_constants.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc15
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc22
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h12
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc18
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc60
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc572
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.cc31
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc66
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc117
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h55
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc58
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc15
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc16
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc42
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h16
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager_test.cc28
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h15
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc17
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_config.cc195
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_config.h69
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc63
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection.cc1021
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection.h183
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h32
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc1368
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc13
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc20
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc25
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h15
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_default_packet_writer.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_default_packet_writer.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc239
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h56
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc174
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc15
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h20
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_flow_controller.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_framer.cc181
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_framer.h18
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc121
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.cc145
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.h71
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator_test.cc109
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.cc314
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h298
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils_test.cc329
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc154
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h32
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc377
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_writer.h21
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packets.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc111
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h27
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc290
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_session.cc713
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_session.h165
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc92
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream.cc99
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream.h21
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc20
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc18
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc76
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_syscall_wrapper.cc49
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_syscall_wrapper.h49
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_tag.cc31
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_tag.h12
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_tag_test.cc42
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_time.h8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_types.cc19
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_types.h75
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_udp_socket.h11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_posix.cc27
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_test.cc82
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc37
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_utils.cc55
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_utils.h18
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_utils_test.cc47
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc42
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc56
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_versions.cc115
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_versions.h127
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc270
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor_test.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc71
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc81
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc106
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h24
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc71
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc19
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc26
-rw-r--r--chromium/net/third_party/quiche/src/quic/masque/masque_encapsulated_epoll_client.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_client_test.cc9
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc7
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/counting_packet_filter.h43
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.cc25
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h34
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc160
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h128
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.cc87
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h72
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.cc190
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.h203
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint_test.cc251
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc219
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.h68
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_fakes.h162
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_interval_counter.h122
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_interval_counter_test.cc108
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.cc271
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h190
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer_test.cc496
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_packet_writer.cc78
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h113
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc470
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_session.h339
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_session_test.cc680
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc170
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.h142
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc656
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport.cc98
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h84
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport_test.cc163
-rw-r--r--chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc221
-rw-r--r--chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.h119
-rw-r--r--chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier_test.cc183
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc23
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/first_flight.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/mock_clock.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/mock_clock.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.cc28
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.h13
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.cc22
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.h37
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc7
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc49
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.h21
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc24
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h37
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.cc11
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simulator/queue.cc8
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.cc16
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h8
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.cc28
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc31
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h15
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc131
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.cc50
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.h14
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter_test.cc21
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc29
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h1
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler.h41
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler_test.cc18
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.cc13
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder_test.cc16
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler.h56
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler_test.cc18
269 files changed, 12664 insertions, 9670 deletions
diff --git a/chromium/net/third_party/mozilla_security_manager/nsNSSCertificateDB.cpp b/chromium/net/third_party/mozilla_security_manager/nsNSSCertificateDB.cpp
index 7174f9947b7..39e9a6267d3 100644
--- a/chromium/net/third_party/mozilla_security_manager/nsNSSCertificateDB.cpp
+++ b/chromium/net/third_party/mozilla_security_manager/nsNSSCertificateDB.cpp
@@ -44,6 +44,7 @@
#include <secerr.h>
#include "base/logging.h"
+#include "base/notreached.h"
#include "crypto/scoped_nss_types.h"
#include "net/base/net_errors.h"
#include "net/cert/x509_certificate.h"
diff --git a/chromium/net/third_party/quiche/BUILD.gn b/chromium/net/third_party/quiche/BUILD.gn
index 59a75e2132a..a715ea8e2cc 100644
--- a/chromium/net/third_party/quiche/BUILD.gn
+++ b/chromium/net/third_party/quiche/BUILD.gn
@@ -23,6 +23,7 @@ source_set("quiche") {
"src/common/platform/api/quiche_str_cat.h",
"src/common/platform/api/quiche_string_piece.h",
"src/common/platform/api/quiche_text_utils.h",
+ "src/common/platform/api/quiche_time_utils.h",
"src/common/platform/api/quiche_unordered_containers.h",
"src/common/quiche_data_reader.cc",
"src/common/quiche_data_reader.h",
@@ -253,6 +254,8 @@ source_set("quiche") {
"src/quic/core/crypto/transport_parameters.h",
"src/quic/core/frames/quic_ack_frame.cc",
"src/quic/core/frames/quic_ack_frame.h",
+ "src/quic/core/frames/quic_ack_frequency_frame.cc",
+ "src/quic/core/frames/quic_ack_frequency_frame.h",
"src/quic/core/frames/quic_blocked_frame.cc",
"src/quic/core/frames/quic_blocked_frame.h",
"src/quic/core/frames/quic_connection_close_frame.cc",
@@ -431,6 +434,8 @@ source_set("quiche") {
"src/quic/core/quic_interval.h",
"src/quic/core/quic_interval_deque.h",
"src/quic/core/quic_interval_set.h",
+ "src/quic/core/quic_legacy_version_encapsulator.cc",
+ "src/quic/core/quic_legacy_version_encapsulator.h",
"src/quic/core/quic_lru_cache.h",
"src/quic/core/quic_mtu_discovery.cc",
"src/quic/core/quic_mtu_discovery.h",
@@ -548,6 +553,8 @@ source_set("quiche") {
"src/quic/quic_transport/quic_transport_session_interface.h",
"src/quic/quic_transport/quic_transport_stream.cc",
"src/quic/quic_transport/quic_transport_stream.h",
+ "src/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc",
+ "src/quic/quic_transport/web_transport_fingerprint_proof_verifier.h",
"src/spdy/core/fifo_write_scheduler.h",
"src/spdy/core/hpack/hpack_constants.cc",
"src/spdy/core/hpack/hpack_constants.h",
@@ -1230,6 +1237,7 @@ source_set("quiche_tests") {
"src/common/platform/api/quiche_endian_test.cc",
"src/common/platform/api/quiche_str_cat_test.cc",
"src/common/platform/api/quiche_text_utils_test.cc",
+ "src/common/platform/api/quiche_time_utils_test.cc",
"src/quic/core/congestion_control/bbr_sender_test.cc",
"src/quic/core/congestion_control/cubic_bytes_test.cc",
"src/quic/core/congestion_control/general_loss_algorithm_test.cc",
@@ -1329,6 +1337,7 @@ source_set("quiche_tests") {
"src/quic/core/quic_interval_deque_test.cc",
"src/quic/core/quic_interval_set_test.cc",
"src/quic/core/quic_interval_test.cc",
+ "src/quic/core/quic_legacy_version_encapsulator_test.cc",
"src/quic/core/quic_lru_cache_test.cc",
"src/quic/core/quic_network_blackhole_detector_test.cc",
"src/quic/core/quic_one_block_arena_test.cc",
@@ -1374,6 +1383,7 @@ source_set("quiche_tests") {
"src/quic/quic_transport/quic_transport_integration_test.cc",
"src/quic/quic_transport/quic_transport_server_session_test.cc",
"src/quic/quic_transport/quic_transport_stream_test.cc",
+ "src/quic/quic_transport/web_transport_fingerprint_proof_verifier_test.cc",
"src/quic/test_tools/crypto_test_utils_test.cc",
"src/quic/test_tools/mock_quic_time_wait_list_manager.cc",
"src/quic/test_tools/mock_quic_time_wait_list_manager.h",
@@ -1426,58 +1436,6 @@ source_set("quiche_tests") {
"src/spdy/platform/api/spdy_test_helpers.h",
]
- # Disable building Quartc tests on iOS as they appear to be flaky there.
- if (!is_ios) {
- sources += [
- "src/quic/quartc/counting_packet_filter.h",
- "src/quic/quartc/quartc_connection_helper.cc",
- "src/quic/quartc/quartc_connection_helper.h",
- "src/quic/quartc/quartc_crypto_helpers.cc",
- "src/quic/quartc/quartc_crypto_helpers.h",
- "src/quic/quartc/quartc_dispatcher.cc",
- "src/quic/quartc/quartc_dispatcher.h",
- "src/quic/quartc/quartc_endpoint.cc",
- "src/quic/quartc/quartc_endpoint.h",
- "src/quic/quartc/quartc_endpoint_test.cc",
- "src/quic/quartc/quartc_factory.cc",
- "src/quic/quartc/quartc_factory.h",
- "src/quic/quartc/quartc_fakes.h",
- "src/quic/quartc/quartc_interval_counter.h",
- "src/quic/quartc/quartc_interval_counter_test.cc",
- "src/quic/quartc/quartc_multiplexer.cc",
- "src/quic/quartc/quartc_multiplexer.h",
- "src/quic/quartc/quartc_multiplexer_test.cc",
- "src/quic/quartc/quartc_packet_writer.cc",
- "src/quic/quartc/quartc_packet_writer.h",
- "src/quic/quartc/quartc_session.cc",
- "src/quic/quartc/quartc_session.h",
- "src/quic/quartc/quartc_session_test.cc",
- "src/quic/quartc/quartc_stream.cc",
- "src/quic/quartc/quartc_stream.h",
- "src/quic/quartc/quartc_stream_test.cc",
- "src/quic/quartc/simulated_packet_transport.cc",
- "src/quic/quartc/simulated_packet_transport.h",
- "src/quic/quartc/simulated_packet_transport_test.cc",
- "src/quic/quartc/test/bidi_test_runner.cc",
- "src/quic/quartc/test/bidi_test_runner.h",
- "src/quic/quartc/test/quartc_bidi_test.cc",
- "src/quic/quartc/test/quartc_competing_endpoint.cc",
- "src/quic/quartc/test/quartc_competing_endpoint.h",
- "src/quic/quartc/test/quartc_data_source.cc",
- "src/quic/quartc/test/quartc_data_source.h",
- "src/quic/quartc/test/quartc_data_source_test.cc",
- "src/quic/quartc/test/quartc_peer.cc",
- "src/quic/quartc/test/quartc_peer.h",
- "src/quic/quartc/test/quartc_peer_test.cc",
- "src/quic/quartc/test/quic_trace_interceptor.cc",
- "src/quic/quartc/test/quic_trace_interceptor.h",
- "src/quic/quartc/test/random_delay_link.cc",
- "src/quic/quartc/test/random_delay_link.h",
- "src/quic/quartc/test/random_packet_filter.cc",
- "src/quic/quartc/test/random_packet_filter.h",
- ]
- }
-
deps = [
"//net",
"//net:quic_test_tools",
diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_optional.h b/chromium/net/third_party/quiche/src/common/platform/api/quiche_optional.h
index 141c0e49cd8..d5d3dac3538 100644
--- a/chromium/net/third_party/quiche/src/common/platform/api/quiche_optional.h
+++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_optional.h
@@ -13,7 +13,8 @@ namespace quiche {
template <typename T>
using QuicheOptional = QuicheOptionalImpl<T>;
-#define QuicheNullOpt QuicheNullOptImpl
+
+#define QUICHE_NULLOPT QUICHE_NULLOPT_IMPL
} // namespace quiche
diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_time_utils.h b/chromium/net/third_party/quiche/src/common/platform/api/quiche_time_utils.h
new file mode 100644
index 00000000000..7319568172b
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_time_utils.h
@@ -0,0 +1,31 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_COMMON_PLATFORM_API_QUICHE_TIME_UTILS_H_
+#define QUICHE_COMMON_PLATFORM_API_QUICHE_TIME_UTILS_H_
+
+#include <cstdint>
+
+#include "net/quiche/common/platform/impl/quiche_time_utils_impl.h"
+
+namespace quiche {
+
+// Converts a civil time specified in UTC into a number of seconds since the
+// Unix epoch. This function is strict about validity of accepted dates. For
+// instance, it will reject February 29 on non-leap years, or 25 hours in a day.
+// As a notable exception, 60 seconds is accepted to deal with potential leap
+// seconds. If the date predates Unix epoch, nullopt will be returned.
+inline QuicheOptional<int64_t> QuicheUtcDateTimeToUnixSeconds(int year,
+ int month,
+ int day,
+ int hour,
+ int minute,
+ int second) {
+ return QuicheUtcDateTimeToUnixSecondsImpl(year, month, day, hour, minute,
+ second);
+}
+
+} // namespace quiche
+
+#endif // QUICHE_COMMON_PLATFORM_API_QUICHE_TIME_UTILS_H_
diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_time_utils_test.cc b/chromium/net/third_party/quiche/src/common/platform/api/quiche_time_utils_test.cc
new file mode 100644
index 00000000000..3ae296dbd81
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_time_utils_test.cc
@@ -0,0 +1,53 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/common/platform/api/quiche_time_utils.h"
+
+#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_test.h"
+
+namespace quiche {
+namespace {
+
+TEST(QuicheTimeUtilsTest, Basic) {
+ EXPECT_EQ(1, QuicheUtcDateTimeToUnixSeconds(1970, 1, 1, 0, 0, 1));
+ EXPECT_EQ(365 * 86400, QuicheUtcDateTimeToUnixSeconds(1971, 1, 1, 0, 0, 0));
+ // Some arbitrary timestamps closer to the present, compared to the output of
+ // "Date(...).getTime()" from the JavaScript console.
+ EXPECT_EQ(1152966896,
+ QuicheUtcDateTimeToUnixSeconds(2006, 7, 15, 12, 34, 56));
+ EXPECT_EQ(1591130001, QuicheUtcDateTimeToUnixSeconds(2020, 6, 2, 20, 33, 21));
+
+ EXPECT_EQ(QUICHE_NULLOPT,
+ QuicheUtcDateTimeToUnixSeconds(1970, 2, 29, 0, 0, 1));
+ EXPECT_NE(QUICHE_NULLOPT,
+ QuicheUtcDateTimeToUnixSeconds(1972, 2, 29, 0, 0, 1));
+}
+
+TEST(QuicheTimeUtilsTest, Bounds) {
+ EXPECT_EQ(QUICHE_NULLOPT,
+ QuicheUtcDateTimeToUnixSeconds(1970, 1, 32, 0, 0, 1));
+ EXPECT_EQ(QUICHE_NULLOPT,
+ QuicheUtcDateTimeToUnixSeconds(1970, 4, 31, 0, 0, 1));
+ EXPECT_EQ(QUICHE_NULLOPT,
+ QuicheUtcDateTimeToUnixSeconds(1970, 1, 0, 0, 0, 1));
+ EXPECT_EQ(QUICHE_NULLOPT,
+ QuicheUtcDateTimeToUnixSeconds(1970, 13, 1, 0, 0, 1));
+ EXPECT_EQ(QUICHE_NULLOPT,
+ QuicheUtcDateTimeToUnixSeconds(1970, 0, 1, 0, 0, 1));
+ EXPECT_EQ(QUICHE_NULLOPT,
+ QuicheUtcDateTimeToUnixSeconds(1970, 1, 1, 24, 0, 0));
+ EXPECT_EQ(QUICHE_NULLOPT,
+ QuicheUtcDateTimeToUnixSeconds(1970, 1, 1, 0, 60, 0));
+}
+
+TEST(QuicheTimeUtilsTest, LeapSecond) {
+ EXPECT_EQ(QuicheUtcDateTimeToUnixSeconds(2015, 6, 30, 23, 59, 60),
+ QuicheUtcDateTimeToUnixSeconds(2015, 7, 1, 0, 0, 0));
+ EXPECT_EQ(QuicheUtcDateTimeToUnixSeconds(2015, 6, 30, 25, 59, 60),
+ QUICHE_NULLOPT);
+}
+
+} // namespace
+} // namespace quiche
diff --git a/chromium/net/third_party/quiche/src/common/quiche_data_reader.cc b/chromium/net/third_party/quiche/src/common/quiche_data_reader.cc
index 344501378b5..2242fea6437 100644
--- a/chromium/net/third_party/quiche/src/common/quiche_data_reader.cc
+++ b/chromium/net/third_party/quiche/src/common/quiche_data_reader.cc
@@ -10,6 +10,7 @@
#include "net/third_party/quiche/src/common/platform/api/quiche_logging.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
namespace quiche {
@@ -119,6 +120,15 @@ bool QuicheDataReader::ReadTag(uint32_t* tag) {
return ReadBytes(tag, sizeof(*tag));
}
+bool QuicheDataReader::ReadDecimal64(size_t num_digits, uint64_t* result) {
+ quiche::QuicheStringPiece digits;
+ if (!ReadStringPiece(&digits, num_digits)) {
+ return false;
+ }
+
+ return QuicheTextUtils::StringToUint64(digits, result);
+}
+
quiche::QuicheStringPiece QuicheDataReader::ReadRemainingPayload() {
quiche::QuicheStringPiece payload = PeekRemainingPayload();
pos_ = len_;
diff --git a/chromium/net/third_party/quiche/src/common/quiche_data_reader.h b/chromium/net/third_party/quiche/src/common/quiche_data_reader.h
index cf62a164708..f74f90d19e2 100644
--- a/chromium/net/third_party/quiche/src/common/quiche_data_reader.h
+++ b/chromium/net/third_party/quiche/src/common/quiche_data_reader.h
@@ -87,6 +87,11 @@ class QUICHE_EXPORT_PRIVATE QuicheDataReader {
// endian.
bool ReadTag(uint32_t* tag);
+ // Reads a sequence of a fixed number of decimal digits, parses them as an
+ // unsigned integer and returns them as a uint64_t. Forwards internal
+ // iterator on success, may forward it even in case of failure.
+ bool ReadDecimal64(size_t num_digits, uint64_t* result);
+
// Returns the remaining payload as a quiche::QuicheStringPiece.
//
// NOTE: Does not copy but rather references strings in the underlying buffer.
diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc
new file mode 100644
index 00000000000..919f76b3b80
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc
@@ -0,0 +1,177 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h"
+#include <cstdint>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+
+namespace quic {
+
+QuicBatchWriterBase::QuicBatchWriterBase(
+ std::unique_ptr<QuicBatchWriterBuffer> batch_buffer)
+ : write_blocked_(false), batch_buffer_(std::move(batch_buffer)) {}
+
+WriteResult QuicBatchWriterBase::WritePacket(
+ const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ PerPacketOptions* options) {
+ const WriteResult result =
+ InternalWritePacket(buffer, buf_len, self_address, peer_address, options);
+ if (result.status == WRITE_STATUS_BLOCKED) {
+ write_blocked_ = true;
+ }
+ return result;
+}
+
+uint64_t QuicBatchWriterBase::GetReleaseTime(
+ const PerPacketOptions* options) const {
+ DCHECK(SupportsReleaseTime());
+
+ if (options == nullptr) {
+ return 0;
+ }
+
+ if ((options->release_time_delay.IsZero() || options->allow_burst) &&
+ !buffered_writes().empty()) {
+ // Send as soon as possible, but no sooner than the last buffered packet.
+ return buffered_writes().back().release_time;
+ }
+
+ // Send according to the release time delay.
+ return NowInNanosForReleaseTime() +
+ options->release_time_delay.ToMicroseconds() * 1000;
+}
+
+WriteResult QuicBatchWriterBase::InternalWritePacket(
+ const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ PerPacketOptions* options) {
+ if (buf_len > kMaxOutgoingPacketSize) {
+ return WriteResult(WRITE_STATUS_MSG_TOO_BIG, EMSGSIZE);
+ }
+
+ uint64_t release_time = SupportsReleaseTime() ? GetReleaseTime(options) : 0;
+
+ const CanBatchResult can_batch_result = CanBatch(
+ buffer, buf_len, self_address, peer_address, options, release_time);
+
+ bool buffered = false;
+ bool flush = can_batch_result.must_flush;
+
+ if (can_batch_result.can_batch) {
+ QuicBatchWriterBuffer::PushResult push_result =
+ batch_buffer_->PushBufferedWrite(buffer, buf_len, self_address,
+ peer_address, options, release_time);
+ if (push_result.succeeded) {
+ buffered = true;
+ // If there's no space left after the packet is buffered, force a flush.
+ flush = flush || (batch_buffer_->GetNextWriteLocation() == nullptr);
+ } else {
+ // If there's no space without this packet, force a flush.
+ flush = true;
+ }
+ }
+
+ if (!flush) {
+ return WriteResult(WRITE_STATUS_OK, 0);
+ }
+
+ size_t num_buffered_packets = buffered_writes().size();
+ const FlushImplResult flush_result = CheckedFlush();
+ const WriteResult& result = flush_result.write_result;
+ QUIC_DVLOG(1) << "Internally flushed " << flush_result.num_packets_sent
+ << " out of " << num_buffered_packets
+ << " packets. WriteResult=" << result;
+
+ if (result.status != WRITE_STATUS_OK) {
+ if (IsWriteBlockedStatus(result.status)) {
+ return WriteResult(
+ buffered ? WRITE_STATUS_BLOCKED_DATA_BUFFERED : WRITE_STATUS_BLOCKED,
+ result.error_code);
+ }
+
+ // Drop all packets, including the one being written.
+ size_t dropped_packets =
+ buffered ? buffered_writes().size() : buffered_writes().size() + 1;
+
+ batch_buffer().Clear();
+ WriteResult result_with_dropped = result;
+ result_with_dropped.dropped_packets =
+ dropped_packets > std::numeric_limits<uint16_t>::max()
+ ? std::numeric_limits<uint16_t>::max()
+ : static_cast<uint16_t>(dropped_packets);
+ return result_with_dropped;
+ }
+
+ if (!buffered) {
+ QuicBatchWriterBuffer::PushResult push_result =
+ batch_buffer_->PushBufferedWrite(buffer, buf_len, self_address,
+ peer_address, options, release_time);
+ buffered = push_result.succeeded;
+
+ // Since buffered_writes has been emptied, this write must have been
+ // buffered successfully.
+ QUIC_BUG_IF(!buffered) << "Failed to push to an empty batch buffer."
+ << " self_addr:" << self_address.ToString()
+ << ", peer_addr:" << peer_address.ToString()
+ << ", buf_len:" << buf_len;
+ }
+
+ return result;
+}
+
+QuicBatchWriterBase::FlushImplResult QuicBatchWriterBase::CheckedFlush() {
+ if (buffered_writes().empty()) {
+ return FlushImplResult{WriteResult(WRITE_STATUS_OK, 0),
+ /*num_packets_sent=*/0, /*bytes_written=*/0};
+ }
+
+ const FlushImplResult flush_result = FlushImpl();
+
+ // Either flush_result.write_result.status is not WRITE_STATUS_OK, or it is
+ // WRITE_STATUS_OK and batch_buffer is empty.
+ DCHECK(flush_result.write_result.status != WRITE_STATUS_OK ||
+ buffered_writes().empty());
+
+ // Flush should never return WRITE_STATUS_BLOCKED_DATA_BUFFERED.
+ DCHECK(flush_result.write_result.status !=
+ WRITE_STATUS_BLOCKED_DATA_BUFFERED);
+
+ return flush_result;
+}
+
+WriteResult QuicBatchWriterBase::Flush() {
+ size_t num_buffered_packets = buffered_writes().size();
+ FlushImplResult flush_result = CheckedFlush();
+ QUIC_DVLOG(1) << "Externally flushed " << flush_result.num_packets_sent
+ << " out of " << num_buffered_packets
+ << " packets. WriteResult=" << flush_result.write_result;
+
+ if (IsWriteError(flush_result.write_result.status)) {
+ if (buffered_writes().size() > std::numeric_limits<uint16_t>::max()) {
+ flush_result.write_result.dropped_packets =
+ std::numeric_limits<uint16_t>::max();
+ } else {
+ flush_result.write_result.dropped_packets =
+ static_cast<uint16_t>(buffered_writes().size());
+ }
+ // Treat all errors as non-retryable fatal errors. Drop all buffered packets
+ // to avoid sending them and getting the same error again.
+ batch_buffer().Clear();
+ }
+
+ if (flush_result.write_result.status == WRITE_STATUS_BLOCKED) {
+ write_blocked_ = true;
+ }
+ return flush_result.write_result;
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h
new file mode 100644
index 00000000000..0213894f227
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h
@@ -0,0 +1,149 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_BASE_H_
+#define QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_BASE_H_
+
+#include <cstdint>
+#include "net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+
+namespace quic {
+
+// QuicBatchWriterBase implements logic common to all derived batch writers,
+// including maintaining write blockage state and a skeleton implemention of
+// WritePacket().
+// A derived batch writer must override the FlushImpl() function to send all
+// buffered writes in a batch. It must also override the CanBatch() function
+// to control whether/when a WritePacket() call should flush.
+class QUIC_EXPORT_PRIVATE QuicBatchWriterBase : public QuicPacketWriter {
+ public:
+ explicit QuicBatchWriterBase(
+ std::unique_ptr<QuicBatchWriterBuffer> batch_buffer);
+
+ // ATTENTION: If this write triggered a flush, and the flush failed, all
+ // buffered packets will be dropped to allow the next write to work. The
+ // number of dropped packets can be found in WriteResult.dropped_packets.
+ WriteResult WritePacket(const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ PerPacketOptions* options) override;
+
+ bool IsWriteBlocked() const final { return write_blocked_; }
+
+ void SetWritable() final { write_blocked_ = false; }
+
+ QuicByteCount GetMaxPacketSize(
+ const QuicSocketAddress& peer_address) const final {
+ return kMaxOutgoingPacketSize;
+ }
+
+ bool SupportsReleaseTime() const { return false; }
+
+ bool IsBatchMode() const final { return true; }
+
+ QuicPacketBuffer GetNextWriteLocation(
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address) final {
+ // No need to explicitly delete QuicBatchWriterBuffer.
+ return {batch_buffer_->GetNextWriteLocation(), nullptr};
+ }
+
+ WriteResult Flush() final;
+
+ protected:
+ const QuicBatchWriterBuffer& batch_buffer() const { return *batch_buffer_; }
+ QuicBatchWriterBuffer& batch_buffer() { return *batch_buffer_; }
+
+ const QuicCircularDeque<BufferedWrite>& buffered_writes() const {
+ return batch_buffer_->buffered_writes();
+ }
+
+ // Get the current time in nanos which is understood by the sending api for
+ // releasing packets in the future.
+ virtual uint64_t NowInNanosForReleaseTime() const {
+ DCHECK(false) << "Should not be called since release time is unsupported.";
+ return 0;
+ }
+
+ // Given the release delay in |options| and the state of |batch_buffer_|, get
+ // the absolute release time.
+ uint64_t GetReleaseTime(const PerPacketOptions* options) const;
+
+ struct QUIC_EXPORT_PRIVATE CanBatchResult {
+ CanBatchResult(bool can_batch, bool must_flush)
+ : can_batch(can_batch), must_flush(must_flush) {}
+ // Whether this write can be batched with existing buffered writes.
+ bool can_batch;
+ // If |can_batch|, whether the caller must flush after this packet is
+ // buffered.
+ // Always true if not |can_batch|.
+ bool must_flush;
+ };
+
+ // Given the existing buffered writes(in buffered_writes()), whether a new
+ // write(in the arguments) can be batched.
+ virtual CanBatchResult CanBatch(const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ const PerPacketOptions* options,
+ uint64_t release_time) const = 0;
+
+ struct QUIC_EXPORT_PRIVATE FlushImplResult {
+ // The return value of the Flush() interface, which is:
+ // - WriteResult(WRITE_STATUS_OK, <bytes_flushed>) if all buffered writes
+ // were sent successfully.
+ // - WRITE_STATUS_BLOCKED or WRITE_STATUS_ERROR, if the batch write is
+ // blocked or returned an error while sending. If a portion of buffered
+ // writes were sent successfully, |FlushImplResult.num_packets_sent| and
+ // |FlushImplResult.bytes_written| contain the number of successfully sent
+ // packets and their total bytes.
+ WriteResult write_result;
+ int num_packets_sent;
+ // If write_result.status == WRITE_STATUS_OK, |bytes_written| will be equal
+ // to write_result.bytes_written. Otherwise |bytes_written| will be the
+ // number of bytes written before WRITE_BLOCK or WRITE_ERROR happened.
+ int bytes_written;
+ };
+
+ // Send all buffered writes(in buffered_writes()) in a batch.
+ // buffered_writes() is guaranteed to be non-empty when this function is
+ // called.
+ virtual FlushImplResult FlushImpl() = 0;
+
+ private:
+ WriteResult InternalWritePacket(const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ PerPacketOptions* options);
+
+ // Calls FlushImpl() and check its post condition.
+ FlushImplResult CheckedFlush();
+
+ bool write_blocked_;
+ std::unique_ptr<QuicBatchWriterBuffer> batch_buffer_;
+};
+
+// QuicUdpBatchWriter is a batch writer backed by a UDP socket.
+class QUIC_EXPORT_PRIVATE QuicUdpBatchWriter : public QuicBatchWriterBase {
+ public:
+ QuicUdpBatchWriter(std::unique_ptr<QuicBatchWriterBuffer> batch_buffer,
+ int fd)
+ : QuicBatchWriterBase(std::move(batch_buffer)), fd_(fd) {}
+
+ int fd() const { return fd_; }
+
+ private:
+ const int fd_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_BASE_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.cc
new file mode 100644
index 00000000000..62261393256
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h"
+
+#include <sstream>
+
+namespace quic {
+
+QuicBatchWriterBuffer::QuicBatchWriterBuffer() {
+ memset(buffer_, 0, sizeof(buffer_));
+}
+
+void QuicBatchWriterBuffer::Clear() {
+ buffered_writes_.clear();
+}
+
+std::string QuicBatchWriterBuffer::DebugString() const {
+ std::ostringstream os;
+ os << "{ buffer: " << static_cast<const void*>(buffer_)
+ << " buffer_end: " << static_cast<const void*>(buffer_end())
+ << " buffered_writes_.size(): " << buffered_writes_.size()
+ << " next_write_loc: " << static_cast<const void*>(GetNextWriteLocation())
+ << " SizeInUse: " << SizeInUse() << " }";
+ return os.str();
+}
+
+bool QuicBatchWriterBuffer::Invariants() const {
+ // Buffers in buffered_writes_ should not overlap, and collectively they
+ // should cover a continuous prefix of buffer_.
+ const char* next_buffer = buffer_;
+ for (auto iter = buffered_writes_.begin(); iter != buffered_writes_.end();
+ ++iter) {
+ if ((iter->buffer != next_buffer) ||
+ (iter->buffer + iter->buf_len > buffer_end())) {
+ return false;
+ }
+ next_buffer += iter->buf_len;
+ }
+
+ return (next_buffer - buffer_) == SizeInUse();
+}
+
+char* QuicBatchWriterBuffer::GetNextWriteLocation() const {
+ const char* next_loc =
+ buffered_writes_.empty()
+ ? buffer_
+ : buffered_writes_.back().buffer + buffered_writes_.back().buf_len;
+ if (buffer_end() - next_loc < kMaxOutgoingPacketSize) {
+ return nullptr;
+ }
+ return const_cast<char*>(next_loc);
+}
+
+QuicBatchWriterBuffer::PushResult QuicBatchWriterBuffer::PushBufferedWrite(
+ const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ const PerPacketOptions* options,
+ uint64_t release_time) {
+ DCHECK(Invariants());
+ DCHECK_LE(buf_len, kMaxOutgoingPacketSize);
+
+ PushResult result = {/*succeeded=*/false, /*buffer_copied=*/false};
+ char* next_write_location = GetNextWriteLocation();
+ if (next_write_location == nullptr) {
+ return result;
+ }
+
+ if (buffer != next_write_location) {
+ if (IsExternalBuffer(buffer, buf_len)) {
+ memcpy(next_write_location, buffer, buf_len);
+ } else if (IsInternalBuffer(buffer, buf_len)) {
+ memmove(next_write_location, buffer, buf_len);
+ } else {
+ QUIC_BUG << "Buffer[" << static_cast<const void*>(buffer) << ", "
+ << static_cast<const void*>(buffer + buf_len)
+ << ") overlaps with internal buffer["
+ << static_cast<const void*>(buffer_) << ", "
+ << static_cast<const void*>(buffer_end()) << ")";
+ return result;
+ }
+ result.buffer_copied = true;
+ } else {
+ // In place push, do nothing.
+ }
+ buffered_writes_.emplace_back(
+ next_write_location, buf_len, self_address, peer_address,
+ options ? options->Clone() : std::unique_ptr<PerPacketOptions>(),
+ release_time);
+
+ DCHECK(Invariants());
+
+ result.succeeded = true;
+ return result;
+}
+
+void QuicBatchWriterBuffer::UndoLastPush() {
+ if (!buffered_writes_.empty()) {
+ buffered_writes_.pop_back();
+ }
+}
+
+QuicBatchWriterBuffer::PopResult QuicBatchWriterBuffer::PopBufferedWrite(
+ int32_t num_buffered_writes) {
+ DCHECK(Invariants());
+ DCHECK_GE(num_buffered_writes, 0);
+ DCHECK_LE(num_buffered_writes, buffered_writes_.size());
+
+ PopResult result = {/*num_buffers_popped=*/0,
+ /*moved_remaining_buffers=*/false};
+
+ result.num_buffers_popped = std::max<int32_t>(num_buffered_writes, 0);
+ result.num_buffers_popped =
+ std::min<int32_t>(result.num_buffers_popped, buffered_writes_.size());
+ buffered_writes_.pop_front_n(result.num_buffers_popped);
+
+ if (!buffered_writes_.empty()) {
+ // If not all buffered writes are erased, the remaining ones will not cover
+ // a continuous prefix of buffer_. We'll fix it by moving the remaining
+ // buffers to the beginning of buffer_ and adjust the buffer pointers in all
+ // remaining buffered writes.
+ // This should happen very rarely, about once per write block.
+ result.moved_remaining_buffers = true;
+ const char* buffer_before_move = buffered_writes_.front().buffer;
+ size_t buffer_len_to_move = buffered_writes_.back().buffer +
+ buffered_writes_.back().buf_len -
+ buffer_before_move;
+ memmove(buffer_, buffer_before_move, buffer_len_to_move);
+
+ size_t distance_to_move = buffer_before_move - buffer_;
+ for (BufferedWrite& buffered_write : buffered_writes_) {
+ buffered_write.buffer -= distance_to_move;
+ }
+
+ DCHECK_EQ(buffer_, buffered_writes_.front().buffer);
+ }
+ DCHECK(Invariants());
+
+ return result;
+}
+
+size_t QuicBatchWriterBuffer::SizeInUse() const {
+ if (buffered_writes_.empty()) {
+ return 0;
+ }
+
+ return buffered_writes_.back().buffer + buffered_writes_.back().buf_len -
+ buffer_;
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h
new file mode 100644
index 00000000000..a441ec3c9d6
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_BUFFER_H_
+#define QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_BUFFER_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_circular_deque.h"
+#include "net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_aligned.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+
+namespace quic {
+
+// QuicBatchWriterBuffer manages an internal buffer to hold data from multiple
+// packets. Packet data are placed continuously within the internal buffer such
+// that they can be sent by a QuicGsoBatchWriter.
+// This class can also be used by a QuicBatchWriter which uses sendmmsg,
+// although it is not optimized for that use case.
+class QUIC_EXPORT_PRIVATE QuicBatchWriterBuffer {
+ public:
+ QuicBatchWriterBuffer();
+
+ // Clear all buffered writes, but leave the internal buffer intact.
+ void Clear();
+
+ char* GetNextWriteLocation() const;
+
+ // Push a buffered write to the back.
+ struct QUIC_EXPORT_PRIVATE PushResult {
+ bool succeeded;
+ // True in one of the following cases:
+ // 1) The packet buffer is external and copied to the internal buffer, or
+ // 2) The packet buffer is from the internal buffer and moved within it.
+ // This only happens if PopBufferedWrite is called in the middle of a
+ // in-place push.
+ // Only valid if |succeeded| is true.
+ bool buffer_copied;
+ };
+
+ PushResult PushBufferedWrite(const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ const PerPacketOptions* options,
+ uint64_t release_time);
+
+ void UndoLastPush();
+
+ // Pop |num_buffered_writes| buffered writes from the front.
+ // |num_buffered_writes| will be capped to [0, buffered_writes().size()]
+ // before it is used.
+ struct QUIC_EXPORT_PRIVATE PopResult {
+ int32_t num_buffers_popped;
+ // True if after |num_buffers_popped| buffers are popped from front, the
+ // remaining buffers are moved to the beginning of the internal buffer.
+ // This should normally be false.
+ bool moved_remaining_buffers;
+ };
+ PopResult PopBufferedWrite(int32_t num_buffered_writes);
+
+ const QuicCircularDeque<BufferedWrite>& buffered_writes() const {
+ return buffered_writes_;
+ }
+
+ bool IsExternalBuffer(const char* buffer, size_t buf_len) const {
+ return (buffer + buf_len) <= buffer_ || buffer >= buffer_end();
+ }
+ bool IsInternalBuffer(const char* buffer, size_t buf_len) const {
+ return buffer >= buffer_ && (buffer + buf_len) <= buffer_end();
+ }
+
+ // Number of bytes used in |buffer_|.
+ // PushBufferedWrite() increases this; PopBufferedWrite decreases this.
+ size_t SizeInUse() const;
+
+ // Rounded up from |kMaxGsoPacketSize|, which is the maximum allowed
+ // size of a GSO packet.
+ static const size_t kBufferSize = 64 * 1024;
+
+ std::string DebugString() const;
+
+ protected:
+ // Whether the invariants of the buffer are upheld. For debug & test only.
+ bool Invariants() const;
+ const char* const buffer_end() const { return buffer_ + sizeof(buffer_); }
+ QUIC_CACHELINE_ALIGNED char buffer_[kBufferSize];
+ QuicCircularDeque<BufferedWrite> buffered_writes_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_BUFFER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer_test.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer_test.cc
new file mode 100644
index 00000000000..4cdb747ab7c
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer_test.cc
@@ -0,0 +1,281 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h"
+#include <memory>
+#include <string>
+
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+
+namespace quic {
+namespace test {
+namespace {
+
+class QUIC_EXPORT_PRIVATE TestQuicBatchWriterBuffer
+ : public QuicBatchWriterBuffer {
+ public:
+ using QuicBatchWriterBuffer::buffer_;
+ using QuicBatchWriterBuffer::buffered_writes_;
+};
+
+static const size_t kBatchBufferSize = QuicBatchWriterBuffer::kBufferSize;
+
+class QuicBatchWriterBufferTest : public QuicTest {
+ public:
+ QuicBatchWriterBufferTest() { SwitchToNewBuffer(); }
+
+ void SwitchToNewBuffer() {
+ batch_buffer_ = std::make_unique<TestQuicBatchWriterBuffer>();
+ }
+
+ // Fill packet_buffer_ with kMaxOutgoingPacketSize bytes of |c|s.
+ char* FillPacketBuffer(char c) {
+ return FillPacketBuffer(c, packet_buffer_, kMaxOutgoingPacketSize);
+ }
+
+ // Fill |packet_buffer| with kMaxOutgoingPacketSize bytes of |c|s.
+ char* FillPacketBuffer(char c, char* packet_buffer) {
+ return FillPacketBuffer(c, packet_buffer, kMaxOutgoingPacketSize);
+ }
+
+ // Fill |packet_buffer| with |buf_len| bytes of |c|s.
+ char* FillPacketBuffer(char c, char* packet_buffer, size_t buf_len) {
+ memset(packet_buffer, c, buf_len);
+ return packet_buffer;
+ }
+
+ void CheckBufferedWriteContent(int buffered_write_index,
+ char buffer_content,
+ size_t buf_len,
+ const QuicIpAddress& self_addr,
+ const QuicSocketAddress& peer_addr,
+ const PerPacketOptions* options) {
+ const BufferedWrite& buffered_write =
+ batch_buffer_->buffered_writes()[buffered_write_index];
+ EXPECT_EQ(buf_len, buffered_write.buf_len);
+ for (size_t i = 0; i < buf_len; ++i) {
+ EXPECT_EQ(buffer_content, buffered_write.buffer[i]);
+ if (buffer_content != buffered_write.buffer[i]) {
+ break;
+ }
+ }
+ EXPECT_EQ(self_addr, buffered_write.self_address);
+ EXPECT_EQ(peer_addr, buffered_write.peer_address);
+ if (options == nullptr) {
+ EXPECT_EQ(nullptr, buffered_write.options);
+ } else {
+ EXPECT_EQ(options->release_time_delay,
+ buffered_write.options->release_time_delay);
+ }
+ }
+
+ protected:
+ std::unique_ptr<TestQuicBatchWriterBuffer> batch_buffer_;
+ QuicIpAddress self_addr_;
+ QuicSocketAddress peer_addr_;
+ uint64_t release_time_ = 0;
+ char packet_buffer_[kMaxOutgoingPacketSize];
+};
+
+class BufferSizeSequence {
+ public:
+ explicit BufferSizeSequence(
+ std::vector<std::pair<std::vector<size_t>, size_t>> stages)
+ : stages_(std::move(stages)),
+ total_buf_len_(0),
+ stage_index_(0),
+ sequence_index_(0) {}
+
+ size_t Next() {
+ const std::vector<size_t>& seq = stages_[stage_index_].first;
+ size_t buf_len = seq[sequence_index_++ % seq.size()];
+ total_buf_len_ += buf_len;
+ if (stages_[stage_index_].second <= total_buf_len_) {
+ stage_index_ = std::min(stage_index_ + 1, stages_.size() - 1);
+ }
+ return buf_len;
+ }
+
+ private:
+ const std::vector<std::pair<std::vector<size_t>, size_t>> stages_;
+ size_t total_buf_len_;
+ size_t stage_index_;
+ size_t sequence_index_;
+};
+
+// Test in-place pushes. A in-place push is a push with a buffer address that is
+// equal to the result of GetNextWriteLocation().
+TEST_F(QuicBatchWriterBufferTest, InPlacePushes) {
+ std::vector<BufferSizeSequence> buffer_size_sequences = {
+ // Push large writes until the buffer is near full, then switch to 1-byte
+ // writes. This covers the edge cases when detecting insufficient buffer.
+ BufferSizeSequence({{{1350}, kBatchBufferSize - 3000}, {{1}, 1e6}}),
+ // A sequence that looks real.
+ BufferSizeSequence({{{1, 39, 97, 150, 1350, 1350, 1350, 1350}, 1e6}}),
+ };
+
+ for (auto& buffer_size_sequence : buffer_size_sequences) {
+ SwitchToNewBuffer();
+ int64_t num_push_failures = 0;
+
+ while (batch_buffer_->SizeInUse() < kBatchBufferSize) {
+ size_t buf_len = buffer_size_sequence.Next();
+ const bool has_enough_space =
+ (kBatchBufferSize - batch_buffer_->SizeInUse() >=
+ kMaxOutgoingPacketSize);
+
+ char* buffer = batch_buffer_->GetNextWriteLocation();
+
+ if (has_enough_space) {
+ EXPECT_EQ(batch_buffer_->buffer_ + batch_buffer_->SizeInUse(), buffer);
+ } else {
+ EXPECT_EQ(nullptr, buffer);
+ }
+
+ SCOPED_TRACE(testing::Message()
+ << "Before Push: buf_len=" << buf_len
+ << ", has_enough_space=" << has_enough_space
+ << ", batch_buffer=" << batch_buffer_->DebugString());
+
+ auto push_result = batch_buffer_->PushBufferedWrite(
+ buffer, buf_len, self_addr_, peer_addr_, nullptr, release_time_);
+ if (!push_result.succeeded) {
+ ++num_push_failures;
+ }
+ EXPECT_EQ(has_enough_space, push_result.succeeded);
+ EXPECT_FALSE(push_result.buffer_copied);
+ if (!has_enough_space) {
+ break;
+ }
+ }
+ // Expect one and only one failure from the final push operation.
+ EXPECT_EQ(1, num_push_failures);
+ }
+}
+
+// Test some in-place pushes mixed with pushes with external buffers.
+TEST_F(QuicBatchWriterBufferTest, MixedPushes) {
+ // First, a in-place push.
+ char* buffer = batch_buffer_->GetNextWriteLocation();
+ auto push_result = batch_buffer_->PushBufferedWrite(
+ FillPacketBuffer('A', buffer), kDefaultMaxPacketSize, self_addr_,
+ peer_addr_, nullptr, release_time_);
+ EXPECT_TRUE(push_result.succeeded);
+ EXPECT_FALSE(push_result.buffer_copied);
+ CheckBufferedWriteContent(0, 'A', kDefaultMaxPacketSize, self_addr_,
+ peer_addr_, nullptr);
+
+ // Then a push with external buffer.
+ push_result = batch_buffer_->PushBufferedWrite(
+ FillPacketBuffer('B'), kDefaultMaxPacketSize, self_addr_, peer_addr_,
+ nullptr, release_time_);
+ EXPECT_TRUE(push_result.succeeded);
+ EXPECT_TRUE(push_result.buffer_copied);
+ CheckBufferedWriteContent(1, 'B', kDefaultMaxPacketSize, self_addr_,
+ peer_addr_, nullptr);
+
+ // Then another in-place push.
+ buffer = batch_buffer_->GetNextWriteLocation();
+ push_result = batch_buffer_->PushBufferedWrite(
+ FillPacketBuffer('C', buffer), kDefaultMaxPacketSize, self_addr_,
+ peer_addr_, nullptr, release_time_);
+ EXPECT_TRUE(push_result.succeeded);
+ EXPECT_FALSE(push_result.buffer_copied);
+ CheckBufferedWriteContent(2, 'C', kDefaultMaxPacketSize, self_addr_,
+ peer_addr_, nullptr);
+
+ // Then another push with external buffer.
+ push_result = batch_buffer_->PushBufferedWrite(
+ FillPacketBuffer('D'), kDefaultMaxPacketSize, self_addr_, peer_addr_,
+ nullptr, release_time_);
+ EXPECT_TRUE(push_result.succeeded);
+ EXPECT_TRUE(push_result.buffer_copied);
+ CheckBufferedWriteContent(3, 'D', kDefaultMaxPacketSize, self_addr_,
+ peer_addr_, nullptr);
+}
+
+TEST_F(QuicBatchWriterBufferTest, PopAll) {
+ const int kNumBufferedWrites = 10;
+ for (int i = 0; i < kNumBufferedWrites; ++i) {
+ EXPECT_TRUE(batch_buffer_
+ ->PushBufferedWrite(packet_buffer_, kDefaultMaxPacketSize,
+ self_addr_, peer_addr_, nullptr,
+ release_time_)
+ .succeeded);
+ }
+ EXPECT_EQ(kNumBufferedWrites, batch_buffer_->buffered_writes().size());
+
+ auto pop_result = batch_buffer_->PopBufferedWrite(kNumBufferedWrites);
+ EXPECT_EQ(0, batch_buffer_->buffered_writes().size());
+ EXPECT_EQ(kNumBufferedWrites, pop_result.num_buffers_popped);
+ EXPECT_FALSE(pop_result.moved_remaining_buffers);
+}
+
+TEST_F(QuicBatchWriterBufferTest, PopPartial) {
+ const int kNumBufferedWrites = 10;
+ for (int i = 0; i < kNumBufferedWrites; ++i) {
+ EXPECT_TRUE(batch_buffer_
+ ->PushBufferedWrite(FillPacketBuffer('A' + i),
+ kDefaultMaxPacketSize - i, self_addr_,
+ peer_addr_, nullptr, release_time_)
+ .succeeded);
+ }
+
+ for (int i = 0;
+ i < kNumBufferedWrites && !batch_buffer_->buffered_writes().empty();
+ ++i) {
+ const size_t size_before_pop = batch_buffer_->buffered_writes().size();
+ const size_t expect_size_after_pop =
+ size_before_pop < i ? 0 : size_before_pop - i;
+ batch_buffer_->PopBufferedWrite(i);
+ ASSERT_EQ(expect_size_after_pop, batch_buffer_->buffered_writes().size());
+ const char first_write_content =
+ 'A' + kNumBufferedWrites - expect_size_after_pop;
+ const size_t first_write_len =
+ kDefaultMaxPacketSize - kNumBufferedWrites + expect_size_after_pop;
+ for (int j = 0; j < expect_size_after_pop; ++j) {
+ CheckBufferedWriteContent(j, first_write_content + j, first_write_len - j,
+ self_addr_, peer_addr_, nullptr);
+ }
+ }
+}
+
+TEST_F(QuicBatchWriterBufferTest, InPlacePushWithPops) {
+ // First, a in-place push.
+ char* buffer = batch_buffer_->GetNextWriteLocation();
+ const size_t first_packet_len = 2;
+ auto push_result = batch_buffer_->PushBufferedWrite(
+ FillPacketBuffer('A', buffer, first_packet_len), first_packet_len,
+ self_addr_, peer_addr_, nullptr, release_time_);
+ EXPECT_TRUE(push_result.succeeded);
+ EXPECT_FALSE(push_result.buffer_copied);
+ CheckBufferedWriteContent(0, 'A', first_packet_len, self_addr_, peer_addr_,
+ nullptr);
+
+ // Simulate the case where the writer wants to do another in-place push, but
+ // can't do so because it can't be batched with the first buffer.
+ buffer = batch_buffer_->GetNextWriteLocation();
+ const size_t second_packet_len = 1350;
+
+ // Flush the first buffer.
+ auto pop_result = batch_buffer_->PopBufferedWrite(1);
+ EXPECT_EQ(1, pop_result.num_buffers_popped);
+ EXPECT_FALSE(pop_result.moved_remaining_buffers);
+
+ // Now the second push.
+ push_result = batch_buffer_->PushBufferedWrite(
+ FillPacketBuffer('B', buffer, second_packet_len), second_packet_len,
+ self_addr_, peer_addr_, nullptr, release_time_);
+ EXPECT_TRUE(push_result.succeeded);
+ EXPECT_TRUE(push_result.buffer_copied);
+ CheckBufferedWriteContent(0, 'B', second_packet_len, self_addr_, peer_addr_,
+ nullptr);
+}
+
+} // namespace
+} // namespace test
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_test.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_test.cc
new file mode 100644
index 00000000000..583b2485c4c
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_test.cc
@@ -0,0 +1,78 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_test.h"
+#include "net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.h"
+#include "net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.h"
+
+namespace quic {
+namespace test {
+namespace {
+
+class QuicGsoBatchWriterIOTestDelegate
+ : public QuicUdpBatchWriterIOTestDelegate {
+ public:
+ bool ShouldSkip(const QuicUdpBatchWriterIOTestParams& params) override {
+ QuicUdpSocketApi socket_api;
+ int fd =
+ socket_api.Create(params.address_family,
+ /*receive_buffer_size=*/kDefaultSocketReceiveBuffer,
+ /*send_buffer_size=*/kDefaultSocketReceiveBuffer);
+ if (fd < 0) {
+ QUIC_LOG(ERROR) << "CreateSocket() failed: " << strerror(errno);
+ return false; // Let the test fail rather than skip it.
+ }
+ const bool gso_not_supported =
+ QuicLinuxSocketUtils::GetUDPSegmentSize(fd) < 0;
+ socket_api.Destroy(fd);
+
+ if (gso_not_supported) {
+ QUIC_LOG(WARNING) << "Test skipped since GSO is not supported.";
+ return true;
+ }
+
+ QUIC_LOG(WARNING) << "OK: GSO is supported.";
+ return false;
+ }
+
+ void ResetWriter(int fd) override {
+ writer_ = std::make_unique<QuicGsoBatchWriter>(
+ std::make_unique<QuicBatchWriterBuffer>(), fd);
+ }
+
+ QuicUdpBatchWriter* GetWriter() override { return writer_.get(); }
+
+ private:
+ std::unique_ptr<QuicGsoBatchWriter> writer_;
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ QuicGsoBatchWriterTest,
+ QuicUdpBatchWriterIOTest,
+ testing::ValuesIn(
+ MakeQuicBatchWriterTestParams<QuicGsoBatchWriterIOTestDelegate>()));
+
+class QuicSendmmsgBatchWriterIOTestDelegate
+ : public QuicUdpBatchWriterIOTestDelegate {
+ public:
+ void ResetWriter(int fd) override {
+ writer_ = std::make_unique<QuicSendmmsgBatchWriter>(
+ std::make_unique<QuicBatchWriterBuffer>(), fd);
+ }
+
+ QuicUdpBatchWriter* GetWriter() override { return writer_.get(); }
+
+ private:
+ std::unique_ptr<QuicSendmmsgBatchWriter> writer_;
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ QuicSendmmsgBatchWriterTest,
+ QuicUdpBatchWriterIOTest,
+ testing::ValuesIn(MakeQuicBatchWriterTestParams<
+ QuicSendmmsgBatchWriterIOTestDelegate>()));
+
+} // namespace
+} // namespace test
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_test.h b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_test.h
new file mode 100644
index 00000000000..b4f36b9f3ca
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_test.h
@@ -0,0 +1,284 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_TEST_H_
+#define QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_TEST_H_
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <iostream>
+#include <utility>
+
+#include "net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h"
+#include "net/third_party/quiche/src/quic/core/quic_udp_socket.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+
+namespace quic {
+namespace test {
+
+static bool IsAddressFamilySupported(int address_family) {
+ static auto check_function = [](int address_family) {
+ int fd = socket(address_family, SOCK_STREAM, 0);
+ if (fd < 0) {
+ QUIC_LOG(ERROR) << "address_family not supported: " << address_family
+ << ", error: " << strerror(errno);
+ EXPECT_EQ(EAFNOSUPPORT, errno);
+ return false;
+ }
+ close(fd);
+ return true;
+ };
+
+ if (address_family == AF_INET) {
+ static const bool ipv4_supported = check_function(AF_INET);
+ return ipv4_supported;
+ }
+
+ static const bool ipv6_supported = check_function(AF_INET6);
+ return ipv6_supported;
+}
+
+static bool CreateSocket(int family, QuicSocketAddress* address, int* fd) {
+ if (family == AF_INET) {
+ *address = QuicSocketAddress(QuicIpAddress::Loopback4(), 0);
+ } else {
+ DCHECK_EQ(family, AF_INET6);
+ *address = QuicSocketAddress(QuicIpAddress::Loopback6(), 0);
+ }
+
+ QuicUdpSocketApi socket_api;
+ *fd = socket_api.Create(family,
+ /*receive_buffer_size=*/kDefaultSocketReceiveBuffer,
+ /*send_buffer_size=*/kDefaultSocketReceiveBuffer);
+ if (*fd < 0) {
+ QUIC_LOG(ERROR) << "CreateSocket() failed: " << strerror(errno);
+ return false;
+ }
+ socket_api.EnableDroppedPacketCount(*fd);
+
+ if (!socket_api.Bind(*fd, *address)) {
+ QUIC_LOG(ERROR) << "Bind failed: " << strerror(errno);
+ return false;
+ }
+
+ if (address->FromSocket(*fd) != 0) {
+ QUIC_LOG(ERROR) << "Unable to get self address. Error: "
+ << strerror(errno);
+ return false;
+ }
+ return true;
+}
+
+struct QuicUdpBatchWriterIOTestParams;
+class QUIC_EXPORT_PRIVATE QuicUdpBatchWriterIOTestDelegate {
+ public:
+ virtual ~QuicUdpBatchWriterIOTestDelegate() {}
+
+ virtual bool ShouldSkip(const QuicUdpBatchWriterIOTestParams& params) {
+ return false;
+ }
+
+ virtual void ResetWriter(int fd) = 0;
+
+ virtual QuicUdpBatchWriter* GetWriter() = 0;
+};
+
+struct QUIC_EXPORT_PRIVATE QuicUdpBatchWriterIOTestParams {
+ // Use shared_ptr because gtest makes copies of test params.
+ std::shared_ptr<QuicUdpBatchWriterIOTestDelegate> delegate;
+ int address_family;
+ int data_size;
+ int packet_size;
+
+ QUIC_EXPORT_PRIVATE friend std::ostream& operator<<(
+ std::ostream& os,
+ const QuicUdpBatchWriterIOTestParams& p) {
+ os << "{ address_family: " << p.address_family
+ << " data_size: " << p.data_size << " packet_size: " << p.packet_size
+ << " }";
+ return os;
+ }
+};
+
+template <class QuicUdpBatchWriterIOTestDelegateT>
+static std::vector<QuicUdpBatchWriterIOTestParams>
+MakeQuicBatchWriterTestParams() {
+ static_assert(std::is_base_of<QuicUdpBatchWriterIOTestDelegate,
+ QuicUdpBatchWriterIOTestDelegateT>::value,
+ "<QuicUdpBatchWriterIOTestDelegateT> needs to derive from "
+ "QuicUdpBatchWriterIOTestDelegate");
+
+ std::vector<QuicUdpBatchWriterIOTestParams> params;
+ for (int address_family : {AF_INET, AF_INET6}) {
+ for (int data_size : {1, 150, 1500, 15000, 64000, 512 * 1024}) {
+ for (int packet_size : {1, 50, 1350, 1452}) {
+ if (packet_size <= data_size && (data_size / packet_size < 2000)) {
+ params.push_back(
+ {std::make_unique<QuicUdpBatchWriterIOTestDelegateT>(),
+ address_family, data_size, packet_size});
+ }
+ }
+ }
+ }
+ return params;
+}
+
+// QuicUdpBatchWriterIOTest is a value parameterized test fixture that can be
+// used by tests of derived classes of QuicUdpBatchWriter, to verify basic
+// packet IO capabilities.
+class QUIC_EXPORT_PRIVATE QuicUdpBatchWriterIOTest
+ : public QuicTestWithParam<QuicUdpBatchWriterIOTestParams> {
+ protected:
+ QuicUdpBatchWriterIOTest()
+ : address_family_(GetParam().address_family),
+ data_size_(GetParam().data_size),
+ packet_size_(GetParam().packet_size),
+ self_socket_(-1),
+ peer_socket_(-1) {
+ QUIC_LOG(INFO) << "QuicUdpBatchWriterIOTestParams: " << GetParam();
+ EXPECT_TRUE(address_family_ == AF_INET || address_family_ == AF_INET6);
+ EXPECT_LE(packet_size_, data_size_);
+ EXPECT_LE(packet_size_, sizeof(packet_buffer_));
+ }
+
+ ~QuicUdpBatchWriterIOTest() override {
+ if (self_socket_ > 0) {
+ close(self_socket_);
+ }
+ if (peer_socket_ > 0) {
+ close(peer_socket_);
+ }
+ }
+
+ // Whether this test should be skipped. A test is passed if skipped.
+ // A test can be skipped when e.g. it exercises a kernel feature that is not
+ // available on the system.
+ bool ShouldSkip() {
+ if (!IsAddressFamilySupported(address_family_)) {
+ QUIC_LOG(WARNING)
+ << "Test skipped since address_family is not supported.";
+ return true;
+ }
+
+ return GetParam().delegate->ShouldSkip(GetParam());
+ }
+
+ // Initialize a test.
+ // To fail the test in Initialize, use ASSERT_xx macros.
+ void Initialize() {
+ ASSERT_TRUE(CreateSocket(address_family_, &self_address_, &self_socket_));
+ ASSERT_TRUE(CreateSocket(address_family_, &peer_address_, &peer_socket_));
+
+ QUIC_DLOG(INFO) << "Self address: " << self_address_.ToString() << ", fd "
+ << self_socket_;
+ QUIC_DLOG(INFO) << "Peer address: " << peer_address_.ToString() << ", fd "
+ << peer_socket_;
+ GetParam().delegate->ResetWriter(self_socket_);
+ }
+
+ QuicUdpBatchWriter* GetWriter() { return GetParam().delegate->GetWriter(); }
+
+ void ValidateWrite() {
+ char this_packet_content = '\0';
+ int this_packet_size;
+ int num_writes = 0;
+ int bytes_flushed = 0;
+ WriteResult result;
+
+ for (int bytes_sent = 0; bytes_sent < data_size_;
+ bytes_sent += this_packet_size, ++this_packet_content) {
+ this_packet_size = std::min(packet_size_, data_size_ - bytes_sent);
+ memset(&packet_buffer_[0], this_packet_content, this_packet_size);
+
+ result = GetWriter()->WritePacket(&packet_buffer_[0], this_packet_size,
+ self_address_.host(), peer_address_,
+ nullptr);
+
+ ASSERT_EQ(WRITE_STATUS_OK, result.status) << strerror(result.error_code);
+ bytes_flushed += result.bytes_written;
+ ++num_writes;
+
+ QUIC_DVLOG(1) << "[write #" << num_writes
+ << "] this_packet_size: " << this_packet_size
+ << ", total_bytes_sent: " << bytes_sent + this_packet_size
+ << ", bytes_flushed: " << bytes_flushed
+ << ", pkt content:" << std::hex << int(this_packet_content);
+ }
+
+ result = GetWriter()->Flush();
+ ASSERT_EQ(WRITE_STATUS_OK, result.status) << strerror(result.error_code);
+ bytes_flushed += result.bytes_written;
+ ASSERT_EQ(data_size_, bytes_flushed);
+
+ QUIC_LOG(INFO) << "Sent " << data_size_ << " bytes in " << num_writes
+ << " writes.";
+ }
+
+ void ValidateRead() {
+ char this_packet_content = '\0';
+ int this_packet_size;
+ int packets_received = 0;
+ for (int bytes_received = 0; bytes_received < data_size_;
+ bytes_received += this_packet_size, ++this_packet_content) {
+ this_packet_size = std::min(packet_size_, data_size_ - bytes_received);
+ SCOPED_TRACE(testing::Message()
+ << "Before ReadPacket: bytes_received=" << bytes_received
+ << ", this_packet_size=" << this_packet_size);
+
+ QuicUdpSocketApi::ReadPacketResult result;
+ result.packet_buffer = {&packet_buffer_[0], sizeof(packet_buffer_)};
+ result.control_buffer = {&control_buffer_[0], sizeof(control_buffer_)};
+ QuicUdpSocketApi().ReadPacket(
+ peer_socket_,
+ quic::BitMask64(QuicUdpPacketInfoBit::V4_SELF_IP,
+ QuicUdpPacketInfoBit::V6_SELF_IP,
+ QuicUdpPacketInfoBit::PEER_ADDRESS),
+ &result);
+ ASSERT_TRUE(result.ok);
+ ASSERT_TRUE(
+ result.packet_info.HasValue(QuicUdpPacketInfoBit::PEER_ADDRESS));
+ QuicSocketAddress read_peer_address = result.packet_info.peer_address();
+ QuicIpAddress read_self_address = read_peer_address.host().IsIPv6()
+ ? result.packet_info.self_v6_ip()
+ : result.packet_info.self_v4_ip();
+
+ EXPECT_EQ(read_self_address, peer_address_.host());
+ EXPECT_EQ(read_peer_address, self_address_);
+ for (int i = 0; i < this_packet_size; ++i) {
+ EXPECT_EQ(this_packet_content, packet_buffer_[i]);
+ }
+ packets_received += this_packet_size;
+ }
+
+ QUIC_LOG(INFO) << "Received " << data_size_ << " bytes in "
+ << packets_received << " packets.";
+ }
+
+ QuicSocketAddress self_address_;
+ QuicSocketAddress peer_address_;
+ char packet_buffer_[1500];
+ char control_buffer_[kDefaultUdpPacketControlBufferSize];
+ int address_family_;
+ const int data_size_;
+ const int packet_size_;
+ int self_socket_;
+ int peer_socket_;
+};
+
+TEST_P(QuicUdpBatchWriterIOTest, WriteAndRead) {
+ if (ShouldSkip()) {
+ return;
+ }
+
+ Initialize();
+
+ ValidateWrite();
+ ValidateRead();
+}
+
+} // namespace test
+} // namespace quic
+
+#endif // QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_TEST_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.cc
new file mode 100644
index 00000000000..56c0e10171f
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.h"
+
+#include <time.h>
+#include <ctime>
+
+#include "net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h"
+
+namespace quic {
+
+QuicGsoBatchWriter::QuicGsoBatchWriter(
+ std::unique_ptr<QuicBatchWriterBuffer> batch_buffer,
+ int fd)
+ : QuicGsoBatchWriter(std::move(batch_buffer), fd, CLOCK_MONOTONIC) {}
+
+QuicGsoBatchWriter::QuicGsoBatchWriter(
+ std::unique_ptr<QuicBatchWriterBuffer> batch_buffer,
+ int fd,
+ clockid_t clockid_for_release_time)
+ : QuicUdpBatchWriter(std::move(batch_buffer), fd),
+ clockid_for_release_time_(clockid_for_release_time),
+ supports_release_time_(
+ GetQuicRestartFlag(quic_support_release_time_for_gso) &&
+ QuicLinuxSocketUtils::EnableReleaseTime(fd,
+ clockid_for_release_time)) {
+ if (supports_release_time_) {
+ QUIC_RESTART_FLAG_COUNT(quic_support_release_time_for_gso);
+ QUIC_LOG_FIRST_N(INFO, 5) << "Release time is enabled.";
+ } else {
+ QUIC_LOG_FIRST_N(INFO, 5) << "Release time is not enabled.";
+ }
+}
+
+QuicGsoBatchWriter::QuicGsoBatchWriter(
+ std::unique_ptr<QuicBatchWriterBuffer> batch_buffer,
+ int fd,
+ clockid_t clockid_for_release_time,
+ ReleaseTimeForceEnabler enabler)
+ : QuicUdpBatchWriter(std::move(batch_buffer), fd),
+ clockid_for_release_time_(clockid_for_release_time),
+ supports_release_time_(true) {
+ QUIC_DLOG(INFO) << "Release time forcefully enabled.";
+}
+
+QuicGsoBatchWriter::CanBatchResult QuicGsoBatchWriter::CanBatch(
+ const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ const PerPacketOptions* options,
+ uint64_t release_time) const {
+ // If there is nothing buffered already, this write will be included in this
+ // batch.
+ if (buffered_writes().empty()) {
+ return CanBatchResult(/*can_batch=*/true, /*must_flush=*/false);
+ }
+
+ // The new write can be batched if all of the following are true:
+ // [0] The total number of the GSO segments(one write=one segment, including
+ // the new write) must not exceed |max_segments|.
+ // [1] It has the same source and destination addresses as already buffered
+ // writes.
+ // [2] It won't cause this batch to exceed kMaxGsoPacketSize.
+ // [3] Already buffered writes all have the same length.
+ // [4] Length of already buffered writes must >= length of the new write.
+ // [5] The new packet has the same release time as buffered writes.
+ const BufferedWrite& first = buffered_writes().front();
+ const BufferedWrite& last = buffered_writes().back();
+ size_t max_segments = MaxSegments(first.buf_len);
+ bool can_batch =
+ buffered_writes().size() < max_segments && // [0]
+ last.self_address == self_address && // [1]
+ last.peer_address == peer_address && // [1]
+ batch_buffer().SizeInUse() + buf_len <= kMaxGsoPacketSize && // [2]
+ first.buf_len == last.buf_len && // [3]
+ first.buf_len >= buf_len && // [4]
+ (!SupportsReleaseTime() || first.release_time == release_time); // [5]
+
+ // A flush is required if any of the following is true:
+ // [a] The new write can't be batched.
+ // [b] Length of the new write is different from the length of already
+ // buffered writes.
+ // [c] The total number of the GSO segments, including the new write, reaches
+ // |max_segments|.
+ bool must_flush = (!can_batch) || // [a]
+ (last.buf_len != buf_len) || // [b]
+ (buffered_writes().size() + 1 == max_segments); // [c]
+ return CanBatchResult(can_batch, must_flush);
+}
+
+uint64_t QuicGsoBatchWriter::NowInNanosForReleaseTime() const {
+ struct timespec ts;
+
+ if (clock_gettime(clockid_for_release_time_, &ts) != 0) {
+ return 0;
+ }
+
+ return ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec;
+}
+
+// static
+void QuicGsoBatchWriter::BuildCmsg(QuicMsgHdr* hdr,
+ const QuicIpAddress& self_address,
+ uint16_t gso_size,
+ uint64_t release_time) {
+ hdr->SetIpInNextCmsg(self_address);
+ if (gso_size > 0) {
+ *hdr->GetNextCmsgData<uint16_t>(SOL_UDP, UDP_SEGMENT) = gso_size;
+ }
+ if (release_time != 0) {
+ *hdr->GetNextCmsgData<uint64_t>(SOL_SOCKET, SO_TXTIME) = release_time;
+ }
+}
+
+QuicGsoBatchWriter::FlushImplResult QuicGsoBatchWriter::FlushImpl() {
+ return InternalFlushImpl<kCmsgSpace>(BuildCmsg);
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.h b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.h
new file mode 100644
index 00000000000..64c7e02fdd4
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.h
@@ -0,0 +1,114 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_GSO_BATCH_WRITER_H_
+#define QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_GSO_BATCH_WRITER_H_
+
+#include "net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h"
+
+namespace quic {
+
+// QuicGsoBatchWriter sends QUIC packets in batches, using UDP socket's generic
+// segmentation offload(GSO) capability.
+class QUIC_EXPORT_PRIVATE QuicGsoBatchWriter : public QuicUdpBatchWriter {
+ public:
+ QuicGsoBatchWriter(std::unique_ptr<QuicBatchWriterBuffer> batch_buffer,
+ int fd);
+
+ // |clockid_for_release_time|: FQ qdisc requires CLOCK_MONOTONIC, EDF requires
+ // CLOCK_TAI.
+ QuicGsoBatchWriter(std::unique_ptr<QuicBatchWriterBuffer> batch_buffer,
+ int fd,
+ clockid_t clockid_for_release_time);
+
+ bool SupportsReleaseTime() const final { return supports_release_time_; }
+
+ CanBatchResult CanBatch(const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ const PerPacketOptions* options,
+ uint64_t release_time) const override;
+
+ FlushImplResult FlushImpl() override;
+
+ protected:
+ // Test only constructor to forcefully enable release time.
+ struct QUIC_EXPORT_PRIVATE ReleaseTimeForceEnabler {};
+ QuicGsoBatchWriter(std::unique_ptr<QuicBatchWriterBuffer> batch_buffer,
+ int fd,
+ clockid_t clockid_for_release_time,
+ ReleaseTimeForceEnabler enabler);
+
+ uint64_t NowInNanosForReleaseTime() const override;
+
+ static size_t MaxSegments(size_t gso_size) {
+ // Max segments should be the min of UDP_MAX_SEGMENTS(64) and
+ // (((64KB - sizeof(ip hdr) - sizeof(udp hdr)) / MSS) + 1), in the typical
+ // case of IPv6 packets with 1500-byte MTU, the result is
+ // ((64KB - 40 - 8) / (1500 - 48)) + 1 = 46
+ // However, due a kernel bug, the limit is much lower for tiny gso_sizes.
+ return gso_size <= 2 ? 16 : 45;
+ }
+
+ static const int kCmsgSpace =
+ kCmsgSpaceForIp + kCmsgSpaceForSegmentSize + kCmsgSpaceForTxTime;
+ static void BuildCmsg(QuicMsgHdr* hdr,
+ const QuicIpAddress& self_address,
+ uint16_t gso_size,
+ uint64_t release_time);
+
+ template <size_t CmsgSpace, typename CmsgBuilderT>
+ FlushImplResult InternalFlushImpl(CmsgBuilderT cmsg_builder) {
+ DCHECK(!IsWriteBlocked());
+ DCHECK(!buffered_writes().empty());
+
+ FlushImplResult result = {WriteResult(WRITE_STATUS_OK, 0),
+ /*num_packets_sent=*/0, /*bytes_written=*/0};
+ WriteResult& write_result = result.write_result;
+
+ int total_bytes = batch_buffer().SizeInUse();
+ const BufferedWrite& first = buffered_writes().front();
+ char cbuf[CmsgSpace];
+ QuicMsgHdr hdr(first.buffer, total_bytes, first.peer_address, cbuf,
+ sizeof(cbuf));
+
+ uint16_t gso_size = buffered_writes().size() > 1 ? first.buf_len : 0;
+ cmsg_builder(&hdr, first.self_address, gso_size, first.release_time);
+
+ write_result = QuicLinuxSocketUtils::WritePacket(fd(), hdr);
+ QUIC_DVLOG(1) << "Write GSO packet result: " << write_result
+ << ", fd: " << fd()
+ << ", self_address: " << first.self_address.ToString()
+ << ", peer_address: " << first.peer_address.ToString()
+ << ", num_segments: " << buffered_writes().size()
+ << ", total_bytes: " << total_bytes
+ << ", gso_size: " << gso_size;
+
+ // All segments in a GSO packet share the same fate - if the write failed,
+ // none of them are sent, and it's not needed to call PopBufferedWrite().
+ if (write_result.status != WRITE_STATUS_OK) {
+ return result;
+ }
+
+ result.num_packets_sent = buffered_writes().size();
+
+ write_result.bytes_written = total_bytes;
+ result.bytes_written = total_bytes;
+
+ batch_buffer().PopBufferedWrite(buffered_writes().size());
+
+ QUIC_BUG_IF(!buffered_writes().empty())
+ << "All packets should have been written on a successful return";
+ return result;
+ }
+
+ private:
+ const clockid_t clockid_for_release_time_;
+ const bool supports_release_time_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_GSO_BATCH_WRITER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer_test.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer_test.cc
new file mode 100644
index 00000000000..c7d695ab4f5
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer_test.cc
@@ -0,0 +1,461 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.h"
+
+#include <cstdint>
+#include <limits>
+#include <memory>
+#include <utility>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.h"
+
+using testing::_;
+using testing::Invoke;
+using testing::StrictMock;
+
+namespace quic {
+namespace test {
+namespace {
+
+size_t PacketLength(const msghdr* msg) {
+ size_t length = 0;
+ for (size_t i = 0; i < msg->msg_iovlen; ++i) {
+ length += msg->msg_iov[i].iov_len;
+ }
+ return length;
+}
+
+uint64_t MillisToNanos(uint64_t milliseconds) {
+ return milliseconds * 1000000;
+}
+
+class QUIC_EXPORT_PRIVATE TestQuicGsoBatchWriter : public QuicGsoBatchWriter {
+ public:
+ using QuicGsoBatchWriter::batch_buffer;
+ using QuicGsoBatchWriter::buffered_writes;
+ using QuicGsoBatchWriter::CanBatch;
+ using QuicGsoBatchWriter::CanBatchResult;
+ using QuicGsoBatchWriter::GetReleaseTime;
+ using QuicGsoBatchWriter::MaxSegments;
+ using QuicGsoBatchWriter::QuicGsoBatchWriter;
+
+ static std::unique_ptr<TestQuicGsoBatchWriter>
+ NewInstanceWithReleaseTimeSupport() {
+ return std::unique_ptr<TestQuicGsoBatchWriter>(new TestQuicGsoBatchWriter(
+ std::make_unique<QuicBatchWriterBuffer>(),
+ /*fd=*/-1, CLOCK_MONOTONIC, ReleaseTimeForceEnabler()));
+ }
+
+ uint64_t NowInNanosForReleaseTime() const override {
+ return MillisToNanos(forced_release_time_ms_);
+ }
+
+ void ForceReleaseTimeMs(uint64_t forced_release_time_ms) {
+ forced_release_time_ms_ = forced_release_time_ms;
+ }
+
+ private:
+ uint64_t forced_release_time_ms_ = 1;
+};
+
+struct QUIC_EXPORT_PRIVATE TestPerPacketOptions : public PerPacketOptions {
+ std::unique_ptr<quic::PerPacketOptions> Clone() const override {
+ return std::make_unique<TestPerPacketOptions>(*this);
+ }
+};
+
+// TestBufferedWrite is a copy-constructible BufferedWrite.
+struct QUIC_EXPORT_PRIVATE TestBufferedWrite : public BufferedWrite {
+ using BufferedWrite::BufferedWrite;
+ TestBufferedWrite(const TestBufferedWrite& other)
+ : BufferedWrite(other.buffer,
+ other.buf_len,
+ other.self_address,
+ other.peer_address,
+ other.options ? other.options->Clone()
+ : std::unique_ptr<PerPacketOptions>(),
+ other.release_time) {}
+};
+
+// Pointed to by all instances of |BatchCriteriaTestData|. Content not used.
+static char unused_packet_buffer[kMaxOutgoingPacketSize];
+
+struct QUIC_EXPORT_PRIVATE BatchCriteriaTestData {
+ BatchCriteriaTestData(size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ uint64_t release_time,
+ bool can_batch,
+ bool must_flush)
+ : buffered_write(unused_packet_buffer,
+ buf_len,
+ self_address,
+ peer_address,
+ std::unique_ptr<PerPacketOptions>(),
+ release_time),
+ can_batch(can_batch),
+ must_flush(must_flush) {}
+
+ TestBufferedWrite buffered_write;
+ // Expected value of CanBatchResult.can_batch when batching |buffered_write|.
+ bool can_batch;
+ // Expected value of CanBatchResult.must_flush when batching |buffered_write|.
+ bool must_flush;
+};
+
+std::vector<BatchCriteriaTestData> BatchCriteriaTestData_SizeDecrease() {
+ const QuicIpAddress self_addr;
+ const QuicSocketAddress peer_addr;
+ std::vector<BatchCriteriaTestData> test_data_table = {
+ // clang-format off
+ // buf_len self_addr peer_addr t_rel can_batch must_flush
+ {1350, self_addr, peer_addr, 0, true, false},
+ {1350, self_addr, peer_addr, 0, true, false},
+ {1350, self_addr, peer_addr, 0, true, false},
+ {39, self_addr, peer_addr, 0, true, true},
+ {39, self_addr, peer_addr, 0, false, true},
+ {1350, self_addr, peer_addr, 0, false, true},
+ // clang-format on
+ };
+ return test_data_table;
+}
+
+std::vector<BatchCriteriaTestData> BatchCriteriaTestData_SizeIncrease() {
+ const QuicIpAddress self_addr;
+ const QuicSocketAddress peer_addr;
+ std::vector<BatchCriteriaTestData> test_data_table = {
+ // clang-format off
+ // buf_len self_addr peer_addr t_rel can_batch must_flush
+ {1350, self_addr, peer_addr, 0, true, false},
+ {1350, self_addr, peer_addr, 0, true, false},
+ {1350, self_addr, peer_addr, 0, true, false},
+ {1351, self_addr, peer_addr, 0, false, true},
+ // clang-format on
+ };
+ return test_data_table;
+}
+
+std::vector<BatchCriteriaTestData> BatchCriteriaTestData_AddressChange() {
+ const QuicIpAddress self_addr1 = QuicIpAddress::Loopback4();
+ const QuicIpAddress self_addr2 = QuicIpAddress::Loopback6();
+ const QuicSocketAddress peer_addr1(self_addr1, 666);
+ const QuicSocketAddress peer_addr2(self_addr1, 777);
+ const QuicSocketAddress peer_addr3(self_addr2, 666);
+ const QuicSocketAddress peer_addr4(self_addr2, 777);
+ std::vector<BatchCriteriaTestData> test_data_table = {
+ // clang-format off
+ // buf_len self_addr peer_addr t_rel can_batch must_flush
+ {1350, self_addr1, peer_addr1, 0, true, false},
+ {1350, self_addr1, peer_addr1, 0, true, false},
+ {1350, self_addr1, peer_addr1, 0, true, false},
+ {1350, self_addr2, peer_addr1, 0, false, true},
+ {1350, self_addr1, peer_addr2, 0, false, true},
+ {1350, self_addr1, peer_addr3, 0, false, true},
+ {1350, self_addr1, peer_addr4, 0, false, true},
+ {1350, self_addr1, peer_addr4, 0, false, true},
+ // clang-format on
+ };
+ return test_data_table;
+}
+
+std::vector<BatchCriteriaTestData> BatchCriteriaTestData_ReleaseTime1() {
+ const QuicIpAddress self_addr;
+ const QuicSocketAddress peer_addr;
+ std::vector<BatchCriteriaTestData> test_data_table = {
+ // clang-format off
+ // buf_len self_addr peer_addr t_rel can_batch must_flush
+ {1350, self_addr, peer_addr, 5, true, false},
+ {1350, self_addr, peer_addr, 5, true, false},
+ {1350, self_addr, peer_addr, 5, true, false},
+ {1350, self_addr, peer_addr, 9, false, true},
+ // clang-format on
+ };
+ return test_data_table;
+}
+
+std::vector<BatchCriteriaTestData> BatchCriteriaTestData_ReleaseTime2() {
+ const QuicIpAddress self_addr;
+ const QuicSocketAddress peer_addr;
+ std::vector<BatchCriteriaTestData> test_data_table = {
+ // clang-format off
+ // buf_len self_addr peer_addr t_rel can_batch must_flush
+ {1350, self_addr, peer_addr, 0, true, false},
+ {1350, self_addr, peer_addr, 0, true, false},
+ {1350, self_addr, peer_addr, 0, true, false},
+ {1350, self_addr, peer_addr, 9, false, true},
+ // clang-format on
+ };
+ return test_data_table;
+}
+
+std::vector<BatchCriteriaTestData> BatchCriteriaTestData_MaxSegments(
+ size_t gso_size) {
+ const QuicIpAddress self_addr;
+ const QuicSocketAddress peer_addr;
+ std::vector<BatchCriteriaTestData> test_data_table;
+ size_t max_segments = TestQuicGsoBatchWriter::MaxSegments(gso_size);
+ for (int i = 0; i < max_segments; ++i) {
+ bool is_last_in_batch = (i + 1 == max_segments);
+ test_data_table.push_back({gso_size, self_addr, peer_addr,
+ /*release_time=*/0, true, is_last_in_batch});
+ }
+ test_data_table.push_back(
+ {gso_size, self_addr, peer_addr, /*release_time=*/0, false, true});
+ return test_data_table;
+}
+
+class QuicGsoBatchWriterTest : public QuicTest {
+ protected:
+ WriteResult WritePacket(QuicGsoBatchWriter* writer, size_t packet_size) {
+ return writer->WritePacket(&packet_buffer_[0], packet_size, self_address_,
+ peer_address_, nullptr);
+ }
+
+ WriteResult WritePacketWithOptions(QuicGsoBatchWriter* writer,
+ PerPacketOptions* options) {
+ return writer->WritePacket(&packet_buffer_[0], 1350, self_address_,
+ peer_address_, options);
+ }
+
+ QuicIpAddress self_address_ = QuicIpAddress::Any4();
+ QuicSocketAddress peer_address_{QuicIpAddress::Any4(), 443};
+ char packet_buffer_[1500];
+ StrictMock<MockQuicSyscallWrapper> mock_syscalls_;
+ ScopedGlobalSyscallWrapperOverride syscall_override_{&mock_syscalls_};
+};
+
+TEST_F(QuicGsoBatchWriterTest, BatchCriteria) {
+ std::unique_ptr<TestQuicGsoBatchWriter> writer;
+
+ std::vector<std::vector<BatchCriteriaTestData>> test_data_tables;
+ test_data_tables.emplace_back(BatchCriteriaTestData_SizeDecrease());
+ test_data_tables.emplace_back(BatchCriteriaTestData_SizeIncrease());
+ test_data_tables.emplace_back(BatchCriteriaTestData_AddressChange());
+ test_data_tables.emplace_back(BatchCriteriaTestData_ReleaseTime1());
+ test_data_tables.emplace_back(BatchCriteriaTestData_ReleaseTime2());
+ test_data_tables.emplace_back(BatchCriteriaTestData_MaxSegments(1));
+ test_data_tables.emplace_back(BatchCriteriaTestData_MaxSegments(2));
+ test_data_tables.emplace_back(BatchCriteriaTestData_MaxSegments(1350));
+
+ for (size_t i = 0; i < test_data_tables.size(); ++i) {
+ writer = TestQuicGsoBatchWriter::NewInstanceWithReleaseTimeSupport();
+
+ const auto& test_data_table = test_data_tables[i];
+ for (size_t j = 0; j < test_data_table.size(); ++j) {
+ const BatchCriteriaTestData& test_data = test_data_table[j];
+ SCOPED_TRACE(testing::Message() << "i=" << i << ", j=" << j);
+ TestQuicGsoBatchWriter::CanBatchResult result = writer->CanBatch(
+ test_data.buffered_write.buffer, test_data.buffered_write.buf_len,
+ test_data.buffered_write.self_address,
+ test_data.buffered_write.peer_address,
+ /*options=*/nullptr, test_data.buffered_write.release_time);
+
+ ASSERT_EQ(test_data.can_batch, result.can_batch);
+ ASSERT_EQ(test_data.must_flush, result.must_flush);
+
+ if (result.can_batch) {
+ ASSERT_TRUE(
+ writer->batch_buffer()
+ .PushBufferedWrite(test_data.buffered_write.buffer,
+ test_data.buffered_write.buf_len,
+ test_data.buffered_write.self_address,
+ test_data.buffered_write.peer_address,
+ /*options=*/nullptr,
+ test_data.buffered_write.release_time)
+ .succeeded);
+ }
+ }
+ }
+}
+
+TEST_F(QuicGsoBatchWriterTest, WriteSuccess) {
+ TestQuicGsoBatchWriter writer(std::make_unique<QuicBatchWriterBuffer>(),
+ /*fd=*/-1);
+
+ ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 1000));
+
+ EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _))
+ .WillOnce(Invoke([](int sockfd, const msghdr* msg, int flags) {
+ EXPECT_EQ(1100u, PacketLength(msg));
+ return 1100;
+ }));
+ ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 1100), WritePacket(&writer, 100));
+ ASSERT_EQ(0u, writer.batch_buffer().SizeInUse());
+ ASSERT_EQ(0u, writer.buffered_writes().size());
+}
+
+TEST_F(QuicGsoBatchWriterTest, WriteBlockDataNotBuffered) {
+ TestQuicGsoBatchWriter writer(std::make_unique<QuicBatchWriterBuffer>(),
+ /*fd=*/-1);
+
+ ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
+ ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
+
+ EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _))
+ .WillOnce(Invoke([](int sockfd, const msghdr* msg, int flags) {
+ EXPECT_EQ(200u, PacketLength(msg));
+ errno = EWOULDBLOCK;
+ return -1;
+ }));
+ ASSERT_EQ(WriteResult(WRITE_STATUS_BLOCKED, EWOULDBLOCK),
+ WritePacket(&writer, 150));
+ ASSERT_EQ(200u, writer.batch_buffer().SizeInUse());
+ ASSERT_EQ(2u, writer.buffered_writes().size());
+}
+
+TEST_F(QuicGsoBatchWriterTest, WriteBlockDataBuffered) {
+ TestQuicGsoBatchWriter writer(std::make_unique<QuicBatchWriterBuffer>(),
+ /*fd=*/-1);
+
+ ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
+ ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
+
+ EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _))
+ .WillOnce(Invoke([](int sockfd, const msghdr* msg, int flags) {
+ EXPECT_EQ(250u, PacketLength(msg));
+ errno = EWOULDBLOCK;
+ return -1;
+ }));
+ ASSERT_EQ(WriteResult(WRITE_STATUS_BLOCKED_DATA_BUFFERED, EWOULDBLOCK),
+ WritePacket(&writer, 50));
+ ASSERT_EQ(250u, writer.batch_buffer().SizeInUse());
+ ASSERT_EQ(3u, writer.buffered_writes().size());
+}
+
+TEST_F(QuicGsoBatchWriterTest, WriteErrorWithoutDataBuffered) {
+ TestQuicGsoBatchWriter writer(std::make_unique<QuicBatchWriterBuffer>(),
+ /*fd=*/-1);
+
+ ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
+ ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
+
+ EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _))
+ .WillOnce(Invoke([](int sockfd, const msghdr* msg, int flags) {
+ EXPECT_EQ(200u, PacketLength(msg));
+ errno = EPERM;
+ return -1;
+ }));
+ WriteResult error_result = WritePacket(&writer, 150);
+ ASSERT_EQ(WriteResult(WRITE_STATUS_ERROR, EPERM), error_result);
+
+ ASSERT_EQ(3u, error_result.dropped_packets);
+ ASSERT_EQ(0u, writer.batch_buffer().SizeInUse());
+ ASSERT_EQ(0u, writer.buffered_writes().size());
+}
+
+TEST_F(QuicGsoBatchWriterTest, WriteErrorAfterDataBuffered) {
+ TestQuicGsoBatchWriter writer(std::make_unique<QuicBatchWriterBuffer>(),
+ /*fd=*/-1);
+
+ ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
+ ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
+
+ EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _))
+ .WillOnce(Invoke([](int sockfd, const msghdr* msg, int flags) {
+ EXPECT_EQ(250u, PacketLength(msg));
+ errno = EPERM;
+ return -1;
+ }));
+ WriteResult error_result = WritePacket(&writer, 50);
+ ASSERT_EQ(WriteResult(WRITE_STATUS_ERROR, EPERM), error_result);
+
+ ASSERT_EQ(3u, error_result.dropped_packets);
+ ASSERT_EQ(0u, writer.batch_buffer().SizeInUse());
+ ASSERT_EQ(0u, writer.buffered_writes().size());
+}
+
+TEST_F(QuicGsoBatchWriterTest, FlushError) {
+ TestQuicGsoBatchWriter writer(std::make_unique<QuicBatchWriterBuffer>(),
+ /*fd=*/-1);
+
+ ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
+ ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
+
+ EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _))
+ .WillOnce(Invoke([](int sockfd, const msghdr* msg, int flags) {
+ EXPECT_EQ(200u, PacketLength(msg));
+ errno = EINVAL;
+ return -1;
+ }));
+ WriteResult error_result = writer.Flush();
+ ASSERT_EQ(WriteResult(WRITE_STATUS_ERROR, EINVAL), error_result);
+
+ ASSERT_EQ(2u, error_result.dropped_packets);
+ ASSERT_EQ(0u, writer.batch_buffer().SizeInUse());
+ ASSERT_EQ(0u, writer.buffered_writes().size());
+}
+
+TEST_F(QuicGsoBatchWriterTest, ReleaseTimeNullOptions) {
+ auto writer = TestQuicGsoBatchWriter::NewInstanceWithReleaseTimeSupport();
+ EXPECT_EQ(0, writer->GetReleaseTime(nullptr));
+}
+
+TEST_F(QuicGsoBatchWriterTest, ReleaseTime) {
+ const WriteResult write_buffered(WRITE_STATUS_OK, 0);
+
+ auto writer = TestQuicGsoBatchWriter::NewInstanceWithReleaseTimeSupport();
+
+ TestPerPacketOptions options;
+ EXPECT_TRUE(options.release_time_delay.IsZero());
+ EXPECT_FALSE(options.allow_burst);
+ EXPECT_EQ(MillisToNanos(1), writer->GetReleaseTime(&options));
+
+ // The 1st packet has no delay.
+ ASSERT_EQ(write_buffered, WritePacketWithOptions(writer.get(), &options));
+ EXPECT_EQ(MillisToNanos(1), writer->buffered_writes().back().release_time);
+
+ // The 2nd packet has some delay, but allows burst.
+ options.release_time_delay = QuicTime::Delta::FromMilliseconds(3);
+ options.allow_burst = true;
+ ASSERT_EQ(write_buffered, WritePacketWithOptions(writer.get(), &options));
+ EXPECT_EQ(MillisToNanos(1), writer->buffered_writes().back().release_time);
+
+ // The 3rd packet has more delay and does not allow burst.
+ // The first 2 packets are flushed due to different release time.
+ EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _))
+ .WillOnce(Invoke([](int sockfd, const msghdr* msg, int flags) {
+ EXPECT_EQ(2700u, PacketLength(msg));
+ errno = 0;
+ return 0;
+ }));
+ options.release_time_delay = QuicTime::Delta::FromMilliseconds(5);
+ options.allow_burst = false;
+ ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 2700),
+ WritePacketWithOptions(writer.get(), &options));
+ EXPECT_EQ(MillisToNanos(6), writer->buffered_writes().back().release_time);
+
+ // The 4th packet has same delay, but allows burst.
+ options.allow_burst = true;
+ ASSERT_EQ(write_buffered, WritePacketWithOptions(writer.get(), &options));
+ EXPECT_EQ(MillisToNanos(6), writer->buffered_writes().back().release_time);
+
+ // The 5th packet has same delay, allows burst, but is shorter.
+ // Packets 3,4 and 5 are flushed.
+ EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _))
+ .WillOnce(Invoke([](int sockfd, const msghdr* msg, int flags) {
+ EXPECT_EQ(3000u, PacketLength(msg));
+ errno = 0;
+ return 0;
+ }));
+ options.allow_burst = true;
+ EXPECT_EQ(MillisToNanos(6), writer->GetReleaseTime(&options));
+ ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 3000),
+ writer->WritePacket(&packet_buffer_[0], 300, self_address_,
+ peer_address_, &options));
+ EXPECT_TRUE(writer->buffered_writes().empty());
+
+ // Pretend 1ms has elapsed and the 6th packet has 1ms less delay. In other
+ // words, the release time should still be the same as packets 3-5.
+ writer->ForceReleaseTimeMs(2);
+ options.release_time_delay = QuicTime::Delta::FromMilliseconds(4);
+ ASSERT_EQ(write_buffered, WritePacketWithOptions(writer.get(), &options));
+ EXPECT_EQ(MillisToNanos(6), writer->buffered_writes().back().release_time);
+}
+
+} // namespace
+} // namespace test
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.cc
new file mode 100644
index 00000000000..efd21791c4d
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.h"
+
+namespace quic {
+
+QuicSendmmsgBatchWriter::QuicSendmmsgBatchWriter(
+ std::unique_ptr<QuicBatchWriterBuffer> batch_buffer,
+ int fd)
+ : QuicUdpBatchWriter(std::move(batch_buffer), fd) {}
+
+QuicSendmmsgBatchWriter::CanBatchResult QuicSendmmsgBatchWriter::CanBatch(
+ const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ const PerPacketOptions* options,
+ uint64_t release_time) const {
+ return CanBatchResult(/*can_batch=*/true, /*must_flush=*/false);
+}
+
+QuicSendmmsgBatchWriter::FlushImplResult QuicSendmmsgBatchWriter::FlushImpl() {
+ return InternalFlushImpl(
+ kCmsgSpaceForIp,
+ [](QuicMMsgHdr* mhdr, int i, const BufferedWrite& buffered_write) {
+ mhdr->SetIpInNextCmsg(i, buffered_write.self_address);
+ });
+}
+
+QuicSendmmsgBatchWriter::FlushImplResult
+QuicSendmmsgBatchWriter::InternalFlushImpl(size_t cmsg_space,
+ const CmsgBuilder& cmsg_builder) {
+ DCHECK(!IsWriteBlocked());
+ DCHECK(!buffered_writes().empty());
+
+ FlushImplResult result = {WriteResult(WRITE_STATUS_OK, 0),
+ /*num_packets_sent=*/0, /*bytes_written=*/0};
+ WriteResult& write_result = result.write_result;
+
+ auto first = buffered_writes().cbegin();
+ const auto last = buffered_writes().cend();
+ while (first != last) {
+ QuicMMsgHdr mhdr(first, last, cmsg_space, cmsg_builder);
+
+ int num_packets_sent;
+ write_result = QuicLinuxSocketUtils::WriteMultiplePackets(
+ fd(), &mhdr, &num_packets_sent);
+ QUIC_DVLOG(1) << "WriteMultiplePackets sent " << num_packets_sent
+ << " out of " << mhdr.num_msgs()
+ << " packets. WriteResult=" << write_result;
+
+ if (write_result.status != WRITE_STATUS_OK) {
+ DCHECK_EQ(0, num_packets_sent);
+ break;
+ } else if (num_packets_sent == 0) {
+ QUIC_BUG << "WriteMultiplePackets returned OK, but no packets were sent.";
+ write_result = WriteResult(WRITE_STATUS_ERROR, EIO);
+ break;
+ }
+
+ first += num_packets_sent;
+
+ result.num_packets_sent += num_packets_sent;
+ result.bytes_written += write_result.bytes_written;
+ }
+
+ // Call PopBufferedWrite() even if write_result.status is not WRITE_STATUS_OK,
+ // to deal with partial writes.
+ batch_buffer().PopBufferedWrite(result.num_packets_sent);
+
+ if (write_result.status != WRITE_STATUS_OK) {
+ return result;
+ }
+
+ QUIC_BUG_IF(!buffered_writes().empty())
+ << "All packets should have been written on a successful return";
+ write_result.bytes_written = result.bytes_written;
+ return result;
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.h b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.h
new file mode 100644
index 00000000000..26a728e676a
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_PLATFORM_IMPL_QUIC_SENDMMSG_BATCH_WRITER_H_
+#define QUICHE_QUIC_PLATFORM_IMPL_QUIC_SENDMMSG_BATCH_WRITER_H_
+
+#include "net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h"
+#include "net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h"
+
+namespace quic {
+
+class QUIC_EXPORT_PRIVATE QuicSendmmsgBatchWriter : public QuicUdpBatchWriter {
+ public:
+ QuicSendmmsgBatchWriter(std::unique_ptr<QuicBatchWriterBuffer> batch_buffer,
+ int fd);
+
+ CanBatchResult CanBatch(const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ const PerPacketOptions* options,
+ uint64_t release_time) const override;
+
+ FlushImplResult FlushImpl() override;
+
+ protected:
+ typedef QuicMMsgHdr::ControlBufferInitializer CmsgBuilder;
+ FlushImplResult InternalFlushImpl(size_t cmsg_space,
+ const CmsgBuilder& cmsg_builder);
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_PLATFORM_IMPL_QUIC_SENDMMSG_BATCH_WRITER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer_test.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer_test.cc
new file mode 100644
index 00000000000..4dcc33c91d3
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer_test.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.h"
+
+namespace quic {
+namespace test {
+namespace {
+
+// Add tests here.
+
+} // namespace
+} // namespace test
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc b/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc
index b4907d4a020..1605b264c63 100644
--- a/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc
@@ -11,6 +11,7 @@
#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h"
#include "net/third_party/quiche/src/quic/core/quic_framer.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
@@ -77,6 +78,7 @@ class ChloFramerVisitor : public QuicFramerVisitorInterface,
bool OnPaddingFrame(const QuicPaddingFrame& frame) override;
bool OnMessageFrame(const QuicMessageFrame& frame) override;
bool OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& frame) override;
+ bool OnAckFrequencyFrame(const QuicAckFrequencyFrame& farme) override;
void OnPacketComplete() override {}
bool IsValidStatelessResetToken(QuicUint128 token) const override;
void OnAuthenticatedIetfStatelessResetPacket(
@@ -289,6 +291,11 @@ bool ChloFramerVisitor::OnHandshakeDoneFrame(
return true;
}
+bool ChloFramerVisitor::OnAckFrequencyFrame(
+ const QuicAckFrequencyFrame& /*frame*/) {
+ return true;
+}
+
bool ChloFramerVisitor::IsValidStatelessResetToken(
QuicUint128 /*token*/) const {
return false;
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc
index f885c94794c..6eacef38e2e 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc
@@ -87,7 +87,7 @@ BandwidthSampler::BandwidthSampler(
total_bytes_sent_at_last_acked_packet_(0),
last_acked_packet_sent_time_(QuicTime::Zero()),
last_acked_packet_ack_time_(QuicTime::Zero()),
- is_app_limited_(started_as_app_limited_),
+ is_app_limited_(true),
connection_state_map_(),
max_tracked_packets_(GetQuicFlag(FLAGS_quic_max_tracked_packet_count)),
unacked_packet_map_(unacked_packet_map),
@@ -105,7 +105,6 @@ BandwidthSampler::BandwidthSampler(const BandwidthSampler& other)
last_acked_packet_sent_time_(other.last_acked_packet_sent_time_),
last_acked_packet_ack_time_(other.last_acked_packet_ack_time_),
last_sent_packet_(other.last_sent_packet_),
- started_as_app_limited_(other.started_as_app_limited_),
is_app_limited_(other.is_app_limited_),
end_of_app_limited_phase_(other.end_of_app_limited_phase_),
connection_state_map_(other.connection_state_map_),
@@ -321,23 +320,13 @@ BandwidthSample BandwidthSampler::OnPacketAcknowledgedInner(
recent_ack_points_.Update(ack_time, total_bytes_acked_);
}
- if (started_as_app_limited_) {
- if (is_app_limited_) {
- // Exit app-limited phase in two cases:
- // (1) end_of_app_limited_phase_ is not initialized, i.e., so far all
- // packets are sent while there are buffered packets or pending data.
- // (2) The current acked packet is after the sent packet marked as the end
- // of the app limit phase.
- if (!end_of_app_limited_phase_.IsInitialized() ||
- packet_number > end_of_app_limited_phase_) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_bw_sampler_app_limited_starting_value);
- is_app_limited_ = false;
- }
- }
- } else {
- // Exit app-limited phase once a packet that was sent while the connection
- // is not app-limited is acknowledged.
- if (is_app_limited_ && end_of_app_limited_phase_.IsInitialized() &&
+ if (is_app_limited_) {
+ // Exit app-limited phase in two cases:
+ // (1) end_of_app_limited_phase_ is not initialized, i.e., so far all
+ // packets are sent while there are buffered packets or pending data.
+ // (2) The current acked packet is after the sent packet marked as the end
+ // of the app limit phase.
+ if (!end_of_app_limited_phase_.IsInitialized() ||
packet_number > end_of_app_limited_phase_) {
is_app_limited_ = false;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h
index b3c07364705..f32eabf0694 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h
@@ -528,10 +528,6 @@ class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface {
// The most recently sent packet.
QuicPacketNumber last_sent_packet_;
- // Indicates whether the bandwidth sampler is started in app-limited phase.
- const bool started_as_app_limited_ =
- GetQuicReloadableFlag(quic_bw_sampler_app_limited_starting_value);
-
// Indicates whether the bandwidth sampler is currently in an app-limited
// phase.
bool is_app_limited_;
@@ -565,8 +561,7 @@ class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface {
MaxAckHeightTracker max_ack_height_tracker_;
QuicByteCount total_bytes_acked_after_last_ack_event_;
- // True if --quic_avoid_overestimate_bandwidth_with_aggregation=true and
- // connection option 'BSAO' is set.
+ // True if connection option 'BSAO' is set.
bool overestimate_avoidance_;
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler_test.cc
index 5dda9986965..f689553bc5b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler_test.cc
@@ -34,8 +34,18 @@ const QuicByteCount kRegularPacketSize = 1280;
static_assert((kRegularPacketSize & 31) == 0,
"kRegularPacketSize has to be five times divisible by 2");
+struct TestParameters {
+ bool overestimate_avoidance;
+};
+
+// Used by ::testing::PrintToStringParamName().
+std::string PrintToString(const TestParameters& p) {
+ return p.overestimate_avoidance ? "enable_overestimate_avoidance"
+ : "no_enable_overestimate_avoidance";
+}
+
// A test fixture with utility methods for BandwidthSampler tests.
-class BandwidthSamplerTest : public QuicTest {
+class BandwidthSamplerTest : public QuicTestWithParam<TestParameters> {
protected:
BandwidthSamplerTest()
: sampler_(nullptr, /*max_height_tracker_window_length=*/0),
@@ -46,8 +56,7 @@ class BandwidthSamplerTest : public QuicTest {
round_trip_count_(0) {
// Ensure that the clock does not start at zero.
clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- if (GetQuicReloadableFlag(
- quic_avoid_overestimate_bandwidth_with_aggregation)) {
+ if (GetParam().overestimate_avoidance) {
sampler_.EnableOverestimateAvoidance();
}
}
@@ -170,8 +179,15 @@ class BandwidthSamplerTest : public QuicTest {
}
};
+INSTANTIATE_TEST_SUITE_P(
+ BandwidthSamplerTests,
+ BandwidthSamplerTest,
+ testing::Values(TestParameters{/*overestimate_avoidance=*/false},
+ TestParameters{/*overestimate_avoidance=*/true}),
+ testing::PrintToStringParamName());
+
// Test the sampler in a simple stop-and-wait sender setting.
-TEST_F(BandwidthSamplerTest, SendAndWait) {
+TEST_P(BandwidthSamplerTest, SendAndWait) {
QuicTime::Delta time_between_packets = QuicTime::Delta::FromMilliseconds(10);
QuicBandwidth expected_bandwidth =
QuicBandwidth::FromBytesPerSecond(kRegularPacketSize * 100);
@@ -200,7 +216,7 @@ TEST_F(BandwidthSamplerTest, SendAndWait) {
EXPECT_EQ(0u, bytes_in_flight_);
}
-TEST_F(BandwidthSamplerTest, SendTimeState) {
+TEST_P(BandwidthSamplerTest, SendTimeState) {
QuicTime::Delta time_between_packets = QuicTime::Delta::FromMilliseconds(10);
// Send packets 1-5.
@@ -266,7 +282,7 @@ TEST_F(BandwidthSamplerTest, SendTimeState) {
// Test the sampler during regular windowed sender scenario with fixed
// CWND of 20.
-TEST_F(BandwidthSamplerTest, SendPaced) {
+TEST_P(BandwidthSamplerTest, SendPaced) {
const QuicTime::Delta time_between_packets =
QuicTime::Delta::FromMilliseconds(1);
QuicBandwidth expected_bandwidth =
@@ -288,7 +304,7 @@ TEST_F(BandwidthSamplerTest, SendPaced) {
}
// Test the sampler in a scenario where 50% of packets is consistently lost.
-TEST_F(BandwidthSamplerTest, SendWithLosses) {
+TEST_P(BandwidthSamplerTest, SendWithLosses) {
const QuicTime::Delta time_between_packets =
QuicTime::Delta::FromMilliseconds(1);
QuicBandwidth expected_bandwidth =
@@ -333,7 +349,7 @@ TEST_F(BandwidthSamplerTest, SendWithLosses) {
// congestion controlled (specifically, non-retransmittable data is not
// congestion controlled). Should be functionally consistent in behavior with
// the SendWithLosses test.
-TEST_F(BandwidthSamplerTest, NotCongestionControlled) {
+TEST_P(BandwidthSamplerTest, NotCongestionControlled) {
const QuicTime::Delta time_between_packets =
QuicTime::Delta::FromMilliseconds(1);
QuicBandwidth expected_bandwidth =
@@ -382,7 +398,7 @@ TEST_F(BandwidthSamplerTest, NotCongestionControlled) {
// Simulate a situation where ACKs arrive in burst and earlier than usual, thus
// producing an ACK rate which is higher than the original send rate.
-TEST_F(BandwidthSamplerTest, CompressedAck) {
+TEST_P(BandwidthSamplerTest, CompressedAck) {
const QuicTime::Delta time_between_packets =
QuicTime::Delta::FromMilliseconds(1);
QuicBandwidth expected_bandwidth =
@@ -410,7 +426,7 @@ TEST_F(BandwidthSamplerTest, CompressedAck) {
}
// Tests receiving ACK packets in the reverse order.
-TEST_F(BandwidthSamplerTest, ReorderedAck) {
+TEST_P(BandwidthSamplerTest, ReorderedAck) {
const QuicTime::Delta time_between_packets =
QuicTime::Delta::FromMilliseconds(1);
QuicBandwidth expected_bandwidth =
@@ -441,7 +457,7 @@ TEST_F(BandwidthSamplerTest, ReorderedAck) {
}
// Test the app-limited logic.
-TEST_F(BandwidthSamplerTest, AppLimited) {
+TEST_P(BandwidthSamplerTest, AppLimited) {
const QuicTime::Delta time_between_packets =
QuicTime::Delta::FromMilliseconds(1);
QuicBandwidth expected_bandwidth =
@@ -508,7 +524,7 @@ TEST_F(BandwidthSamplerTest, AppLimited) {
}
// Test the samples taken at the first flight of packets sent.
-TEST_F(BandwidthSamplerTest, FirstRoundTrip) {
+TEST_P(BandwidthSamplerTest, FirstRoundTrip) {
const QuicTime::Delta time_between_packets =
QuicTime::Delta::FromMilliseconds(1);
const QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(800);
@@ -543,7 +559,7 @@ TEST_F(BandwidthSamplerTest, FirstRoundTrip) {
}
// Test sampler's ability to remove obsolete packets.
-TEST_F(BandwidthSamplerTest, RemoveObsoletePackets) {
+TEST_P(BandwidthSamplerTest, RemoveObsoletePackets) {
SendPacket(1);
SendPacket(2);
SendPacket(3);
@@ -566,7 +582,7 @@ TEST_F(BandwidthSamplerTest, RemoveObsoletePackets) {
EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_));
}
-TEST_F(BandwidthSamplerTest, NeuterPacket) {
+TEST_P(BandwidthSamplerTest, NeuterPacket) {
SendPacket(1);
EXPECT_EQ(0u, sampler_.total_bytes_neutered());
@@ -589,7 +605,7 @@ TEST_F(BandwidthSamplerTest, NeuterPacket) {
EXPECT_EQ(0u, sample.extra_acked);
}
-TEST_F(BandwidthSamplerTest, CongestionEventSampleDefaultValues) {
+TEST_P(BandwidthSamplerTest, CongestionEventSampleDefaultValues) {
// Make sure a default constructed CongestionEventSample has the correct
// initial values for BandwidthSampler::OnCongestionEvent() to work.
BandwidthSampler::CongestionEventSample sample;
@@ -602,7 +618,7 @@ TEST_F(BandwidthSamplerTest, CongestionEventSampleDefaultValues) {
}
// 1) Send 2 packets, 2) Ack both in 1 event, 3) Repeat.
-TEST_F(BandwidthSamplerTest, TwoAckedPacketsPerEvent) {
+TEST_P(BandwidthSamplerTest, TwoAckedPacketsPerEvent) {
QuicTime::Delta time_between_packets = QuicTime::Delta::FromMilliseconds(10);
QuicBandwidth sending_rate = QuicBandwidth::FromBytesAndTimeDelta(
kRegularPacketSize, time_between_packets);
@@ -631,7 +647,7 @@ TEST_F(BandwidthSamplerTest, TwoAckedPacketsPerEvent) {
}
}
-TEST_F(BandwidthSamplerTest, LoseEveryOtherPacket) {
+TEST_P(BandwidthSamplerTest, LoseEveryOtherPacket) {
QuicTime::Delta time_between_packets = QuicTime::Delta::FromMilliseconds(10);
QuicBandwidth sending_rate = QuicBandwidth::FromBytesAndTimeDelta(
kRegularPacketSize, time_between_packets);
@@ -663,7 +679,7 @@ TEST_F(BandwidthSamplerTest, LoseEveryOtherPacket) {
}
}
-TEST_F(BandwidthSamplerTest, AckHeightRespectBandwidthEstimateUpperBound) {
+TEST_P(BandwidthSamplerTest, AckHeightRespectBandwidthEstimateUpperBound) {
QuicTime::Delta time_between_packets = QuicTime::Delta::FromMilliseconds(10);
QuicBandwidth first_packet_sending_rate =
QuicBandwidth::FromBytesAndTimeDelta(kRegularPacketSize,
@@ -693,10 +709,7 @@ TEST_F(BandwidthSamplerTest, AckHeightRespectBandwidthEstimateUpperBound) {
class MaxAckHeightTrackerTest : public QuicTest {
protected:
MaxAckHeightTrackerTest() : tracker_(/*initial_filter_window=*/10) {
- if (GetQuicReloadableFlag(
- quic_avoid_overestimate_bandwidth_with_aggregation)) {
- tracker_.SetAckAggregationBandwidthThreshold(1.8);
- }
+ tracker_.SetAckAggregationBandwidthThreshold(1.8);
}
// Run a full aggregation episode, which is one or more aggregated acks,
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc
index 90df9a0c0da..cdd0cb54c16 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc
@@ -110,7 +110,7 @@ void Bbr2NetworkModel::OnCongestionEventStart(
// b) all packets in |acked_packets| did not generate valid samples. (e.g. ack
// of ack-only packets). In both cases, total_bytes_acked() will not change.
if (prior_bytes_acked != total_bytes_acked()) {
- QUIC_BUG_IF(sample.sample_max_bandwidth.IsZero())
+ QUIC_LOG_IF(WARNING, sample.sample_max_bandwidth.IsZero())
<< total_bytes_acked() - prior_bytes_acked << " bytes from "
<< acked_packets.size()
<< " packets have been acked, but sample_max_bandwidth is zero.";
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h
index e110a4c3297..ddef7722939 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h
@@ -184,6 +184,9 @@ struct QUIC_EXPORT_PRIVATE Bbr2Params {
// Can be enabled by connection option 'B2LO'.
bool ignore_inflight_lo = false;
+
+ // Can be enabled by connection optoin 'B2HI'.
+ bool limit_inflight_hi_by_cwnd = false;
};
class QUIC_EXPORT_PRIVATE RoundTripCounter {
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc
index 6fb7eee8059..f6a09388604 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc
@@ -198,9 +198,9 @@ Bbr2ProbeBwMode::AdaptUpperBoundsResult Bbr2ProbeBwMode::MaybeAdaptUpperBounds(
cycle_.is_sample_from_probing = false;
if (!send_state.is_app_limited) {
- QuicByteCount inflight_at_send = BytesInFlight(send_state);
+ const QuicByteCount inflight_at_send = BytesInFlight(send_state);
- QuicByteCount inflight_target =
+ const QuicByteCount inflight_target =
sender_->GetTargetBytesInflight() * (1.0 - Params().beta);
if (inflight_at_send >= inflight_target) {
// The new code does not change behavior.
@@ -209,7 +209,20 @@ Bbr2ProbeBwMode::AdaptUpperBoundsResult Bbr2ProbeBwMode::MaybeAdaptUpperBounds(
// The new code actually cuts inflight_hi slower than before.
QUIC_CODE_COUNT(quic_bbr2_cut_inflight_hi_gradually_in_effect);
}
- model_->set_inflight_hi(std::max(inflight_at_send, inflight_target));
+ if (Params().limit_inflight_hi_by_cwnd) {
+ const QuicByteCount cwnd_target =
+ sender_->GetCongestionWindow() * (1.0 - Params().beta);
+ if (inflight_at_send >= cwnd_target) {
+ // The new code does not change behavior.
+ QUIC_CODE_COUNT(quic_bbr2_cut_inflight_hi_cwnd_noop);
+ } else {
+ // The new code actually cuts inflight_hi slower than before.
+ QUIC_CODE_COUNT(quic_bbr2_cut_inflight_hi_cwnd_in_effect);
+ }
+ model_->set_inflight_hi(std::max(inflight_at_send, cwnd_target));
+ } else {
+ model_->set_inflight_hi(std::max(inflight_at_send, inflight_target));
+ }
}
QUIC_DVLOG(3) << sender_ << " " << cycle_.phase
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc
index 8c0171bc9bf..d1b3159f271 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc
@@ -95,11 +95,7 @@ void Bbr2Sender::SetFromConfig(const QuicConfig& config,
if (config.HasClientRequestedIndependentOption(kBBR9, perspective)) {
params_.flexible_app_limited = true;
}
- if (GetQuicReloadableFlag(
- quic_avoid_overestimate_bandwidth_with_aggregation) &&
- config.HasClientRequestedIndependentOption(kBSAO, perspective)) {
- QUIC_RELOADABLE_FLAG_COUNT_N(
- quic_avoid_overestimate_bandwidth_with_aggregation, 4, 4);
+ if (config.HasClientRequestedIndependentOption(kBSAO, perspective)) {
model_.EnableOverestimateAvoidance();
}
if (config.HasClientRequestedIndependentOption(kB2NA, perspective)) {
@@ -127,14 +123,18 @@ void Bbr2Sender::SetFromConfig(const QuicConfig& config,
QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_ignore_inflight_lo);
params_.ignore_inflight_lo = true;
}
+ if (GetQuicReloadableFlag(quic_bbr2_limit_inflight_hi) &&
+ config.HasClientRequestedIndependentOption(kB2HI, perspective)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_limit_inflight_hi);
+ params_.limit_inflight_hi_by_cwnd = true;
+ }
ApplyConnectionOptions(config.ClientRequestedIndependentOptions(perspective));
}
void Bbr2Sender::ApplyConnectionOptions(
const QuicTagVector& connection_options) {
- if (GetQuicReloadableFlag(quic_bbr2_lower_startup_cwnd_gain) &&
- ContainsQuicTag(connection_options, kBBQ2)) {
+ if (ContainsQuicTag(connection_options, kBBQ2)) {
// 2 is the lower, derived gain for CWND.
params_.startup_cwnd_gain = 2;
params_.drain_cwnd_gain = 2;
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc
index f803ab68cdf..205d3563f90 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc
@@ -427,10 +427,7 @@ TEST_F(Bbr2DefaultTopologyTest, SimpleTransferSmallBuffer) {
}
TEST_F(Bbr2DefaultTopologyTest, SimpleTransfer2RTTAggregationBytes) {
- if (GetQuicReloadableFlag(
- quic_avoid_overestimate_bandwidth_with_aggregation)) {
- SetConnectionOption(kBSAO);
- }
+ SetConnectionOption(kBSAO);
DefaultTopologyParams params;
CreateNetwork(params);
// 2 RTTs of aggregation, with a max of 10kb.
@@ -440,17 +437,9 @@ TEST_F(Bbr2DefaultTopologyTest, SimpleTransfer2RTTAggregationBytes) {
DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
- if (GetQuicReloadableFlag(
- quic_avoid_overestimate_bandwidth_with_aggregation)) {
- EXPECT_APPROX_EQ(params.BottleneckBandwidth(),
- sender_->ExportDebugState().bandwidth_hi, 0.01f);
- } else {
- EXPECT_LE(params.BottleneckBandwidth() * 0.99f,
- sender_->ExportDebugState().bandwidth_hi);
- // TODO(b/36022633): Bandwidth sampler overestimates with aggregation.
- EXPECT_GE(params.BottleneckBandwidth() * 1.5f,
- sender_->ExportDebugState().bandwidth_hi);
- }
+ EXPECT_APPROX_EQ(params.BottleneckBandwidth(),
+ sender_->ExportDebugState().bandwidth_hi, 0.01f);
+
EXPECT_LE(sender_loss_rate_in_packets(), 0.05);
// The margin here is high, because the aggregation greatly increases
// smoothed rtt.
@@ -459,10 +448,7 @@ TEST_F(Bbr2DefaultTopologyTest, SimpleTransfer2RTTAggregationBytes) {
}
TEST_F(Bbr2DefaultTopologyTest, SimpleTransferAckDecimation) {
- if (GetQuicReloadableFlag(
- quic_avoid_overestimate_bandwidth_with_aggregation)) {
- SetConnectionOption(kBSAO);
- }
+ SetConnectionOption(kBSAO);
// Enable Ack Decimation on the receiver.
QuicConnectionPeer::SetAckMode(receiver_endpoint_.connection(),
AckMode::ACK_DECIMATION);
@@ -473,17 +459,9 @@ TEST_F(Bbr2DefaultTopologyTest, SimpleTransferAckDecimation) {
DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
- if (GetQuicReloadableFlag(
- quic_avoid_overestimate_bandwidth_with_aggregation)) {
- EXPECT_APPROX_EQ(params.BottleneckBandwidth(),
- sender_->ExportDebugState().bandwidth_hi, 0.01f);
- } else {
- EXPECT_LE(params.BottleneckBandwidth() * 0.99f,
- sender_->ExportDebugState().bandwidth_hi);
- // TODO(b/36022633): Bandwidth sampler overestimates with aggregation.
- EXPECT_GE(params.BottleneckBandwidth() * 1.1f,
- sender_->ExportDebugState().bandwidth_hi);
- }
+ EXPECT_APPROX_EQ(params.BottleneckBandwidth(),
+ sender_->ExportDebugState().bandwidth_hi, 0.01f);
+
EXPECT_LE(sender_loss_rate_in_packets(), 0.001);
EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited);
// The margin here is high, because the aggregation greatly increases
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc
index f150ec14787..6c6f3efd2ad 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc
@@ -32,10 +32,6 @@ const float kDefaultHighGain = 2.885f;
const float kDerivedHighGain = 2.773f;
// The newly derived CWND gain for STARTUP, 2.
const float kDerivedHighCWNDGain = 2.0f;
-// The gain used in STARTUP after loss has been detected.
-// 1.5 is enough to allow for 25% exogenous loss and still observe a 25% growth
-// in measured bandwidth.
-const float kStartupAfterLossGain = 1.5f;
// The cycle of gains used during the PROBE_BW stage.
const float kPacingGain[] = {1.25, 0.75, 1, 1, 1, 1, 1, 1};
@@ -106,8 +102,6 @@ BbrSender::BbrSender(QuicTime now,
congestion_window_gain_constant_(
static_cast<float>(GetQuicFlag(FLAGS_quic_bbr_cwnd_gain))),
num_startup_rtts_(kRoundTripsWithoutGrowthBeforeExitingStartup),
- exit_startup_on_loss_(
- GetQuicReloadableFlag(quic_bbr_default_exit_startup_on_loss)),
cycle_current_offset_(0),
last_cycle_start_(QuicTime::Zero()),
is_at_full_bandwidth_(false),
@@ -138,10 +132,7 @@ BbrSender::BbrSender(QuicTime now,
stats_->slowstart_duration = QuicTimeAccumulator();
}
EnterStartupMode(now);
- if (exit_startup_on_loss_) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_bbr_default_exit_startup_on_loss);
- set_high_cwnd_gain(kDerivedHighCWNDGain);
- }
+ set_high_cwnd_gain(kDerivedHighCWNDGain);
}
BbrSender::~BbrSender() {}
@@ -203,14 +194,8 @@ QuicByteCount BbrSender::GetCongestionWindow() const {
return ProbeRttCongestionWindow();
}
- if (exit_startup_on_loss_) {
- if (InRecovery()) {
- return std::min(congestion_window_, recovery_window_);
- }
- } else {
- if (InRecovery() && !(rate_based_startup_ && mode_ == STARTUP)) {
- return std::min(congestion_window_, recovery_window_);
- }
+ if (InRecovery()) {
+ return std::min(congestion_window_, recovery_window_);
}
return congestion_window_;
@@ -265,17 +250,9 @@ void BbrSender::SetFromConfig(const QuicConfig& config,
if (config.HasClientRequestedIndependentOption(k2RTT, perspective)) {
num_startup_rtts_ = 2;
}
- if (!exit_startup_on_loss_ &&
- config.HasClientRequestedIndependentOption(kBBRS, perspective)) {
- slower_startup_ = true;
- }
if (config.HasClientRequestedIndependentOption(kBBR3, perspective)) {
drain_to_target_ = true;
}
- if (!exit_startup_on_loss_ &&
- config.HasClientRequestedIndependentOption(kBBS1, perspective)) {
- rate_based_startup_ = true;
- }
if (GetQuicReloadableFlag(quic_bbr_mitigate_overly_large_bandwidth_sample)) {
if (config.HasClientRequestedIndependentOption(kBWM3, perspective)) {
bytes_lost_multiplier_with_network_parameters_adjusted_ = 3;
@@ -313,11 +290,7 @@ void BbrSender::SetFromConfig(const QuicConfig& config,
max_congestion_window_with_network_parameters_adjusted_ =
100 * kDefaultTCPMSS;
}
- if (GetQuicReloadableFlag(
- quic_avoid_overestimate_bandwidth_with_aggregation) &&
- config.HasClientRequestedIndependentOption(kBSAO, perspective)) {
- QUIC_RELOADABLE_FLAG_COUNT_N(
- quic_avoid_overestimate_bandwidth_with_aggregation, 3, 4);
+ if (config.HasClientRequestedIndependentOption(kBSAO, perspective)) {
sampler_.EnableOverestimateAvoidance();
}
@@ -325,14 +298,7 @@ void BbrSender::SetFromConfig(const QuicConfig& config,
}
void BbrSender::ApplyConnectionOptions(
- const QuicTagVector& connection_options) {
- if (ContainsQuicTag(connection_options, kLRTT)) {
- exit_startup_on_loss_ = true;
- }
- if (ContainsQuicTag(connection_options, kBBQ2)) {
- set_high_cwnd_gain(kDerivedHighCWNDGain);
- }
-}
+ const QuicTagVector& /*connection_options*/) {}
void BbrSender::AdjustNetworkParameters(const NetworkParams& params) {
const QuicBandwidth& bandwidth = params.bandwidth;
@@ -352,12 +318,16 @@ void BbrSender::AdjustNetworkParameters(const NetworkParams& params) {
// Ignore bad bandwidth samples.
return;
}
+
+ auto cwnd_bootstrapping_rtt = params.quic_bbr_donot_inject_bandwidth
+ ? GetMinRtt()
+ : rtt_stats_->SmoothedOrInitialRtt();
const QuicByteCount new_cwnd = std::max(
kMinInitialCongestionWindow * kDefaultTCPMSS,
std::min(max_congestion_window_with_network_parameters_adjusted_,
- bandwidth * (params.quic_bbr_donot_inject_bandwidth
- ? GetMinRtt()
- : rtt_stats_->SmoothedOrInitialRtt())));
+ bandwidth * cwnd_bootstrapping_rtt));
+
+ stats_->cwnd_bootstrapping_rtt_us = cwnd_bootstrapping_rtt.ToMicroseconds();
if (!rtt_stats_->smoothed_rtt().IsZero()) {
QUIC_CODE_COUNT(quic_smoothed_rtt_available);
} else if (rtt_stats_->initial_rtt() !=
@@ -434,7 +404,7 @@ void BbrSender::OnCongestionEvent(bool /*rtt_updated*/,
// ack-only packets). In both cases, sampler_.total_bytes_acked() will not
// change.
if (total_bytes_acked_before != sampler_.total_bytes_acked()) {
- QUIC_BUG_IF(sample.sample_max_bandwidth.IsZero())
+ QUIC_LOG_IF(WARNING, sample.sample_max_bandwidth.IsZero())
<< sampler_.total_bytes_acked() - total_bytes_acked_before
<< " bytes from " << acked_packets.size()
<< " packets have been acked, but sample_max_bandwidth is zero.";
@@ -502,13 +472,10 @@ QuicTime::Delta BbrSender::GetMinRtt() const {
if (!min_rtt_.IsZero()) {
return min_rtt_;
}
- if (GetQuicReloadableFlag(quic_bbr_use_available_min_rtt)) {
- // min_rtt could be available if the handshake packet gets neutered then
- // gets acknowledged. This could only happen for QUIC crypto where we do not
- // drop keys.
- return rtt_stats_->MinOrInitialRtt();
- }
- return rtt_stats_->initial_rtt();
+ // min_rtt could be available if the handshake packet gets neutered then
+ // gets acknowledged. This could only happen for QUIC crypto where we do not
+ // drop keys.
+ return rtt_stats_->MinOrInitialRtt();
}
QuicByteCount BbrSender::GetTargetCongestionWindow(float gain) const {
@@ -675,10 +642,6 @@ void BbrSender::OnExitStartup(QuicTime now) {
bool BbrSender::ShouldExitStartupDueToLoss(
const SendTimeState& last_packet_send_state) const {
- if (!exit_startup_on_loss_) {
- return false;
- }
-
if (num_loss_events_in_round_ <
GetQuicFlag(FLAGS_quic_bbr2_default_startup_full_loss_count) ||
!last_packet_send_state.is_valid) {
@@ -749,7 +712,7 @@ void BbrSender::UpdateRecoveryState(QuicPacketNumber last_acked_packet,
bool has_losses,
bool is_round_start) {
// Disable recovery in startup, if loss-based exit is enabled.
- if (exit_startup_on_loss_ && !is_at_full_bandwidth_) {
+ if (!is_at_full_bandwidth_) {
return;
}
@@ -843,16 +806,6 @@ void BbrSender::CalculatePacingRate(QuicByteCount bytes_lost) {
}
}
- if (!exit_startup_on_loss_) {
- // Slow the pacing rate in STARTUP once loss has ever been detected.
- const bool has_ever_detected_loss = end_recovery_at_.IsInitialized();
- if (slower_startup_ && has_ever_detected_loss &&
- has_non_app_limited_sample_) {
- pacing_rate_ = kStartupAfterLossGain * BandwidthEstimate();
- return;
- }
- }
-
// Do not decrease the pacing rate during startup.
pacing_rate_ = std::max(pacing_rate_, target_rate);
}
@@ -898,10 +851,6 @@ void BbrSender::CalculateCongestionWindow(QuicByteCount bytes_acked,
void BbrSender::CalculateRecoveryWindow(QuicByteCount bytes_acked,
QuicByteCount bytes_lost) {
- if (!exit_startup_on_loss_ && rate_based_startup_ && mode_ == STARTUP) {
- return;
- }
-
if (recovery_state_ == NOT_IN_RECOVERY) {
return;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h
index c7285d76f24..446f0ddff8d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h
@@ -326,13 +326,6 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface {
// The number of RTTs to stay in STARTUP mode. Defaults to 3.
QuicRoundTripCount num_startup_rtts_;
- // Latched value of --quic_bbr_default_exit_startup_on_loss.
- // If true, exit startup if all of the following conditions are met:
- // - 1RTT has passed with no bandwidth increase,
- // - Some number of congestion events happened with loss, in the last round.
- // - Some amount of inflight bytes (at the start of the last round) are lost.
- bool exit_startup_on_loss_;
-
// Number of round-trips in PROBE_BW mode, used for determining the current
// pacing gain cycle.
int cycle_current_offset_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc
index e50a7c04c61..88559185087 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc
@@ -115,6 +115,9 @@ class BbrSenderTest : public QuicTest {
}
void SetUp() override {
+ SetQuicReloadableFlag(quic_fix_bbr_cwnd_in_bandwidth_resumption, true);
+ SetQuicReloadableFlag(quic_bbr_fix_pacing_rate, true);
+ SetQuicReloadableFlag(quic_bbr_donot_inject_bandwidth, true);
if (GetQuicFlag(FLAGS_quic_bbr_test_regression_mode) == "regress") {
SendAlgorithmTestResult expected;
ASSERT_TRUE(LoadSendAlgorithmTestResult(&expected));
@@ -389,10 +392,7 @@ TEST_F(BbrSenderTest, RemoveBytesLostInRecovery) {
// Test a simple long data transfer with 2 rtts of aggregation.
TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes) {
- if (GetQuicReloadableFlag(
- quic_avoid_overestimate_bandwidth_with_aggregation)) {
- SetConnectionOption(kBSAO);
- }
+ SetConnectionOption(kBSAO);
CreateDefaultSetup();
// 2 RTTs of aggregation, with a max of 10kb.
EnableAggregation(10 * 1024, 2 * kTestRtt);
@@ -401,20 +401,10 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes) {
DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
EXPECT_TRUE(sender_->ExportDebugState().mode == BbrSender::PROBE_BW ||
sender_->ExportDebugState().mode == BbrSender::PROBE_RTT);
- if (GetQuicReloadableFlag(
- quic_avoid_overestimate_bandwidth_with_aggregation)) {
- EXPECT_APPROX_EQ(kTestLinkBandwidth,
- sender_->ExportDebugState().max_bandwidth, 0.01f);
- } else {
- // It's possible to read a bandwidth as much as 50% too high with
- // aggregation.
- EXPECT_LE(kTestLinkBandwidth * 0.93f,
- sender_->ExportDebugState().max_bandwidth);
- // TODO(ianswett): Tighten this bound once we understand why BBR is
- // overestimating bandwidth with aggregation. b/36022633
- EXPECT_GE(kTestLinkBandwidth * 1.5f,
- sender_->ExportDebugState().max_bandwidth);
- }
+
+ EXPECT_APPROX_EQ(kTestLinkBandwidth,
+ sender_->ExportDebugState().max_bandwidth, 0.01f);
+
// The margin here is high, because the aggregation greatly increases
// smoothed rtt.
EXPECT_GE(kTestRtt * 4, rtt_stats_->smoothed_rtt());
@@ -423,10 +413,7 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes) {
// Test a simple long data transfer with 2 rtts of aggregation.
TEST_F(BbrSenderTest, SimpleTransferAckDecimation) {
- if (GetQuicReloadableFlag(
- quic_avoid_overestimate_bandwidth_with_aggregation)) {
- SetConnectionOption(kBSAO);
- }
+ SetConnectionOption(kBSAO);
// Decrease the CWND gain so extra CWND is required with stretch acks.
SetQuicFlag(FLAGS_quic_bbr_cwnd_gain, 1.0);
sender_ = new BbrSender(
@@ -446,20 +433,9 @@ TEST_F(BbrSenderTest, SimpleTransferAckDecimation) {
DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode);
- if (GetQuicReloadableFlag(
- quic_avoid_overestimate_bandwidth_with_aggregation)) {
- EXPECT_APPROX_EQ(kTestLinkBandwidth,
- sender_->ExportDebugState().max_bandwidth, 0.01f);
- } else {
- // It's possible to read a bandwidth as much as 50% too high with
- // aggregation.
- EXPECT_LE(kTestLinkBandwidth * 0.93f,
- sender_->ExportDebugState().max_bandwidth);
- // TODO(ianswett): Tighten this bound once we understand why BBR is
- // overestimating bandwidth with aggregation. b/36022633
- EXPECT_GE(kTestLinkBandwidth * 1.5f,
- sender_->ExportDebugState().max_bandwidth);
- }
+ EXPECT_APPROX_EQ(kTestLinkBandwidth,
+ sender_->ExportDebugState().max_bandwidth, 0.01f);
+
// TODO(ianswett): Expect 0 packets are lost once BBR no longer measures
// bandwidth higher than the link rate.
EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited);
@@ -471,10 +447,7 @@ TEST_F(BbrSenderTest, SimpleTransferAckDecimation) {
// Test a simple long data transfer with 2 rtts of aggregation.
TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes20RTTWindow) {
- if (GetQuicReloadableFlag(
- quic_avoid_overestimate_bandwidth_with_aggregation)) {
- SetConnectionOption(kBSAO);
- }
+ SetConnectionOption(kBSAO);
// Disable Ack Decimation on the receiver, because it can increase srtt.
QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING);
CreateDefaultSetup();
@@ -486,20 +459,10 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes20RTTWindow) {
DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
EXPECT_TRUE(sender_->ExportDebugState().mode == BbrSender::PROBE_BW ||
sender_->ExportDebugState().mode == BbrSender::PROBE_RTT);
- if (GetQuicReloadableFlag(
- quic_avoid_overestimate_bandwidth_with_aggregation)) {
- EXPECT_APPROX_EQ(kTestLinkBandwidth,
- sender_->ExportDebugState().max_bandwidth, 0.01f);
- } else {
- // It's possible to read a bandwidth as much as 50% too high with
- // aggregation.
- EXPECT_LE(kTestLinkBandwidth * 0.93f,
- sender_->ExportDebugState().max_bandwidth);
- // TODO(ianswett): Tighten this bound once we understand why BBR is
- // overestimating bandwidth with aggregation. b/36022633
- EXPECT_GE(kTestLinkBandwidth * 1.5f,
- sender_->ExportDebugState().max_bandwidth);
- }
+
+ EXPECT_APPROX_EQ(kTestLinkBandwidth,
+ sender_->ExportDebugState().max_bandwidth, 0.01f);
+
// TODO(ianswett): Expect 0 packets are lost once BBR no longer measures
// bandwidth higher than the link rate.
// The margin here is high, because the aggregation greatly increases
@@ -510,10 +473,7 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes20RTTWindow) {
// Test a simple long data transfer with 2 rtts of aggregation.
TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes40RTTWindow) {
- if (GetQuicReloadableFlag(
- quic_avoid_overestimate_bandwidth_with_aggregation)) {
- SetConnectionOption(kBSAO);
- }
+ SetConnectionOption(kBSAO);
// Disable Ack Decimation on the receiver, because it can increase srtt.
QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING);
CreateDefaultSetup();
@@ -525,20 +485,10 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes40RTTWindow) {
DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
EXPECT_TRUE(sender_->ExportDebugState().mode == BbrSender::PROBE_BW ||
sender_->ExportDebugState().mode == BbrSender::PROBE_RTT);
- if (GetQuicReloadableFlag(
- quic_avoid_overestimate_bandwidth_with_aggregation)) {
- EXPECT_APPROX_EQ(kTestLinkBandwidth,
- sender_->ExportDebugState().max_bandwidth, 0.01f);
- } else {
- // It's possible to read a bandwidth as much as 50% too high with
- // aggregation.
- EXPECT_LE(kTestLinkBandwidth * 0.93f,
- sender_->ExportDebugState().max_bandwidth);
- // TODO(ianswett): Tighten this bound once we understand why BBR is
- // overestimating bandwidth with aggregation. b/36022633
- EXPECT_GE(kTestLinkBandwidth * 1.5f,
- sender_->ExportDebugState().max_bandwidth);
- }
+
+ EXPECT_APPROX_EQ(kTestLinkBandwidth,
+ sender_->ExportDebugState().max_bandwidth, 0.01f);
+
// TODO(ianswett): Expect 0 packets are lost once BBR no longer measures
// bandwidth higher than the link rate.
// The margin here is high, because the aggregation greatly increases
@@ -667,17 +617,10 @@ TEST_F(BbrSenderTest, Drain) {
EXPECT_APPROX_EQ(sender_->BandwidthEstimate() * (1 / 2.885f),
sender_->PacingRate(0), 0.01f);
- if (!GetQuicReloadableFlag(quic_bbr_default_exit_startup_on_loss)) {
- // BBR uses CWND gain of 2.88 during STARTUP, hence it will fill the buffer
- // with approximately 1.88 BDPs. Here, we use 1.5 to give some margin for
- // error.
- EXPECT_GE(queue->bytes_queued(), 1.5 * kTestBdp);
- } else {
- // BBR uses CWND gain of 2 during STARTUP, hence it will fill the buffer
- // with approximately 1 BDP. Here, we use 0.8 to give some margin for
- // error.
- EXPECT_GE(queue->bytes_queued(), 0.8 * kTestBdp);
- }
+ // BBR uses CWND gain of 2 during STARTUP, hence it will fill the buffer
+ // with approximately 1 BDP. Here, we use 0.8 to give some margin for
+ // error.
+ EXPECT_GE(queue->bytes_queued(), 0.8 * kTestBdp);
// Observe increased RTT due to bufferbloat.
const QuicTime::Delta queueing_delay =
@@ -935,9 +878,6 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTStartup) {
TEST_F(BbrSenderTest, SimpleTransferExitStartupOnLoss) {
CreateDefaultSetup();
- if (!GetQuicReloadableFlag(quic_bbr_default_exit_startup_on_loss)) {
- SetConnectionOption(kLRTT);
- }
EXPECT_EQ(3u, sender_->num_startup_rtts());
// Run until the full bandwidth is reached and check how many rounds it was.
@@ -965,9 +905,6 @@ TEST_F(BbrSenderTest, SimpleTransferExitStartupOnLoss) {
TEST_F(BbrSenderTest, SimpleTransferExitStartupOnLossSmallBuffer) {
CreateSmallBufferSetup();
- if (!GetQuicReloadableFlag(quic_bbr_default_exit_startup_on_loss)) {
- SetConnectionOption(kLRTT);
- }
EXPECT_EQ(3u, sender_->num_startup_rtts());
// Run until the full bandwidth is reached and check how many rounds it was.
@@ -1021,9 +958,6 @@ TEST_F(BbrSenderTest, DerivedPacingGainStartup) {
TEST_F(BbrSenderTest, DerivedCWNDGainStartup) {
CreateSmallBufferSetup();
- if (!GetQuicReloadableFlag(quic_bbr_default_exit_startup_on_loss)) {
- SetConnectionOption(kBBQ2);
- }
EXPECT_EQ(3u, sender_->num_startup_rtts());
// Verify that Sender is in slow start.
EXPECT_TRUE(sender_->InSlowStart());
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc
index f00045e7b8e..666e7ea7c5a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc
@@ -12,6 +12,20 @@
namespace quic {
+namespace {
+float DetectionResponseTime(QuicTime::Delta rtt,
+ QuicTime send_time,
+ QuicTime detection_time) {
+ if (detection_time <= send_time || rtt.IsZero()) {
+ // Time skewed, assume a very fast detection where |detection_time| is
+ // |send_time| + |rtt|.
+ return 1.0;
+ }
+ float send_to_detection_us = (detection_time - send_time).ToMicroseconds();
+ return send_to_detection_us / rtt.ToMicroseconds();
+}
+} // namespace
+
GeneralLossAlgorithm::GeneralLossAlgorithm()
: loss_detection_timeout_(QuicTime::Zero()),
reordering_shift_(kDefaultLossDelayShift),
@@ -56,7 +70,7 @@ LossDetectionInterface::DetectionStats GeneralLossAlgorithm::DetectLosses(
QuicTime::Delta max_rtt =
std::max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt());
max_rtt = std::max(kAlarmGranularity, max_rtt);
- QuicTime::Delta loss_delay = max_rtt + (max_rtt >> reordering_shift_);
+ const QuicTime::Delta loss_delay = max_rtt + (max_rtt >> reordering_shift_);
QuicPacketNumber packet_number = unacked_packets.GetLeastUnacked();
auto it = unacked_packets.begin();
if (least_in_flight_.IsInitialized() && least_in_flight_ >= packet_number) {
@@ -100,12 +114,18 @@ LossDetectionInterface::DetectionStats GeneralLossAlgorithm::DetectLosses(
if (!skip_packet_threshold_detection &&
largest_newly_acked - packet_number >= reordering_threshold_) {
packets_lost->push_back(LostPacket(packet_number, it->bytes_sent));
+ detection_stats.total_loss_detection_response_time +=
+ DetectionResponseTime(max_rtt, it->sent_time, time);
continue;
}
// Time threshold loss detection.
QuicTime when_lost = it->sent_time + loss_delay;
if (time < when_lost) {
+ if (time >=
+ it->sent_time + max_rtt + (max_rtt >> (reordering_shift_ + 1))) {
+ ++detection_stats.sent_packets_num_borderline_time_reorderings;
+ }
loss_detection_timeout_ = when_lost;
if (!least_in_flight_.IsInitialized()) {
// At this point, packet_number is in flight and not detected as lost.
@@ -114,6 +134,8 @@ LossDetectionInterface::DetectionStats GeneralLossAlgorithm::DetectLosses(
break;
}
packets_lost->push_back(LostPacket(packet_number, it->bytes_sent));
+ detection_stats.total_loss_detection_response_time +=
+ DetectionResponseTime(max_rtt, it->sent_time, time);
}
if (!least_in_flight_.IsInitialized()) {
// There is no in flight packet.
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h
index ee8ba64c2d7..950831e4594 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h
@@ -58,6 +58,11 @@ class QUIC_EXPORT_PRIVATE GeneralLossAlgorithm : public LossDetectionInterface {
<< "Unexpected call to GeneralLossAlgorithm::OnMinRttAvailable";
}
+ void OnUserAgentIdKnown() override {
+ DCHECK(false)
+ << "Unexpected call to GeneralLossAlgorithm::OnUserAgentIdKnown";
+ }
+
void OnConnectionClosed() override {
DCHECK(false)
<< "Unexpected call to GeneralLossAlgorithm::OnConnectionClosed";
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc
index 1a58ade2695..be33c25857c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -62,14 +62,17 @@ class GeneralLossAlgorithmTest : public QuicTest {
const AckedPacketVector& packets_acked,
const std::vector<uint64_t>& losses_expected) {
return VerifyLosses(largest_newly_acked, packets_acked, losses_expected,
+ quiche::QuicheOptional<QuicPacketCount>(),
quiche::QuicheOptional<QuicPacketCount>());
}
- void VerifyLosses(uint64_t largest_newly_acked,
- const AckedPacketVector& packets_acked,
- const std::vector<uint64_t>& losses_expected,
- quiche::QuicheOptional<QuicPacketCount>
- max_sequence_reordering_expected) {
+ void VerifyLosses(
+ uint64_t largest_newly_acked,
+ const AckedPacketVector& packets_acked,
+ const std::vector<uint64_t>& losses_expected,
+ quiche::QuicheOptional<QuicPacketCount> max_sequence_reordering_expected,
+ quiche::QuicheOptional<QuicPacketCount>
+ num_borderline_time_reorderings_expected) {
unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace(
APPLICATION_DATA, QuicPacketNumber(largest_newly_acked));
LostPacketVector lost_packets;
@@ -80,6 +83,10 @@ class GeneralLossAlgorithmTest : public QuicTest {
EXPECT_EQ(stats.sent_packets_max_sequence_reordering,
max_sequence_reordering_expected.value());
}
+ if (num_borderline_time_reorderings_expected.has_value()) {
+ EXPECT_EQ(stats.sent_packets_num_borderline_time_reorderings,
+ num_borderline_time_reorderings_expected.value());
+ }
ASSERT_EQ(losses_expected.size(), lost_packets.size());
for (size_t i = 0; i < losses_expected.size(); ++i) {
EXPECT_EQ(lost_packets[i].packet_number,
@@ -104,19 +111,19 @@ TEST_F(GeneralLossAlgorithmTest, NackRetransmit1Packet) {
unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
packets_acked.push_back(AckedPacket(
QuicPacketNumber(2), kMaxOutgoingPacketSize, QuicTime::Zero()));
- VerifyLosses(2, packets_acked, std::vector<uint64_t>{}, 1);
+ VerifyLosses(2, packets_acked, std::vector<uint64_t>{}, 1, 0);
packets_acked.clear();
// No loss on two acks.
unacked_packets_.RemoveFromInFlight(QuicPacketNumber(3));
packets_acked.push_back(AckedPacket(
QuicPacketNumber(3), kMaxOutgoingPacketSize, QuicTime::Zero()));
- VerifyLosses(3, packets_acked, std::vector<uint64_t>{}, 2);
+ VerifyLosses(3, packets_acked, std::vector<uint64_t>{}, 2, 0);
packets_acked.clear();
// Loss on three acks.
unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4));
packets_acked.push_back(AckedPacket(
QuicPacketNumber(4), kMaxOutgoingPacketSize, QuicTime::Zero()));
- VerifyLosses(4, packets_acked, {1}, 3);
+ VerifyLosses(4, packets_acked, {1}, 3, 0);
EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
}
@@ -176,7 +183,12 @@ TEST_F(GeneralLossAlgorithmTest, EarlyRetransmit1Packet) {
EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(),
loss_algorithm_.GetLossTimeout());
- clock_.AdvanceTime(1.25 * rtt_stats_.latest_rtt());
+ clock_.AdvanceTime(1.13 * rtt_stats_.latest_rtt());
+ // If reordering_shift increases by one we should have detected a loss.
+ VerifyLosses(2, packets_acked, {}, /*max_sequence_reordering_expected=*/1,
+ /*num_borderline_time_reorderings_expected=*/1);
+
+ clock_.AdvanceTime(0.13 * rtt_stats_.latest_rtt());
VerifyLosses(2, packets_acked, {1});
EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h
index 8d91976de45..6799de97ae5 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h
@@ -29,6 +29,10 @@ class QUIC_EXPORT_PRIVATE LossDetectionInterface {
struct QUIC_NO_EXPORT DetectionStats {
// Maximum sequence reordering observed in newly acked packets.
QuicPacketCount sent_packets_max_sequence_reordering = 0;
+ QuicPacketCount sent_packets_num_borderline_time_reorderings = 0;
+ // Total detection response time for lost packets from this detection.
+ // See QuicConnectionStats for the definition of detection response time.
+ float total_loss_detection_response_time = 0.0;
};
// Called when a new ack arrives or the loss alarm fires.
@@ -56,6 +60,8 @@ class QUIC_EXPORT_PRIVATE LossDetectionInterface {
virtual void OnMinRttAvailable() = 0;
+ virtual void OnUserAgentIdKnown() = 0;
+
virtual void OnConnectionClosed() = 0;
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.cc
index 0f294d6b94e..5debad62c6b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.cc
@@ -54,6 +54,10 @@ LossDetectionInterface::DetectionStats UberLossAlgorithm::DetectLosses(
overall_stats.sent_packets_max_sequence_reordering =
std::max(overall_stats.sent_packets_max_sequence_reordering,
stats.sent_packets_max_sequence_reordering);
+ overall_stats.sent_packets_num_borderline_time_reorderings +=
+ stats.sent_packets_num_borderline_time_reorderings;
+ overall_stats.total_loss_detection_response_time +=
+ stats.total_loss_detection_response_time;
}
return overall_stats;
@@ -96,11 +100,27 @@ void UberLossAlgorithm::SetLossDetectionTuner(
}
void UberLossAlgorithm::MaybeStartTuning() {
- if (tuner_started_ || !tuning_enabled_ || !min_rtt_available_) {
+ if (tuner_started_ || !tuning_enabled_ || !min_rtt_available_ ||
+ !user_agent_known_) {
return;
}
tuner_started_ = tuner_->Start(&tuned_parameters_);
+ if (!tuner_started_) {
+ return;
+ }
+
+ if (tuned_parameters_.reordering_shift.has_value() &&
+ tuned_parameters_.reordering_threshold.has_value()) {
+ QUIC_DLOG(INFO) << "Setting reordering shift to "
+ << *tuned_parameters_.reordering_shift
+ << ", and reordering threshold to "
+ << *tuned_parameters_.reordering_threshold;
+ SetReorderingShift(*tuned_parameters_.reordering_shift);
+ SetReorderingThreshold(*tuned_parameters_.reordering_threshold);
+ } else {
+ QUIC_BUG << "Tuner started but some parameters are missing";
+ }
}
void UberLossAlgorithm::OnConfigNegotiated() {}
@@ -110,6 +130,11 @@ void UberLossAlgorithm::OnMinRttAvailable() {
MaybeStartTuning();
}
+void UberLossAlgorithm::OnUserAgentIdKnown() {
+ user_agent_known_ = true;
+ MaybeStartTuning();
+}
+
void UberLossAlgorithm::OnConnectionClosed() {
if (tuner_ != nullptr && tuner_started_) {
tuner_->Finish(tuned_parameters_);
@@ -151,6 +176,10 @@ QuicPacketCount UberLossAlgorithm::GetPacketReorderingThreshold() const {
return general_loss_algorithms_[APPLICATION_DATA].reordering_threshold();
}
+int UberLossAlgorithm::GetPacketReorderingShift() const {
+ return general_loss_algorithms_[APPLICATION_DATA].reordering_shift();
+}
+
void UberLossAlgorithm::DisablePacketThresholdForRuntPackets() {
for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
general_loss_algorithms_[i].disable_packet_threshold_for_runt_packets();
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h
index 86b652572b7..0d1453c07b3 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h
@@ -7,6 +7,7 @@
#include "net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h"
namespace quic {
@@ -72,6 +73,7 @@ class QUIC_EXPORT_PRIVATE UberLossAlgorithm : public LossDetectionInterface {
std::unique_ptr<LossDetectionTunerInterface> tuner);
void OnConfigNegotiated() override;
void OnMinRttAvailable() override;
+ void OnUserAgentIdKnown() override;
void OnConnectionClosed() override;
// Sets reordering_shift for all packet number spaces.
@@ -93,12 +95,25 @@ class QUIC_EXPORT_PRIVATE UberLossAlgorithm : public LossDetectionInterface {
// Always 3 when adaptive reordering is not enabled.
QuicPacketCount GetPacketReorderingThreshold() const;
+ // Get the packet reordering shift from the APPLICATION_DATA PN space.
+ int GetPacketReorderingShift() const;
+
// Disable packet threshold loss detection for *runt* packets.
void DisablePacketThresholdForRuntPackets();
// Called to reset loss detection of |space|.
void ResetLossDetection(PacketNumberSpace space);
+ bool use_adaptive_reordering_threshold() const {
+ return general_loss_algorithms_[APPLICATION_DATA]
+ .use_adaptive_reordering_threshold();
+ }
+
+ bool use_adaptive_time_threshold() const {
+ return general_loss_algorithms_[APPLICATION_DATA]
+ .use_adaptive_time_threshold();
+ }
+
private:
friend class test::QuicSentPacketManagerPeer;
@@ -112,6 +127,10 @@ class QUIC_EXPORT_PRIVATE UberLossAlgorithm : public LossDetectionInterface {
LossDetectionParameters tuned_parameters_;
bool tuner_started_ = false;
bool min_rtt_available_ = false;
+ // If flag is false, set |user_agent_known_| to true, so loss detection tuner
+ // will start once SetFromConfig is called and min rtt is available.
+ bool user_agent_known_ =
+ !GetQuicReloadableFlag(quic_save_user_agent_in_quic_session);
bool tuning_enabled_ = false; // Whether tuning is enabled by config.
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc
index 6fd949f317a..e6635402d68 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc
@@ -4,9 +4,12 @@
#include "net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h"
+#include <memory>
#include <utility>
#include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
@@ -204,6 +207,143 @@ TEST_F(UberLossAlgorithmTest, PacketInLimbo) {
VerifyLosses(6, packets_acked_, std::vector<uint64_t>{2});
}
+class TestLossTuner : public LossDetectionTunerInterface {
+ public:
+ TestLossTuner(bool forced_start_result,
+ LossDetectionParameters forced_parameters)
+ : forced_start_result_(forced_start_result),
+ forced_parameters_(std::move(forced_parameters)) {}
+
+ ~TestLossTuner() override = default;
+
+ bool Start(LossDetectionParameters* params) override {
+ start_called_ = true;
+ *params = forced_parameters_;
+ return forced_start_result_;
+ }
+
+ void Finish(const LossDetectionParameters& /*params*/) override {}
+
+ bool start_called() const { return start_called_; }
+
+ private:
+ bool forced_start_result_;
+ LossDetectionParameters forced_parameters_;
+ bool start_called_ = false;
+};
+
+// Verify the parameters are changed if first call SetFromConfig(), then call
+// OnMinRttAvailable().
+TEST_F(UberLossAlgorithmTest, LossDetectionTuning_SetFromConfigFirst) {
+ const int old_reordering_shift = loss_algorithm_.GetPacketReorderingShift();
+ const QuicPacketCount old_reordering_threshold =
+ loss_algorithm_.GetPacketReorderingThreshold();
+
+ loss_algorithm_.OnUserAgentIdKnown();
+
+ // Not owned.
+ TestLossTuner* test_tuner = new TestLossTuner(
+ /*forced_start_result=*/true,
+ LossDetectionParameters{
+ /*reordering_shift=*/old_reordering_shift + 1,
+ /*reordering_threshold=*/old_reordering_threshold * 2});
+ loss_algorithm_.SetLossDetectionTuner(
+ std::unique_ptr<LossDetectionTunerInterface>(test_tuner));
+
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(kELDT);
+ config.SetInitialReceivedConnectionOptions(connection_options);
+ loss_algorithm_.SetFromConfig(config, Perspective::IS_SERVER);
+
+ // MinRtt was not available when SetFromConfig was called.
+ EXPECT_FALSE(test_tuner->start_called());
+ EXPECT_EQ(old_reordering_shift, loss_algorithm_.GetPacketReorderingShift());
+ EXPECT_EQ(old_reordering_threshold,
+ loss_algorithm_.GetPacketReorderingThreshold());
+
+ // Tuning should start when MinRtt becomes available.
+ loss_algorithm_.OnMinRttAvailable();
+ EXPECT_TRUE(test_tuner->start_called());
+ EXPECT_NE(old_reordering_shift, loss_algorithm_.GetPacketReorderingShift());
+ EXPECT_NE(old_reordering_threshold,
+ loss_algorithm_.GetPacketReorderingThreshold());
+}
+
+// Verify the parameters are changed if first call OnMinRttAvailable(), then
+// call SetFromConfig().
+TEST_F(UberLossAlgorithmTest, LossDetectionTuning_OnMinRttAvailableFirst) {
+ const int old_reordering_shift = loss_algorithm_.GetPacketReorderingShift();
+ const QuicPacketCount old_reordering_threshold =
+ loss_algorithm_.GetPacketReorderingThreshold();
+
+ loss_algorithm_.OnUserAgentIdKnown();
+
+ // Not owned.
+ TestLossTuner* test_tuner = new TestLossTuner(
+ /*forced_start_result=*/true,
+ LossDetectionParameters{
+ /*reordering_shift=*/old_reordering_shift + 1,
+ /*reordering_threshold=*/old_reordering_threshold * 2});
+ loss_algorithm_.SetLossDetectionTuner(
+ std::unique_ptr<LossDetectionTunerInterface>(test_tuner));
+
+ loss_algorithm_.OnMinRttAvailable();
+ EXPECT_FALSE(test_tuner->start_called());
+ EXPECT_EQ(old_reordering_shift, loss_algorithm_.GetPacketReorderingShift());
+ EXPECT_EQ(old_reordering_threshold,
+ loss_algorithm_.GetPacketReorderingThreshold());
+
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(kELDT);
+ config.SetInitialReceivedConnectionOptions(connection_options);
+ // Should start tuning since MinRtt is available.
+ loss_algorithm_.SetFromConfig(config, Perspective::IS_SERVER);
+
+ EXPECT_TRUE(test_tuner->start_called());
+ EXPECT_NE(old_reordering_shift, loss_algorithm_.GetPacketReorderingShift());
+ EXPECT_NE(old_reordering_threshold,
+ loss_algorithm_.GetPacketReorderingThreshold());
+}
+
+// Verify the parameters are not changed if Tuner.Start() returns false.
+TEST_F(UberLossAlgorithmTest, LossDetectionTuning_StartFailed) {
+ const int old_reordering_shift = loss_algorithm_.GetPacketReorderingShift();
+ const QuicPacketCount old_reordering_threshold =
+ loss_algorithm_.GetPacketReorderingThreshold();
+
+ loss_algorithm_.OnUserAgentIdKnown();
+
+ // Not owned.
+ TestLossTuner* test_tuner = new TestLossTuner(
+ /*forced_start_result=*/false,
+ LossDetectionParameters{
+ /*reordering_shift=*/old_reordering_shift + 1,
+ /*reordering_threshold=*/old_reordering_threshold * 2});
+ loss_algorithm_.SetLossDetectionTuner(
+ std::unique_ptr<LossDetectionTunerInterface>(test_tuner));
+
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(kELDT);
+ config.SetInitialReceivedConnectionOptions(connection_options);
+ loss_algorithm_.SetFromConfig(config, Perspective::IS_SERVER);
+
+ // MinRtt was not available when SetFromConfig was called.
+ EXPECT_FALSE(test_tuner->start_called());
+ EXPECT_EQ(old_reordering_shift, loss_algorithm_.GetPacketReorderingShift());
+ EXPECT_EQ(old_reordering_threshold,
+ loss_algorithm_.GetPacketReorderingThreshold());
+
+ // Parameters should not change since test_tuner->Start() returns false.
+ loss_algorithm_.OnMinRttAvailable();
+ EXPECT_TRUE(test_tuner->start_called());
+ EXPECT_EQ(old_reordering_shift, loss_algorithm_.GetPacketReorderingShift());
+ EXPECT_EQ(old_reordering_threshold,
+ loss_algorithm_.GetPacketReorderingThreshold());
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc
index 0f17d121ca0..af6b54c5863 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc
@@ -4,6 +4,7 @@
#include "net/third_party/quiche/src/quic/core/crypto/certificate_view.h"
+#include <algorithm>
#include <cstdint>
#include <memory>
#include <string>
@@ -17,6 +18,8 @@
#include "third_party/boringssl/src/include/openssl/rsa.h"
#include "third_party/boringssl/src/include/openssl/ssl.h"
#include "net/third_party/quiche/src/quic/core/crypto/boring_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_time.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
@@ -24,10 +27,17 @@
#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_time_utils.h"
+#include "net/third_party/quiche/src/common/quiche_data_reader.h"
+
+namespace {
+
+using ::quiche::QuicheOptional;
+using ::quiche::QuicheStringPiece;
+using ::quiche::QuicheTextUtils;
// The literals below were encoded using `ascii2der | xxd -i`. The comments
// above the literals are the contents in the der2ascii syntax.
-namespace {
// X.509 version 3 (version numbering starts with zero).
// INTEGER { 2 }
@@ -94,22 +104,54 @@ PublicKeyType PublicKeyTypeFromSignatureAlgorithm(
namespace quic {
+QuicheOptional<quic::QuicWallTime> ParseDerTime(unsigned tag,
+ QuicheStringPiece payload) {
+ if (tag != CBS_ASN1_GENERALIZEDTIME && tag != CBS_ASN1_UTCTIME) {
+ QUIC_BUG << "Invalid tag supplied for a DER timestamp";
+ return QUICHE_NULLOPT;
+ }
+
+ const size_t year_length = tag == CBS_ASN1_GENERALIZEDTIME ? 4 : 2;
+ uint64_t year, month, day, hour, minute, second;
+ quiche::QuicheDataReader reader(payload);
+ if (!reader.ReadDecimal64(year_length, &year) ||
+ !reader.ReadDecimal64(2, &month) || !reader.ReadDecimal64(2, &day) ||
+ !reader.ReadDecimal64(2, &hour) || !reader.ReadDecimal64(2, &minute) ||
+ !reader.ReadDecimal64(2, &second) ||
+ reader.ReadRemainingPayload() != "Z") {
+ QUIC_DLOG(WARNING) << "Failed to parse the DER timestamp";
+ return QUICHE_NULLOPT;
+ }
+
+ if (tag == CBS_ASN1_UTCTIME) {
+ DCHECK_LE(year, 100u);
+ year += (year >= 50) ? 1900 : 2000;
+ }
+
+ const QuicheOptional<int64_t> unix_time =
+ quiche::QuicheUtcDateTimeToUnixSeconds(year, month, day, hour, minute,
+ second);
+ if (!unix_time.has_value() || *unix_time < 0) {
+ return QUICHE_NULLOPT;
+ }
+ return QuicWallTime::FromUNIXSeconds(*unix_time);
+}
+
PemReadResult ReadNextPemMessage(std::istream* input) {
- constexpr quiche::QuicheStringPiece kPemBegin = "-----BEGIN ";
- constexpr quiche::QuicheStringPiece kPemEnd = "-----END ";
- constexpr quiche::QuicheStringPiece kPemDashes = "-----";
+ constexpr QuicheStringPiece kPemBegin = "-----BEGIN ";
+ constexpr QuicheStringPiece kPemEnd = "-----END ";
+ constexpr QuicheStringPiece kPemDashes = "-----";
std::string line_buffer, encoded_message_contents, expected_end;
bool pending_message = false;
PemReadResult result;
while (std::getline(*input, line_buffer)) {
- quiche::QuicheStringPiece line(line_buffer);
- quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&line);
+ QuicheStringPiece line(line_buffer);
+ QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&line);
// Handle BEGIN lines.
- if (!pending_message &&
- quiche::QuicheTextUtils::StartsWith(line, kPemBegin) &&
- quiche::QuicheTextUtils::EndsWith(line, kPemDashes)) {
+ if (!pending_message && QuicheTextUtils::StartsWith(line, kPemBegin) &&
+ QuicheTextUtils::EndsWith(line, kPemDashes)) {
result.type = std::string(
line.substr(kPemBegin.size(),
line.size() - kPemDashes.size() - kPemBegin.size()));
@@ -120,8 +162,8 @@ PemReadResult ReadNextPemMessage(std::istream* input) {
// Handle END lines.
if (pending_message && line == expected_end) {
- quiche::QuicheOptional<std::string> data =
- quiche::QuicheTextUtils::Base64Decode(encoded_message_contents);
+ QuicheOptional<std::string> data =
+ QuicheTextUtils::Base64Decode(encoded_message_contents);
if (data.has_value()) {
result.status = PemReadResult::kOk;
result.contents = data.value();
@@ -137,11 +179,11 @@ PemReadResult ReadNextPemMessage(std::istream* input) {
}
bool eof_reached = input->eof() && !pending_message;
return PemReadResult{
- .status = (eof_reached ? PemReadResult::kEof : PemReadResult::kError)};
+ (eof_reached ? PemReadResult::kEof : PemReadResult::kError), "", ""};
}
std::unique_ptr<CertificateView> CertificateView::ParseSingleCertificate(
- quiche::QuicheStringPiece certificate) {
+ QuicheStringPiece certificate) {
std::unique_ptr<CertificateView> result(new CertificateView());
CBS top = StringPieceToCbs(certificate);
@@ -215,6 +257,25 @@ std::unique_ptr<CertificateView> CertificateView::ParseSingleCertificate(
return nullptr;
}
+ unsigned not_before_tag, not_after_tag;
+ CBS not_before, not_after;
+ if (!CBS_get_any_asn1(&validity, &not_before, &not_before_tag) ||
+ !CBS_get_any_asn1(&validity, &not_after, &not_after_tag) ||
+ CBS_len(&validity) != 0) {
+ QUIC_DLOG(WARNING) << "Failed to extract the validity dates";
+ return nullptr;
+ }
+ QuicheOptional<QuicWallTime> not_before_parsed =
+ ParseDerTime(not_before_tag, CbsToStringPiece(not_before));
+ QuicheOptional<QuicWallTime> not_after_parsed =
+ ParseDerTime(not_after_tag, CbsToStringPiece(not_after));
+ if (!not_before_parsed.has_value() || !not_after_parsed.has_value()) {
+ QUIC_DLOG(WARNING) << "Failed to parse validity dates";
+ return nullptr;
+ }
+ result->validity_start_ = *not_before_parsed;
+ result->validity_end_ = *not_after_parsed;
+
result->public_key_.reset(EVP_parse_public_key(&spki));
if (result->public_key_ == nullptr) {
QUIC_DLOG(WARNING) << "Failed to parse the public key";
@@ -286,7 +347,7 @@ bool CertificateView::ParseExtensions(CBS extensions) {
return false;
}
- quiche::QuicheStringPiece alt_name = CbsToStringPiece(alt_name_cbs);
+ QuicheStringPiece alt_name = CbsToStringPiece(alt_name_cbs);
QuicIpAddress ip_address;
// GeneralName ::= CHOICE {
switch (alt_name_tag) {
@@ -306,8 +367,8 @@ bool CertificateView::ParseExtensions(CBS extensions) {
break;
default:
- QUIC_DLOG(WARNING) << "Invalid subjectAltName tag";
- return false;
+ QUIC_DLOG(INFO) << "Unknown subjectAltName tag " << alt_name_tag;
+ continue;
}
}
}
@@ -355,8 +416,8 @@ bool CertificateView::ValidatePublicKeyParameters() {
}
}
-bool CertificateView::VerifySignature(quiche::QuicheStringPiece data,
- quiche::QuicheStringPiece signature,
+bool CertificateView::VerifySignature(QuicheStringPiece data,
+ QuicheStringPiece signature,
uint16_t signature_algorithm) const {
if (PublicKeyTypeFromSignatureAlgorithm(signature_algorithm) !=
PublicKeyTypeFromKey(public_key_.get())) {
@@ -386,7 +447,7 @@ bool CertificateView::VerifySignature(quiche::QuicheStringPiece data,
}
std::unique_ptr<CertificatePrivateKey> CertificatePrivateKey::LoadFromDer(
- quiche::QuicheStringPiece private_key) {
+ QuicheStringPiece private_key) {
std::unique_ptr<CertificatePrivateKey> result(new CertificatePrivateKey());
CBS private_key_cbs = StringPieceToCbs(private_key);
result->private_key_.reset(EVP_parse_private_key(&private_key_cbs));
@@ -423,7 +484,7 @@ std::unique_ptr<CertificatePrivateKey> CertificatePrivateKey::LoadPemFromStream(
return nullptr;
}
-std::string CertificatePrivateKey::Sign(quiche::QuicheStringPiece input,
+std::string CertificatePrivateKey::Sign(QuicheStringPiece input,
uint16_t signature_algorithm) {
if (PublicKeyTypeFromSignatureAlgorithm(signature_algorithm) !=
PublicKeyTypeFromKey(private_key_.get())) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.h b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.h
index 286226d7e20..13bb5ff14ae 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.h
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.h
@@ -13,8 +13,11 @@
#include "third_party/boringssl/src/include/openssl/bytestring.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
#include "net/third_party/quiche/src/quic/core/crypto/boring_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_time.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
namespace quic {
@@ -46,6 +49,8 @@ class QUIC_EXPORT_PRIVATE CertificateView {
// without parsing them. Returns an empty vector if any parsing error occurs.
static std::vector<std::string> LoadPemFromStream(std::istream* input);
+ QuicWallTime validity_start() const { return validity_start_; }
+ QuicWallTime validity_end() const { return validity_end_; }
const EVP_PKEY* public_key() const { return public_key_.get(); }
const std::vector<quiche::QuicheStringPiece>& subject_alt_name_domains()
@@ -64,6 +69,9 @@ class QUIC_EXPORT_PRIVATE CertificateView {
private:
CertificateView() = default;
+ QuicWallTime validity_start_ = QuicWallTime::Zero();
+ QuicWallTime validity_end_ = QuicWallTime::Zero();
+
// Public key parsed from SPKI.
bssl::UniquePtr<EVP_PKEY> public_key_;
@@ -103,6 +111,12 @@ class QUIC_EXPORT_PRIVATE CertificatePrivateKey {
bssl::UniquePtr<EVP_PKEY> private_key_;
};
+// Parses a DER time based on the specified ASN.1 tag. Exposed primarily for
+// testing.
+QUIC_EXPORT_PRIVATE quiche::QuicheOptional<quic::QuicWallTime> ParseDerTime(
+ unsigned tag,
+ quiche::QuicheStringPiece payload);
+
} // namespace quic
#endif // QUICHE_QUIC_CORE_CRYPTO_CERTIFICATE_VIEW_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_test.cc
index b0b52f14f3b..ad512143243 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_test.cc
@@ -8,19 +8,23 @@
#include <sstream>
#include "third_party/boringssl/src/include/openssl/base.h"
+#include "third_party/boringssl/src/include/openssl/bytestring.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
#include "third_party/boringssl/src/include/openssl/ssl.h"
+#include "net/third_party/quiche/src/quic/core/quic_time.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/test_certificates.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_time_utils.h"
namespace quic {
namespace test {
namespace {
-using testing::ElementsAre;
-using testing::HasSubstr;
+using ::testing::ElementsAre;
+using ::testing::HasSubstr;
+using ::testing::Optional;
TEST(CertificateViewTest, PemParser) {
std::stringstream stream(kTestCertificatePem);
@@ -45,6 +49,24 @@ TEST(CertificateViewTest, Parse) {
EXPECT_THAT(view->subject_alt_name_ips(),
ElementsAre(QuicIpAddress::Loopback4()));
EXPECT_EQ(EVP_PKEY_id(view->public_key()), EVP_PKEY_RSA);
+
+ const QuicWallTime validity_start = QuicWallTime::FromUNIXSeconds(
+ *quiche::QuicheUtcDateTimeToUnixSeconds(2020, 1, 30, 18, 13, 59));
+ EXPECT_EQ(view->validity_start(), validity_start);
+ const QuicWallTime validity_end = QuicWallTime::FromUNIXSeconds(
+ *quiche::QuicheUtcDateTimeToUnixSeconds(2020, 2, 2, 18, 13, 59));
+ EXPECT_EQ(view->validity_end(), validity_end);
+}
+
+TEST(CertificateViewTest, ParseCertWithUnknownSanType) {
+ std::stringstream stream(kTestCertWithUnknownSanTypePem);
+ PemReadResult result = ReadNextPemMessage(&stream);
+ EXPECT_EQ(result.status, PemReadResult::kOk);
+ EXPECT_EQ(result.type, "CERTIFICATE");
+
+ std::unique_ptr<CertificateView> view =
+ CertificateView::ParseSingleCertificate(result.contents);
+ EXPECT_TRUE(view != nullptr);
}
TEST(CertificateViewTest, PemSingleCertificate) {
@@ -109,6 +131,47 @@ TEST(CertificateViewTest, PrivateKeyPem) {
EXPECT_TRUE(legacy_key->MatchesPublicKey(*view));
}
+TEST(CertificateViewTest, DerTime) {
+ EXPECT_THAT(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19700101000024Z"),
+ Optional(QuicWallTime::FromUNIXSeconds(24)));
+ EXPECT_THAT(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19710101000024Z"),
+ Optional(QuicWallTime::FromUNIXSeconds(365 * 86400 + 24)));
+ EXPECT_THAT(ParseDerTime(CBS_ASN1_UTCTIME, "700101000024Z"),
+ Optional(QuicWallTime::FromUNIXSeconds(24)));
+ EXPECT_TRUE(ParseDerTime(CBS_ASN1_UTCTIME, "200101000024Z").has_value());
+
+ EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, ""), QUICHE_NULLOPT);
+ EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19700101000024.001Z"),
+ QUICHE_NULLOPT);
+ EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19700101000024Q"),
+ QUICHE_NULLOPT);
+ EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19700101000024-0500"),
+ QUICHE_NULLOPT);
+ EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "700101000024ZZ"),
+ QUICHE_NULLOPT);
+ EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19700101000024.00Z"),
+ QUICHE_NULLOPT);
+ EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19700101000024.Z"),
+ QUICHE_NULLOPT);
+ EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "197O0101000024Z"),
+ QUICHE_NULLOPT);
+ EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19700101000024.0O1Z"),
+ QUICHE_NULLOPT);
+ EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "-9700101000024Z"),
+ QUICHE_NULLOPT);
+ EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "1970-101000024Z"),
+ QUICHE_NULLOPT);
+
+ EXPECT_TRUE(ParseDerTime(CBS_ASN1_UTCTIME, "490101000024Z").has_value());
+ // This should parse as 1950, which predates UNIX epoch.
+ EXPECT_FALSE(ParseDerTime(CBS_ASN1_UTCTIME, "500101000024Z").has_value());
+
+ EXPECT_THAT(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19700101230000Z"),
+ Optional(QuicWallTime::FromUNIXSeconds(23 * 3600)));
+ EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19700101240000Z"),
+ QUICHE_NULLOPT);
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h
index 172fd822d0b..4beec0bdf90 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h
@@ -125,6 +125,8 @@ const QuicTag kB2CL = TAG('B', '2', 'C', 'L'); // For BBRv2, allow PROBE_BW
// cwnd to be below BDP + ack
// height.
const QuicTag kB2LO = TAG('B', '2', 'L', 'O'); // Ignore inflight_lo in BBR2
+const QuicTag kB2HI = TAG('B', '2', 'H', 'I'); // Limit inflight_hi reduction
+ // based on CWND.
const QuicTag kBSAO = TAG('B', 'S', 'A', 'O'); // Avoid Overestimation in
// Bandwidth Sampler with ack
// aggregation
@@ -160,7 +162,13 @@ const QuicTag kACKQ = TAG('A', 'C', 'K', 'Q'); // Send an immediate ack after
// 1 RTT of not receiving.
const QuicTag kSSLR = TAG('S', 'S', 'L', 'R'); // Slow Start Large Reduction.
const QuicTag kNPRR = TAG('N', 'P', 'R', 'R'); // Pace at unity instead of PRR
+const QuicTag k2RTO = TAG('2', 'R', 'T', 'O'); // Close connection on 2 RTOs
+const QuicTag k3RTO = TAG('3', 'R', 'T', 'O'); // Close connection on 3 RTOs
+const QuicTag k4RTO = TAG('4', 'R', 'T', 'O'); // Close connection on 4 RTOs
const QuicTag k5RTO = TAG('5', 'R', 'T', 'O'); // Close connection on 5 RTOs
+const QuicTag k6RTO = TAG('6', 'R', 'T', 'O'); // Close connection on 6 RTOs
+const QuicTag kCBHD = TAG('C', 'B', 'H', 'D'); // Client only blackhole
+ // detection.
const QuicTag kCONH = TAG('C', 'O', 'N', 'H'); // Conservative Handshake
// Retransmissions.
const QuicTag kLFAK = TAG('L', 'F', 'A', 'K'); // Don't invoke FACK on the
@@ -225,6 +233,8 @@ const QuicTag kPLE2 = TAG('P', 'L', 'E', '2'); // Arm the 1st PTO with
// earliest in flight sent time
// and at least 1.5*srtt from
// last sent packet.
+const QuicTag kAPTO = TAG('A', 'P', 'T', 'O'); // Use 1.5 * initial RTT before
+ // any RTT sample is available.
const QuicTag kELDT = TAG('E', 'L', 'D', 'T'); // Enable Loss Detection Tuning
@@ -329,6 +339,9 @@ const QuicTag kCFCW = TAG('C', 'F', 'C', 'W'); // Initial session/connection
// flow control receive window.
const QuicTag kUAID = TAG('U', 'A', 'I', 'D'); // Client's User Agent ID.
const QuicTag kXLCT = TAG('X', 'L', 'C', 'T'); // Expected leaf certificate.
+const QuicTag kQLVE = TAG('Q', 'L', 'V', 'E'); // Legacy Version
+ // Encapsulation.
+const QuicTag kQNZR = TAG('Q', 'N', 'Z', 'R'); // Turn off QUIC crypto 0-RTT.
const QuicTag kMAD = TAG('M', 'A', 'D', 0); // Max Ack Delay (IETF QUIC)
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc
index ee9dc53cf64..58d39b8f7d6 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc
@@ -508,6 +508,12 @@ TEST_P(CryptoServerTest, RejectTooLargeButValidSTK) {
}
TEST_P(CryptoServerTest, TooSmall) {
+ if (GetQuicReloadableFlag(quic_dont_pad_chlo)) {
+ // This test validates that non-padded CHLOs are rejected, it cannot pass
+ // when the padding is no longer required.
+ // TODO(dschinazi) remove this test when we deprecate quic_dont_pad_chlo.
+ return;
+ }
ShouldFailMentioning(
"too small", crypto_test_utils::CreateCHLO(
{{"PDMD", "X509"}, {"VER\0", client_version_string_}}));
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc
index b6c6b7ae434..3127edec87b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc
@@ -117,10 +117,16 @@ namespace {
// Salt from https://tools.ietf.org/html/draft-ietf-quic-tls-25#section-5.2
// and https://tools.ietf.org/html/draft-ietf-quic-tls-27#section-5.2
+// and https://tools.ietf.org/html/draft-ietf-quic-tls-28#section-5.2
const uint8_t kDraft25InitialSalt[] = {0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb,
0x5a, 0x11, 0xa7, 0xd2, 0x43, 0x2b, 0xb4,
0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02};
+// Salt from https://tools.ietf.org/html/draft-ietf-quic-tls-29#section-5.2
+const uint8_t kDraft29InitialSalt[] = {0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2,
+ 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61,
+ 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99};
+
// Salts used by deployed versions of QUIC. When introducing a new version,
// generate a new salt by running `openssl rand -hex 20`.
@@ -135,7 +141,7 @@ const uint8_t kT050Salt[] = {0x7f, 0xf5, 0x79, 0xe5, 0xac, 0xd0, 0x72,
const uint8_t* InitialSaltForVersion(const ParsedQuicVersion& version,
size_t* out_len) {
- static_assert(SupportedVersions().size() == 8u,
+ static_assert(SupportedVersions().size() == 9u,
"Supported versions out of sync with initial encryption salts");
switch (version.handshake_protocol) {
case PROTOCOL_QUIC_CRYPTO:
@@ -166,6 +172,9 @@ const uint8_t* InitialSaltForVersion(const ParsedQuicVersion& version,
// draft-27 uses the same salt as draft-25.
*out_len = QUICHE_ARRAYSIZE(kDraft25InitialSalt);
return kDraft25InitialSalt;
+ case QUIC_VERSION_IETF_DRAFT_29:
+ *out_len = QUICHE_ARRAYSIZE(kDraft29InitialSalt);
+ return kDraft29InitialSalt;
default:
QUIC_BUG << "No initial obfuscation salt for version " << version;
}
@@ -183,11 +192,20 @@ const char kPreSharedKeyLabel[] = "QUIC PSK";
// Retry Integrity Protection Keys and Nonces.
// https://tools.ietf.org/html/draft-ietf-quic-tls-25#section-5.8
// https://tools.ietf.org/html/draft-ietf-quic-tls-27#section-5.8
+// https://tools.ietf.org/html/draft-ietf-quic-tls-28#section-5.8
const uint8_t kDraft25RetryIntegrityKey[] = {0x4d, 0x32, 0xec, 0xdb, 0x2a, 0x21,
0x33, 0xc8, 0x41, 0xe4, 0x04, 0x3d,
0xf2, 0x7d, 0x44, 0x30};
const uint8_t kDraft25RetryIntegrityNonce[] = {
0x4d, 0x16, 0x11, 0xd0, 0x55, 0x13, 0xa5, 0x52, 0xc5, 0x87, 0xd5, 0x75};
+
+// https://tools.ietf.org/html/draft-ietf-quic-tls-29#section-5.8
+const uint8_t kDraft29RetryIntegrityKey[] = {0xcc, 0xce, 0x18, 0x7e, 0xd0, 0x9a,
+ 0x09, 0xd0, 0x57, 0x28, 0x15, 0x5a,
+ 0x6c, 0xb9, 0x6b, 0xe1};
+const uint8_t kDraft29RetryIntegrityNonce[] = {
+ 0xe5, 0x49, 0x30, 0xf9, 0x7f, 0x21, 0x36, 0xf0, 0x53, 0x0a, 0x8c, 0x1c};
+
// Keys used by Google versions of QUIC. When introducing a new version,
// generate a new key by running `openssl rand -hex 16`.
const uint8_t kT050RetryIntegrityKey[] = {0xc9, 0x2d, 0x32, 0x3d, 0x9c, 0xe3,
@@ -227,6 +245,15 @@ bool RetryIntegrityKeysForVersion(const ParsedQuicVersion& version,
QUICHE_ARRAYSIZE(kDraft25RetryIntegrityNonce));
return true;
}
+ if (version == ParsedQuicVersion::Draft29()) {
+ *key = quiche::QuicheStringPiece(
+ reinterpret_cast<const char*>(kDraft29RetryIntegrityKey),
+ QUICHE_ARRAYSIZE(kDraft29RetryIntegrityKey));
+ *nonce = quiche::QuicheStringPiece(
+ reinterpret_cast<const char*>(kDraft29RetryIntegrityNonce),
+ QUICHE_ARRAYSIZE(kDraft29RetryIntegrityNonce));
+ return true;
+ }
QUIC_BUG << "Attempted to get retry integrity keys for version " << version;
return false;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.cc
index 6afc65f557a..e432682bddd 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.cc
@@ -104,8 +104,8 @@ bool ProofSourceX509::AddCertificateChain(
}
certificates_.push_front(Certificate{
- .chain = chain,
- .key = std::move(key),
+ chain,
+ std::move(key),
});
Certificate* certificate = &certificates_.front();
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc
index 7f8edc22cfe..9314e99f293 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc
@@ -67,7 +67,10 @@ QuicCryptoClientConfig::QuicCryptoClientConfig(
std::unique_ptr<SessionCache> session_cache)
: proof_verifier_(std::move(proof_verifier)),
session_cache_(std::move(session_cache)),
- ssl_ctx_(TlsClientConnection::CreateSslCtx()) {
+ enable_zero_rtt_for_tls_(
+ GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls)),
+ ssl_ctx_(TlsClientConnection::CreateSslCtx(enable_zero_rtt_for_tls_)),
+ disable_chlo_padding_(GetQuicReloadableFlag(quic_dont_pad_chlo)) {
DCHECK(proof_verifier_.get());
SetDefaults();
}
@@ -132,16 +135,6 @@ QuicCryptoClientConfig::CachedState::GetServerConfig() const {
return scfg_.get();
}
-void QuicCryptoClientConfig::CachedState::add_server_designated_connection_id(
- QuicConnectionId connection_id) {
- server_designated_connection_ids_.push(connection_id);
-}
-
-bool QuicCryptoClientConfig::CachedState::has_server_designated_connection_id()
- const {
- return !server_designated_connection_ids_.empty();
-}
-
void QuicCryptoClientConfig::CachedState::add_server_nonce(
const std::string& server_nonce) {
server_nonces_.push(server_nonce);
@@ -204,9 +197,6 @@ void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() {
server_config_.clear();
scfg_.reset();
SetProofInvalid();
- QuicQueue<QuicConnectionId> empty_queue;
- using std::swap;
- swap(server_designated_connection_ids_, empty_queue);
}
void QuicCryptoClientConfig::CachedState::SetProof(
@@ -249,9 +239,6 @@ void QuicCryptoClientConfig::CachedState::Clear() {
proof_verify_details_.reset();
scfg_.reset();
++generation_counter_;
- QuicQueue<QuicConnectionId> empty_queue;
- using std::swap;
- swap(server_designated_connection_ids_, empty_queue);
}
void QuicCryptoClientConfig::CachedState::ClearProof() {
@@ -370,7 +357,6 @@ void QuicCryptoClientConfig::CachedState::InitializeFrom(
chlo_hash_ = other.chlo_hash_;
server_config_sig_ = other.server_config_sig_;
server_config_valid_ = other.server_config_valid_;
- server_designated_connection_ids_ = other.server_designated_connection_ids_;
expiration_time_ = other.expiration_time_;
if (other.proof_verify_details_ != nullptr) {
proof_verify_details_.reset(other.proof_verify_details_->Clone());
@@ -378,18 +364,6 @@ void QuicCryptoClientConfig::CachedState::InitializeFrom(
++generation_counter_;
}
-QuicConnectionId
-QuicCryptoClientConfig::CachedState::GetNextServerDesignatedConnectionId() {
- if (server_designated_connection_ids_.empty()) {
- QUIC_BUG
- << "Attempting to consume a connection id that was never designated.";
- return EmptyQuicConnectionId();
- }
- const QuicConnectionId next_id = server_designated_connection_ids_.front();
- server_designated_connection_ids_.pop();
- return next_id;
-}
-
std::string QuicCryptoClientConfig::CachedState::GetNextServerNonce() {
if (server_nonces_.empty()) {
QUIC_BUG
@@ -447,7 +421,7 @@ void QuicCryptoClientConfig::FillInchoateClientHello(
CryptoHandshakeMessage* out) const {
out->set_tag(kCHLO);
// TODO(rch): Remove this when we remove quic_use_chlo_packet_size flag.
- if (pad_inchoate_hello_) {
+ if (pad_inchoate_hello_ && !disable_chlo_padding_) {
out->set_minimum_size(kClientHelloMinimumSize);
} else {
out->set_minimum_size(1);
@@ -536,7 +510,7 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello(
FillInchoateClientHello(server_id, preferred_version, cached, rand,
/* demand_x509_proof= */ true, out_params, out);
- if (pad_full_hello_) {
+ if (pad_full_hello_ && !disable_chlo_padding_) {
out->set_minimum_size(kClientHelloMinimumSize);
} else {
out->set_minimum_size(1);
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h
index e3867c8e7b2..ce0efe530c7 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h
@@ -76,6 +76,10 @@ class QUIC_EXPORT_PRIVATE SessionCache {
virtual std::unique_ptr<QuicResumptionState> Lookup(
const QuicServerId& server_id,
const SSL_CTX* ctx) = 0;
+
+ // Called when 0-RTT is rejected. Disables early data for all the TLS tickets
+ // associated with |server_id|.
+ virtual void ClearEarlyData(const QuicServerId& server_id) = 0;
};
// QuicCryptoClientConfig contains crypto-related configuration settings for a
@@ -171,20 +175,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
void set_cert_sct(quiche::QuicheStringPiece cert_sct);
- // Adds the connection ID to the queue of server-designated connection-ids.
- void add_server_designated_connection_id(QuicConnectionId connection_id);
-
- // If true, the crypto config contains at least one connection ID specified
- // by the server, and the client should use one of these IDs when initiating
- // the next connection.
- bool has_server_designated_connection_id() const;
-
- // This function should only be called when
- // has_server_designated_connection_id is true. Returns the next
- // connection_id specified by the server and removes it from the
- // queue of ids.
- QuicConnectionId GetNextServerDesignatedConnectionId();
-
// Adds the servernonce to the queue of server nonces.
void add_server_nonce(const std::string& server_nonce);
@@ -238,10 +228,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
// scfg contains the cached, parsed value of |server_config|.
mutable std::unique_ptr<CryptoHandshakeMessage> scfg_;
- // TODO(jokulik): Consider using a hash-set as extra book-keeping to ensure
- // that no connection-id is added twice. Also, consider keeping the server
- // nonces and connection_ids together in one queue.
- QuicQueue<QuicConnectionId> server_designated_connection_ids_;
QuicQueue<std::string> server_nonces_;
};
@@ -368,6 +354,8 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
void set_proof_source(std::unique_ptr<ProofSource> proof_source);
SSL_CTX* ssl_ctx() const;
+ bool early_data_enabled_for_tls() const { return enable_zero_rtt_for_tls_; }
+
// Initialize the CachedState from |canonical_crypto_config| for the
// |canonical_server_id| as the initial CachedState for |server_id|. We will
// copy config data only if |canonical_crypto_config| has valid proof.
@@ -409,6 +397,10 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
bool pad_full_hello() const { return pad_full_hello_; }
void set_pad_full_hello(bool new_value) { pad_full_hello_ = new_value; }
+ void set_disable_chlo_padding(bool disabled) {
+ disable_chlo_padding_ = disabled;
+ }
+
private:
// Sets the members to reasonable, default values.
void SetDefaults();
@@ -450,6 +442,9 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
std::unique_ptr<ProofVerifier> proof_verifier_;
std::unique_ptr<SessionCache> session_cache_;
std::unique_ptr<ProofSource> proof_source_;
+
+ // Latched value of reloadable flag quic_enable_zero_rtt_for_tls
+ bool enable_zero_rtt_for_tls_;
bssl::UniquePtr<SSL_CTX> ssl_ctx_;
// The |user_agent_id_| passed in QUIC's CHLO message.
@@ -475,6 +470,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
// other means of verifying the client.
bool pad_inchoate_hello_ = true;
bool pad_full_hello_ = true;
+ bool disable_chlo_padding_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config_test.cc
index 4b6dcd71bcb..c995e8a87c0 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config_test.cc
@@ -81,46 +81,6 @@ TEST_F(QuicCryptoClientConfigTest, CachedState_SetProofVerifyDetails) {
EXPECT_EQ(details, state.proof_verify_details());
}
-TEST_F(QuicCryptoClientConfigTest, CachedState_ServerDesignatedConnectionId) {
- QuicCryptoClientConfig::CachedState state;
- EXPECT_FALSE(state.has_server_designated_connection_id());
-
- uint64_t conn_id = 1234;
- QuicConnectionId connection_id = TestConnectionId(conn_id);
- state.add_server_designated_connection_id(connection_id);
- EXPECT_TRUE(state.has_server_designated_connection_id());
- EXPECT_EQ(connection_id, state.GetNextServerDesignatedConnectionId());
- EXPECT_FALSE(state.has_server_designated_connection_id());
-
- // Allow the ID to be set multiple times. It's unusual that this would
- // happen, but not impossible.
- connection_id = TestConnectionId(++conn_id);
- state.add_server_designated_connection_id(connection_id);
- EXPECT_TRUE(state.has_server_designated_connection_id());
- EXPECT_EQ(connection_id, state.GetNextServerDesignatedConnectionId());
- connection_id = TestConnectionId(++conn_id);
- state.add_server_designated_connection_id(connection_id);
- EXPECT_EQ(connection_id, state.GetNextServerDesignatedConnectionId());
- EXPECT_FALSE(state.has_server_designated_connection_id());
-
- // Test FIFO behavior.
- const QuicConnectionId first_cid = TestConnectionId(0xdeadbeef);
- const QuicConnectionId second_cid = TestConnectionId(0xfeedbead);
- state.add_server_designated_connection_id(first_cid);
- state.add_server_designated_connection_id(second_cid);
- EXPECT_TRUE(state.has_server_designated_connection_id());
- EXPECT_EQ(first_cid, state.GetNextServerDesignatedConnectionId());
- EXPECT_EQ(second_cid, state.GetNextServerDesignatedConnectionId());
-}
-
-TEST_F(QuicCryptoClientConfigTest, CachedState_ServerIdConsumedBeforeSet) {
- QuicCryptoClientConfig::CachedState state;
- EXPECT_FALSE(state.has_server_designated_connection_id());
- EXPECT_QUIC_BUG(state.GetNextServerDesignatedConnectionId(),
- "Attempting to consume a connection id "
- "that was never designated.");
-}
-
TEST_F(QuicCryptoClientConfigTest, CachedState_ServerNonce) {
QuicCryptoClientConfig::CachedState state;
EXPECT_FALSE(state.has_server_nonce());
@@ -170,7 +130,6 @@ TEST_F(QuicCryptoClientConfigTest, CachedState_InitializeFrom) {
EXPECT_EQ(state.source_address_token(), other.source_address_token());
EXPECT_EQ(state.certs(), other.certs());
EXPECT_EQ(1u, other.generation_counter());
- EXPECT_FALSE(state.has_server_designated_connection_id());
EXPECT_FALSE(state.has_server_nonce());
}
@@ -200,7 +159,11 @@ TEST_F(QuicCryptoClientConfigTest, InchoateChlo) {
EXPECT_TRUE(msg.GetStringPiece(kALPN, &alpn));
EXPECT_EQ("hq", alpn);
- EXPECT_EQ(msg.minimum_size(), 1024u);
+ if (GetQuicReloadableFlag(quic_dont_pad_chlo)) {
+ EXPECT_EQ(msg.minimum_size(), 1u);
+ } else {
+ EXPECT_EQ(msg.minimum_size(), 1024u);
+ }
}
TEST_F(QuicCryptoClientConfigTest, InchoateChloIsNotPadded) {
@@ -532,7 +495,6 @@ TEST_F(QuicCryptoClientConfigTest, ProcessReject) {
AllSupportedTransportVersions().front(),
"", &cached, out_params, &error),
IsQuicNoError());
- EXPECT_FALSE(cached.has_server_designated_connection_id());
EXPECT_FALSE(cached.has_server_nonce());
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc
index 9cb089bf0e8..c07b8d3bf11 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc
@@ -1211,10 +1211,14 @@ void QuicCryptoServerConfig::EvaluateClientHello(
const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello;
ClientHelloInfo* info = &(client_hello_state->info);
- if (validate_chlo_size_ && client_hello.size() < kClientHelloMinimumSize) {
- helper.ValidationComplete(QUIC_CRYPTO_INVALID_VALUE_LENGTH,
- "Client hello too small", nullptr);
- return;
+ if (GetQuicReloadableFlag(quic_dont_pad_chlo)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_dont_pad_chlo, 1, 2);
+ } else {
+ if (validate_chlo_size_ && client_hello.size() < kClientHelloMinimumSize) {
+ helper.ValidationComplete(QUIC_CRYPTO_INVALID_VALUE_LENGTH,
+ "Client hello too small", nullptr);
+ return;
+ }
}
if (client_hello.GetStringPiece(kSNI, &info->sni) &&
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.cc
index 7d112245b3c..79088473bbc 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.cc
@@ -11,7 +11,8 @@ TlsClientConnection::TlsClientConnection(SSL_CTX* ssl_ctx, Delegate* delegate)
delegate_(delegate) {}
// static
-bssl::UniquePtr<SSL_CTX> TlsClientConnection::CreateSslCtx() {
+bssl::UniquePtr<SSL_CTX> TlsClientConnection::CreateSslCtx(
+ bool enable_early_data) {
bssl::UniquePtr<SSL_CTX> ssl_ctx = TlsConnection::CreateSslCtx();
// Configure certificate verification.
SSL_CTX_set_custom_verify(ssl_ctx.get(), SSL_VERIFY_PEER, &VerifyCallback);
@@ -22,6 +23,8 @@ bssl::UniquePtr<SSL_CTX> TlsClientConnection::CreateSslCtx() {
SSL_CTX_set_session_cache_mode(
ssl_ctx.get(), SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL);
SSL_CTX_sess_set_new_cb(ssl_ctx.get(), NewSessionCallback);
+
+ SSL_CTX_set_early_data_enabled(ssl_ctx.get(), enable_early_data);
return ssl_ctx;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h
index 035f420a835..a7ef209792f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h
@@ -39,7 +39,7 @@ class QUIC_EXPORT_PRIVATE TlsClientConnection : public TlsConnection {
TlsClientConnection(SSL_CTX* ssl_ctx, Delegate* delegate);
// Creates and configures an SSL_CTX that is appropriate for clients to use.
- static bssl::UniquePtr<SSL_CTX> CreateSslCtx();
+ static bssl::UniquePtr<SSL_CTX> CreateSslCtx(bool enable_early_data);
private:
// Registered as the callback for SSL_CTX_set_custom_verify. The
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.cc
index 75d28c55d60..8e4d391db4b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.cc
@@ -114,28 +114,6 @@ const SSL_QUIC_METHOD TlsConnection::kSslQuicMethod{
TlsConnection::SendAlertCallback};
// static
-int TlsConnection::SetEncryptionSecretCallback(
- SSL* ssl,
- enum ssl_encryption_level_t level,
- const uint8_t* read_key,
- const uint8_t* write_key,
- size_t key_length) {
- // TODO(nharper): replace these vectors and memcpys with spans (which
- // unfortunately doesn't yet exist in quic/platform/api).
- std::vector<uint8_t> read_secret(key_length), write_secret(key_length);
- memcpy(read_secret.data(), read_key, key_length);
- memcpy(write_secret.data(), write_key, key_length);
- TlsConnection::Delegate* delegate = ConnectionFromSsl(ssl)->delegate_;
- const SSL_CIPHER* cipher = SSL_get_pending_cipher(ssl);
- delegate->SetWriteSecret(QuicEncryptionLevel(level), cipher, write_secret);
- if (!delegate->SetReadSecret(QuicEncryptionLevel(level), cipher,
- read_secret)) {
- return 0;
- }
- return 1;
-}
-
-// static
int TlsConnection::SetReadSecretCallback(SSL* ssl,
enum ssl_encryption_level_t level,
const SSL_CIPHER* cipher,
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.h b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.h
index d65f63c68e5..15a4f4f9a3a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.h
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.h
@@ -101,11 +101,6 @@ class QUIC_EXPORT_PRIVATE TlsConnection {
static const SSL_QUIC_METHOD kSslQuicMethod;
// The following static functions make up the members of kSslQuicMethod:
- static int SetEncryptionSecretCallback(SSL* ssl,
- enum ssl_encryption_level_t level,
- const uint8_t* read_key,
- const uint8_t* write_key,
- size_t key_length);
static int SetReadSecretCallback(SSL* ssl,
enum ssl_encryption_level_t level,
const SSL_CIPHER* cipher,
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc
index 3e286adc84b..330a14d5ea2 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc
@@ -10,6 +10,8 @@
#include <memory>
#include <utility>
+#include "third_party/boringssl/src/include/openssl/digest.h"
+#include "third_party/boringssl/src/include/openssl/sha.h"
#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h"
#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
@@ -31,8 +33,8 @@ namespace quic {
// which parameter is encoded. The supported draft version is noted in
// transport_parameters.h.
enum TransportParameters::TransportParameterId : uint64_t {
- kOriginalConnectionId = 0,
- kIdleTimeout = 1,
+ kOriginalDestinationConnectionId = 0,
+ kMaxIdleTimeout = 1,
kStatelessResetToken = 2,
kMaxPacketSize = 3,
kInitialMaxData = 4,
@@ -43,15 +45,18 @@ enum TransportParameters::TransportParameterId : uint64_t {
kInitialMaxStreamsUni = 9,
kAckDelayExponent = 0xa,
kMaxAckDelay = 0xb,
- kDisableMigration = 0xc,
+ kDisableActiveMigration = 0xc,
kPreferredAddress = 0xd,
kActiveConnectionIdLimit = 0xe,
+ kInitialSourceConnectionId = 0xf,
+ kRetrySourceConnectionId = 0x10,
kMaxDatagramFrameSize = 0x20,
kInitialRoundTripTime = 0x3127,
kGoogleConnectionOptions = 0x3128,
kGoogleUserAgentId = 0x3129,
+ kGoogleSupportHandshakeDone = 0x312A, // Only used in T050.
kGoogleQuicParam = 18257, // Used for non-standard Google-specific params.
kGoogleQuicVersion =
18258, // Used to transmit version and supported_versions.
@@ -74,14 +79,14 @@ constexpr uint64_t kDefaultActiveConnectionIdLimitTransportParam = 2;
std::string TransportParameterIdToString(
TransportParameters::TransportParameterId param_id) {
switch (param_id) {
- case TransportParameters::kOriginalConnectionId:
- return "original_connection_id";
- case TransportParameters::kIdleTimeout:
- return "idle_timeout";
+ case TransportParameters::kOriginalDestinationConnectionId:
+ return "original_destination_connection_id";
+ case TransportParameters::kMaxIdleTimeout:
+ return "max_idle_timeout";
case TransportParameters::kStatelessResetToken:
return "stateless_reset_token";
case TransportParameters::kMaxPacketSize:
- return "max_packet_size";
+ return "max_udp_payload_size";
case TransportParameters::kInitialMaxData:
return "initial_max_data";
case TransportParameters::kInitialMaxStreamDataBidiLocal:
@@ -98,12 +103,16 @@ std::string TransportParameterIdToString(
return "ack_delay_exponent";
case TransportParameters::kMaxAckDelay:
return "max_ack_delay";
- case TransportParameters::kDisableMigration:
- return "disable_migration";
+ case TransportParameters::kDisableActiveMigration:
+ return "disable_active_migration";
case TransportParameters::kPreferredAddress:
return "preferred_address";
case TransportParameters::kActiveConnectionIdLimit:
return "active_connection_id_limit";
+ case TransportParameters::kInitialSourceConnectionId:
+ return "initial_source_connection_id";
+ case TransportParameters::kRetrySourceConnectionId:
+ return "retry_source_connection_id";
case TransportParameters::kMaxDatagramFrameSize:
return "max_datagram_frame_size";
case TransportParameters::kInitialRoundTripTime:
@@ -112,6 +121,8 @@ std::string TransportParameterIdToString(
return "google_connection_options";
case TransportParameters::kGoogleUserAgentId:
return "user_agent_id";
+ case TransportParameters::kGoogleSupportHandshakeDone:
+ return "support_handshake_done";
case TransportParameters::kGoogleQuicParam:
return "google";
case TransportParameters::kGoogleQuicVersion:
@@ -123,8 +134,8 @@ std::string TransportParameterIdToString(
bool TransportParameterIdIsKnown(
TransportParameters::TransportParameterId param_id) {
switch (param_id) {
- case TransportParameters::kOriginalConnectionId:
- case TransportParameters::kIdleTimeout:
+ case TransportParameters::kOriginalDestinationConnectionId:
+ case TransportParameters::kMaxIdleTimeout:
case TransportParameters::kStatelessResetToken:
case TransportParameters::kMaxPacketSize:
case TransportParameters::kInitialMaxData:
@@ -135,13 +146,16 @@ bool TransportParameterIdIsKnown(
case TransportParameters::kInitialMaxStreamsUni:
case TransportParameters::kAckDelayExponent:
case TransportParameters::kMaxAckDelay:
- case TransportParameters::kDisableMigration:
+ case TransportParameters::kDisableActiveMigration:
case TransportParameters::kPreferredAddress:
case TransportParameters::kActiveConnectionIdLimit:
+ case TransportParameters::kInitialSourceConnectionId:
+ case TransportParameters::kRetrySourceConnectionId:
case TransportParameters::kMaxDatagramFrameSize:
case TransportParameters::kInitialRoundTripTime:
case TransportParameters::kGoogleConnectionOptions:
case TransportParameters::kGoogleUserAgentId:
+ case TransportParameters::kGoogleSupportHandshakeDone:
case TransportParameters::kGoogleQuicParam:
case TransportParameters::kGoogleQuicVersion:
return true;
@@ -401,18 +415,18 @@ std::string TransportParameters::ToString() const {
rv += " supported_versions " +
QuicVersionLabelVectorToString(supported_versions);
}
- if (original_connection_id.has_value()) {
- rv += " " + TransportParameterIdToString(kOriginalConnectionId) + " " +
- original_connection_id.value().ToString();
+ if (original_destination_connection_id.has_value()) {
+ rv += " " + TransportParameterIdToString(kOriginalDestinationConnectionId) +
+ " " + original_destination_connection_id.value().ToString();
}
- rv += idle_timeout_milliseconds.ToString(/*for_use_in_list=*/true);
+ rv += max_idle_timeout_ms.ToString(/*for_use_in_list=*/true);
if (!stateless_reset_token.empty()) {
rv += " " + TransportParameterIdToString(kStatelessResetToken) + " " +
quiche::QuicheTextUtils::HexEncode(
reinterpret_cast<const char*>(stateless_reset_token.data()),
stateless_reset_token.size());
}
- rv += max_packet_size.ToString(/*for_use_in_list=*/true);
+ rv += max_udp_payload_size.ToString(/*for_use_in_list=*/true);
rv += initial_max_data.ToString(/*for_use_in_list=*/true);
rv += initial_max_stream_data_bidi_local.ToString(/*for_use_in_list=*/true);
rv += initial_max_stream_data_bidi_remote.ToString(/*for_use_in_list=*/true);
@@ -421,14 +435,22 @@ std::string TransportParameters::ToString() const {
rv += initial_max_streams_uni.ToString(/*for_use_in_list=*/true);
rv += ack_delay_exponent.ToString(/*for_use_in_list=*/true);
rv += max_ack_delay.ToString(/*for_use_in_list=*/true);
- if (disable_migration) {
- rv += " " + TransportParameterIdToString(kDisableMigration);
+ if (disable_active_migration) {
+ rv += " " + TransportParameterIdToString(kDisableActiveMigration);
}
if (preferred_address) {
rv += " " + TransportParameterIdToString(kPreferredAddress) + " " +
preferred_address->ToString();
}
rv += active_connection_id_limit.ToString(/*for_use_in_list=*/true);
+ if (initial_source_connection_id.has_value()) {
+ rv += " " + TransportParameterIdToString(kInitialSourceConnectionId) + " " +
+ initial_source_connection_id.value().ToString();
+ }
+ if (retry_source_connection_id.has_value()) {
+ rv += " " + TransportParameterIdToString(kRetrySourceConnectionId) + " " +
+ retry_source_connection_id.value().ToString();
+ }
rv += max_datagram_frame_size.ToString(/*for_use_in_list=*/true);
rv += initial_round_trip_time_us.ToString(/*for_use_in_list=*/true);
if (google_connection_options.has_value()) {
@@ -447,12 +469,24 @@ std::string TransportParameters::ToString() const {
rv += " " + TransportParameterIdToString(kGoogleUserAgentId) + " \"" +
user_agent_id.value() + "\"";
}
+ if (support_handshake_done) {
+ rv += " " + TransportParameterIdToString(kGoogleSupportHandshakeDone);
+ }
if (google_quic_params) {
rv += " " + TransportParameterIdToString(kGoogleQuicParam);
}
for (const auto& kv : custom_parameters) {
rv += " 0x" + quiche::QuicheTextUtils::Hex(static_cast<uint32_t>(kv.first));
- rv += "=" + quiche::QuicheTextUtils::HexEncode(kv.second);
+ rv += "=";
+ static constexpr size_t kMaxPrintableLength = 32;
+ if (kv.second.length() <= kMaxPrintableLength) {
+ rv += quiche::QuicheTextUtils::HexEncode(kv.second);
+ } else {
+ quiche::QuicheStringPiece truncated(kv.second.data(),
+ kMaxPrintableLength);
+ rv += quiche::QuicheStrCat(quiche::QuicheTextUtils::HexEncode(truncated),
+ "...(length ", kv.second.length(), ")");
+ }
}
rv += "]";
return rv;
@@ -460,11 +494,11 @@ std::string TransportParameters::ToString() const {
TransportParameters::TransportParameters()
: version(0),
- idle_timeout_milliseconds(kIdleTimeout),
- max_packet_size(kMaxPacketSize,
- kDefaultMaxPacketSizeTransportParam,
- kMinMaxPacketSizeTransportParam,
- kVarInt62MaxValue),
+ max_idle_timeout_ms(kMaxIdleTimeout),
+ max_udp_payload_size(kMaxPacketSize,
+ kDefaultMaxPacketSizeTransportParam,
+ kMinMaxPacketSizeTransportParam,
+ kVarInt62MaxValue),
initial_max_data(kInitialMaxData),
initial_max_stream_data_bidi_local(kInitialMaxStreamDataBidiLocal),
initial_max_stream_data_bidi_remote(kInitialMaxStreamDataBidiRemote),
@@ -479,13 +513,14 @@ TransportParameters::TransportParameters()
kDefaultMaxAckDelayTransportParam,
0,
kMaxMaxAckDelayTransportParam),
- disable_migration(false),
+ disable_active_migration(false),
active_connection_id_limit(kActiveConnectionIdLimit,
kDefaultActiveConnectionIdLimitTransportParam,
kMinActiveConnectionIdLimitTransportParam,
kVarInt62MaxValue),
max_datagram_frame_size(kMaxDatagramFrameSize),
- initial_round_trip_time_us(kInitialRoundTripTime)
+ initial_round_trip_time_us(kInitialRoundTripTime),
+ support_handshake_done(false)
// Important note: any new transport parameters must be added
// to TransportParameters::AreValid, SerializeTransportParameters and
// ParseTransportParameters, TransportParameters's custom copy constructor, the
@@ -496,10 +531,11 @@ TransportParameters::TransportParameters(const TransportParameters& other)
: perspective(other.perspective),
version(other.version),
supported_versions(other.supported_versions),
- original_connection_id(other.original_connection_id),
- idle_timeout_milliseconds(other.idle_timeout_milliseconds),
+ original_destination_connection_id(
+ other.original_destination_connection_id),
+ max_idle_timeout_ms(other.max_idle_timeout_ms),
stateless_reset_token(other.stateless_reset_token),
- max_packet_size(other.max_packet_size),
+ max_udp_payload_size(other.max_udp_payload_size),
initial_max_data(other.initial_max_data),
initial_max_stream_data_bidi_local(
other.initial_max_stream_data_bidi_local),
@@ -510,12 +546,15 @@ TransportParameters::TransportParameters(const TransportParameters& other)
initial_max_streams_uni(other.initial_max_streams_uni),
ack_delay_exponent(other.ack_delay_exponent),
max_ack_delay(other.max_ack_delay),
- disable_migration(other.disable_migration),
+ disable_active_migration(other.disable_active_migration),
active_connection_id_limit(other.active_connection_id_limit),
+ initial_source_connection_id(other.initial_source_connection_id),
+ retry_source_connection_id(other.retry_source_connection_id),
max_datagram_frame_size(other.max_datagram_frame_size),
initial_round_trip_time_us(other.initial_round_trip_time_us),
google_connection_options(other.google_connection_options),
user_agent_id(other.user_agent_id),
+ support_handshake_done(other.support_handshake_done),
custom_parameters(other.custom_parameters) {
if (other.preferred_address) {
preferred_address = std::make_unique<TransportParameters::PreferredAddress>(
@@ -530,11 +569,11 @@ TransportParameters::TransportParameters(const TransportParameters& other)
bool TransportParameters::operator==(const TransportParameters& rhs) const {
if (!(perspective == rhs.perspective && version == rhs.version &&
supported_versions == rhs.supported_versions &&
- original_connection_id == rhs.original_connection_id &&
- idle_timeout_milliseconds.value() ==
- rhs.idle_timeout_milliseconds.value() &&
+ original_destination_connection_id ==
+ rhs.original_destination_connection_id &&
+ max_idle_timeout_ms.value() == rhs.max_idle_timeout_ms.value() &&
stateless_reset_token == rhs.stateless_reset_token &&
- max_packet_size.value() == rhs.max_packet_size.value() &&
+ max_udp_payload_size.value() == rhs.max_udp_payload_size.value() &&
initial_max_data.value() == rhs.initial_max_data.value() &&
initial_max_stream_data_bidi_local.value() ==
rhs.initial_max_stream_data_bidi_local.value() &&
@@ -548,15 +587,18 @@ bool TransportParameters::operator==(const TransportParameters& rhs) const {
rhs.initial_max_streams_uni.value() &&
ack_delay_exponent.value() == rhs.ack_delay_exponent.value() &&
max_ack_delay.value() == rhs.max_ack_delay.value() &&
- disable_migration == rhs.disable_migration &&
+ disable_active_migration == rhs.disable_active_migration &&
active_connection_id_limit.value() ==
rhs.active_connection_id_limit.value() &&
+ initial_source_connection_id == rhs.initial_source_connection_id &&
+ retry_source_connection_id == rhs.retry_source_connection_id &&
max_datagram_frame_size.value() ==
rhs.max_datagram_frame_size.value() &&
initial_round_trip_time_us.value() ==
rhs.initial_round_trip_time_us.value() &&
google_connection_options == rhs.google_connection_options &&
user_agent_id == rhs.user_agent_id &&
+ support_handshake_done == rhs.support_handshake_done &&
custom_parameters == rhs.custom_parameters)) {
return false;
}
@@ -591,8 +633,8 @@ bool TransportParameters::AreValid(std::string* error_details) const {
return false;
}
if (perspective == Perspective::IS_CLIENT &&
- original_connection_id.has_value()) {
- *error_details = "Client cannot send original connection ID";
+ original_destination_connection_id.has_value()) {
+ *error_details = "Client cannot send original_destination_connection_id";
return false;
}
if (!stateless_reset_token.empty() &&
@@ -619,6 +661,11 @@ bool TransportParameters::AreValid(std::string* error_details) const {
*error_details = "Internal preferred address family failure";
return false;
}
+ if (perspective == Perspective::IS_CLIENT &&
+ retry_source_connection_id.has_value()) {
+ *error_details = "Client cannot send retry_source_connection_id";
+ return false;
+ }
for (const auto& kv : custom_parameters) {
if (TransportParameterIdIsKnown(kv.first)) {
*error_details = quiche::QuicheStrCat(
@@ -637,7 +684,7 @@ bool TransportParameters::AreValid(std::string* error_details) const {
return false;
}
const bool ok =
- idle_timeout_milliseconds.IsValid() && max_packet_size.IsValid() &&
+ max_idle_timeout_ms.IsValid() && max_udp_payload_size.IsValid() &&
initial_max_data.IsValid() &&
initial_max_stream_data_bidi_local.IsValid() &&
initial_max_stream_data_bidi_remote.IsValid() &&
@@ -669,11 +716,78 @@ bool SerializeTransportParameters(ParsedQuicVersion version,
return false;
}
- // Empirically transport parameters generally fit within 128 bytes.
- // For now we hope this will be enough.
- // TODO(dschinazi) make this grow if needed.
- static const size_t kMaxTransportParametersLength = 4096;
- out->resize(kMaxTransportParametersLength);
+ // Maximum length of the GREASE transport parameter (see below).
+ static constexpr size_t kMaxGreaseLength = 16;
+
+ // Empirically transport parameters generally fit within 128 bytes, but we
+ // need to allocate the size up front. Integer transport parameters
+ // have a maximum encoded length of 24 bytes (3 variable length integers),
+ // other transport parameters have a length of 16 + the maximum value length.
+ static constexpr size_t kTypeAndValueLength = 2 * sizeof(uint64_t);
+ static constexpr size_t kIntegerParameterLength =
+ kTypeAndValueLength + sizeof(uint64_t);
+ static constexpr size_t kStatelessResetParameterLength =
+ kTypeAndValueLength + 16 /* stateless reset token length */;
+ static constexpr size_t kConnectionIdParameterLength =
+ kTypeAndValueLength + 255 /* maximum connection ID length */;
+ static constexpr size_t kPreferredAddressParameterLength =
+ kTypeAndValueLength + 4 /*IPv4 address */ + 2 /* IPv4 port */ +
+ 16 /* IPv6 address */ + 1 /* Connection ID length */ +
+ 255 /* maximum connection ID length */ + 16 /* stateless reset token */;
+ static constexpr size_t kGreaseParameterLength =
+ kTypeAndValueLength + kMaxGreaseLength;
+ static constexpr size_t kKnownTransportParamLength =
+ kConnectionIdParameterLength + // original_destination_connection_id
+ kIntegerParameterLength + // max_idle_timeout
+ kStatelessResetParameterLength + // stateless_reset_token
+ kIntegerParameterLength + // max_udp_payload_size
+ kIntegerParameterLength + // initial_max_data
+ kIntegerParameterLength + // initial_max_stream_data_bidi_local
+ kIntegerParameterLength + // initial_max_stream_data_bidi_remote
+ kIntegerParameterLength + // initial_max_stream_data_uni
+ kIntegerParameterLength + // initial_max_streams_bidi
+ kIntegerParameterLength + // initial_max_streams_uni
+ kIntegerParameterLength + // ack_delay_exponent
+ kIntegerParameterLength + // max_ack_delay
+ kTypeAndValueLength + // disable_active_migration
+ kPreferredAddressParameterLength + // preferred_address
+ kIntegerParameterLength + // active_connection_id_limit
+ kConnectionIdParameterLength + // initial_source_connection_id
+ kConnectionIdParameterLength + // retry_source_connection_id
+ kIntegerParameterLength + // max_datagram_frame_size
+ kIntegerParameterLength + // initial_round_trip_time_us
+ kTypeAndValueLength + // google_connection_options
+ kTypeAndValueLength + // user_agent_id
+ kTypeAndValueLength + // support_handshake_done
+ kTypeAndValueLength + // google
+ kTypeAndValueLength + // google-version
+ kGreaseParameterLength; // GREASE
+
+ size_t max_transport_param_length = kKnownTransportParamLength;
+ // google_connection_options.
+ if (in.google_connection_options.has_value()) {
+ max_transport_param_length +=
+ in.google_connection_options.value().size() * sizeof(QuicTag);
+ }
+ // user_agent_id.
+ if (in.user_agent_id.has_value()) {
+ max_transport_param_length += in.user_agent_id.value().length();
+ }
+ // Google-specific version extension.
+ max_transport_param_length +=
+ sizeof(in.version) + 1 /* versions length */ +
+ in.supported_versions.size() * sizeof(QuicVersionLabel);
+ // Custom parameters.
+ for (const auto& kv : in.custom_parameters) {
+ max_transport_param_length += kTypeAndValueLength + kv.second.length();
+ }
+ // Google-specific non-standard parameter.
+ if (in.google_quic_params) {
+ max_transport_param_length +=
+ in.google_quic_params->GetSerialized().length();
+ }
+
+ out->resize(max_transport_param_length);
QuicDataWriter writer(out->size(), reinterpret_cast<char*>(out->data()));
if (!version.HasVarIntTransportParams()) {
@@ -688,24 +802,27 @@ bool SerializeTransportParameters(ParsedQuicVersion version,
}
}
- // original_connection_id
- if (in.original_connection_id.has_value()) {
+ // original_destination_connection_id
+ if (in.original_destination_connection_id.has_value()) {
DCHECK_EQ(Perspective::IS_SERVER, in.perspective);
- QuicConnectionId original_connection_id = in.original_connection_id.value();
+ QuicConnectionId original_destination_connection_id =
+ in.original_destination_connection_id.value();
if (!WriteTransportParameterId(
- &writer, TransportParameters::kOriginalConnectionId, version) ||
+ &writer, TransportParameters::kOriginalDestinationConnectionId,
+ version) ||
!WriteTransportParameterStringPiece(
&writer,
- quiche::QuicheStringPiece(original_connection_id.data(),
- original_connection_id.length()),
+ quiche::QuicheStringPiece(
+ original_destination_connection_id.data(),
+ original_destination_connection_id.length()),
version)) {
- QUIC_BUG << "Failed to write original_connection_id "
- << in.original_connection_id.value() << " for " << in;
+ QUIC_BUG << "Failed to write original_destination_connection_id "
+ << original_destination_connection_id << " for " << in;
return false;
}
}
- if (!in.idle_timeout_milliseconds.Write(&writer, version)) {
+ if (!in.max_idle_timeout_ms.Write(&writer, version)) {
QUIC_BUG << "Failed to write idle_timeout for " << in;
return false;
}
@@ -728,7 +845,7 @@ bool SerializeTransportParameters(ParsedQuicVersion version,
}
}
- if (!in.max_packet_size.Write(&writer, version) ||
+ if (!in.max_udp_payload_size.Write(&writer, version) ||
!in.initial_max_data.Write(&writer, version) ||
!in.initial_max_stream_data_bidi_local.Write(&writer, version) ||
!in.initial_max_stream_data_bidi_remote.Write(&writer, version) ||
@@ -744,12 +861,12 @@ bool SerializeTransportParameters(ParsedQuicVersion version,
return false;
}
- // disable_migration
- if (in.disable_migration) {
+ // disable_active_migration
+ if (in.disable_active_migration) {
if (!WriteTransportParameterId(
- &writer, TransportParameters::kDisableMigration, version) ||
+ &writer, TransportParameters::kDisableActiveMigration, version) ||
!WriteTransportParameterLength(&writer, /*length=*/0, version)) {
- QUIC_BUG << "Failed to write disable_migration for " << in;
+ QUIC_BUG << "Failed to write disable_active_migration for " << in;
return false;
}
}
@@ -791,6 +908,42 @@ bool SerializeTransportParameters(ParsedQuicVersion version,
}
}
+ // initial_source_connection_id
+ if (in.initial_source_connection_id.has_value()) {
+ QuicConnectionId initial_source_connection_id =
+ in.initial_source_connection_id.value();
+ if (!WriteTransportParameterId(
+ &writer, TransportParameters::kInitialSourceConnectionId,
+ version) ||
+ !WriteTransportParameterStringPiece(
+ &writer,
+ quiche::QuicheStringPiece(initial_source_connection_id.data(),
+ initial_source_connection_id.length()),
+ version)) {
+ QUIC_BUG << "Failed to write initial_source_connection_id "
+ << initial_source_connection_id << " for " << in;
+ return false;
+ }
+ }
+
+ // retry_source_connection_id
+ if (in.retry_source_connection_id.has_value()) {
+ DCHECK_EQ(Perspective::IS_SERVER, in.perspective);
+ QuicConnectionId retry_source_connection_id =
+ in.retry_source_connection_id.value();
+ if (!WriteTransportParameterId(
+ &writer, TransportParameters::kRetrySourceConnectionId, version) ||
+ !WriteTransportParameterStringPiece(
+ &writer,
+ quiche::QuicheStringPiece(retry_source_connection_id.data(),
+ retry_source_connection_id.length()),
+ version)) {
+ QUIC_BUG << "Failed to write retry_source_connection_id "
+ << retry_source_connection_id << " for " << in;
+ return false;
+ }
+ }
+
// Google-specific connection options.
if (in.google_connection_options.has_value()) {
static_assert(sizeof(in.google_connection_options.value().front()) == 4,
@@ -827,6 +980,17 @@ bool SerializeTransportParameters(ParsedQuicVersion version,
}
}
+ // Google-specific support handshake done.
+ if (in.support_handshake_done) {
+ if (!WriteTransportParameterId(
+ &writer, TransportParameters::kGoogleSupportHandshakeDone,
+ version) ||
+ !WriteTransportParameterLength(&writer, /*length=*/0, version)) {
+ QUIC_BUG << "Failed to write support_handshake_done for " << in;
+ return false;
+ }
+ }
+
// Google-specific non-standard parameter.
if (in.google_quic_params) {
const QuicData& serialized_google_quic_params =
@@ -910,7 +1074,6 @@ bool SerializeTransportParameters(ParsedQuicVersion version,
<< grease_id64 << " invalid for " << version;
TransportParameters::TransportParameterId grease_id =
static_cast<TransportParameters::TransportParameterId>(grease_id64);
- const size_t kMaxGreaseLength = 16;
const size_t grease_length = random->RandUint64() % kMaxGreaseLength;
DCHECK_GE(kMaxGreaseLength, grease_length);
char grease_contents[kMaxGreaseLength];
@@ -989,41 +1152,43 @@ bool ParseTransportParameters(ParsedQuicVersion version,
QuicDataReader value_reader(value);
bool parse_success = true;
switch (param_id) {
- case TransportParameters::kOriginalConnectionId: {
- if (out->original_connection_id.has_value()) {
- *error_details = "Received a second original connection ID";
+ case TransportParameters::kOriginalDestinationConnectionId: {
+ if (out->original_destination_connection_id.has_value()) {
+ *error_details =
+ "Received a second original_destination_connection_id";
return false;
}
const size_t connection_id_length = value_reader.BytesRemaining();
if (!QuicUtils::IsConnectionIdLengthValidForVersion(
connection_id_length, version.transport_version)) {
*error_details = quiche::QuicheStrCat(
- "Received original connection ID of invalid length ",
+ "Received original_destination_connection_id of invalid length ",
connection_id_length);
return false;
}
- QuicConnectionId original_connection_id;
- if (!value_reader.ReadConnectionId(&original_connection_id,
+ QuicConnectionId original_destination_connection_id;
+ if (!value_reader.ReadConnectionId(&original_destination_connection_id,
connection_id_length)) {
- *error_details = "Failed to read original connection ID";
+ *error_details = "Failed to read original_destination_connection_id";
return false;
}
- out->original_connection_id = original_connection_id;
+ out->original_destination_connection_id =
+ original_destination_connection_id;
} break;
- case TransportParameters::kIdleTimeout:
+ case TransportParameters::kMaxIdleTimeout:
parse_success =
- out->idle_timeout_milliseconds.Read(&value_reader, error_details);
+ out->max_idle_timeout_ms.Read(&value_reader, error_details);
break;
case TransportParameters::kStatelessResetToken: {
if (!out->stateless_reset_token.empty()) {
- *error_details = "Received a second stateless reset token";
+ *error_details = "Received a second stateless_reset_token";
return false;
}
quiche::QuicheStringPiece stateless_reset_token =
value_reader.ReadRemainingPayload();
if (stateless_reset_token.length() != kStatelessResetTokenLength) {
*error_details = quiche::QuicheStrCat(
- "Received stateless reset token of invalid length ",
+ "Received stateless_reset_token of invalid length ",
stateless_reset_token.length());
return false;
}
@@ -1032,7 +1197,8 @@ bool ParseTransportParameters(ParsedQuicVersion version,
stateless_reset_token.data() + stateless_reset_token.length());
} break;
case TransportParameters::kMaxPacketSize:
- parse_success = out->max_packet_size.Read(&value_reader, error_details);
+ parse_success =
+ out->max_udp_payload_size.Read(&value_reader, error_details);
break;
case TransportParameters::kInitialMaxData:
parse_success =
@@ -1065,12 +1231,12 @@ bool ParseTransportParameters(ParsedQuicVersion version,
case TransportParameters::kMaxAckDelay:
parse_success = out->max_ack_delay.Read(&value_reader, error_details);
break;
- case TransportParameters::kDisableMigration:
- if (out->disable_migration) {
- *error_details = "Received a second disable migration";
+ case TransportParameters::kDisableActiveMigration:
+ if (out->disable_active_migration) {
+ *error_details = "Received a second disable_active_migration";
return false;
}
- out->disable_migration = true;
+ out->disable_active_migration = true;
break;
case TransportParameters::kPreferredAddress: {
TransportParameters::PreferredAddress preferred_address;
@@ -1087,7 +1253,7 @@ bool ParseTransportParameters(ParsedQuicVersion version,
&preferred_address.connection_id) ||
!value_reader.ReadBytes(&preferred_address.stateless_reset_token[0],
kStatelessResetTokenLength)) {
- *error_details = "Failed to read preferred address";
+ *error_details = "Failed to read preferred_address";
return false;
}
preferred_address.ipv4_socket_address =
@@ -1096,13 +1262,13 @@ bool ParseTransportParameters(ParsedQuicVersion version,
QuicSocketAddress(QuicIpAddress(ipv6_address), ipv6_port);
if (!preferred_address.ipv4_socket_address.host().IsIPv4() ||
!preferred_address.ipv6_socket_address.host().IsIPv6()) {
- *error_details = "Received preferred addresses of bad families " +
+ *error_details = "Received preferred_address of bad families " +
preferred_address.ToString();
return false;
}
if (!QuicUtils::IsConnectionIdValidForVersion(
preferred_address.connection_id, version.transport_version)) {
- *error_details = "Received invalid preferred address connection ID " +
+ *error_details = "Received invalid preferred_address connection ID " +
preferred_address.ToString();
return false;
}
@@ -1114,6 +1280,48 @@ bool ParseTransportParameters(ParsedQuicVersion version,
parse_success =
out->active_connection_id_limit.Read(&value_reader, error_details);
break;
+ case TransportParameters::kInitialSourceConnectionId: {
+ if (out->initial_source_connection_id.has_value()) {
+ *error_details = "Received a second initial_source_connection_id";
+ return false;
+ }
+ const size_t connection_id_length = value_reader.BytesRemaining();
+ if (!QuicUtils::IsConnectionIdLengthValidForVersion(
+ connection_id_length, version.transport_version)) {
+ *error_details = quiche::QuicheStrCat(
+ "Received initial_source_connection_id of invalid length ",
+ connection_id_length);
+ return false;
+ }
+ QuicConnectionId initial_source_connection_id;
+ if (!value_reader.ReadConnectionId(&initial_source_connection_id,
+ connection_id_length)) {
+ *error_details = "Failed to read initial_source_connection_id";
+ return false;
+ }
+ out->initial_source_connection_id = initial_source_connection_id;
+ } break;
+ case TransportParameters::kRetrySourceConnectionId: {
+ if (out->retry_source_connection_id.has_value()) {
+ *error_details = "Received a second retry_source_connection_id";
+ return false;
+ }
+ const size_t connection_id_length = value_reader.BytesRemaining();
+ if (!QuicUtils::IsConnectionIdLengthValidForVersion(
+ connection_id_length, version.transport_version)) {
+ *error_details = quiche::QuicheStrCat(
+ "Received retry_source_connection_id of invalid length ",
+ connection_id_length);
+ return false;
+ }
+ QuicConnectionId retry_source_connection_id;
+ if (!value_reader.ReadConnectionId(&retry_source_connection_id,
+ connection_id_length)) {
+ *error_details = "Failed to read retry_source_connection_id";
+ return false;
+ }
+ out->retry_source_connection_id = retry_source_connection_id;
+ } break;
case TransportParameters::kMaxDatagramFrameSize:
parse_success =
out->max_datagram_frame_size.Read(&value_reader, error_details);
@@ -1124,14 +1332,14 @@ bool ParseTransportParameters(ParsedQuicVersion version,
break;
case TransportParameters::kGoogleConnectionOptions: {
if (out->google_connection_options.has_value()) {
- *error_details = "Received a second Google connection options";
+ *error_details = "Received a second google_connection_options";
return false;
}
out->google_connection_options = QuicTagVector{};
while (!value_reader.IsDoneReading()) {
QuicTag connection_option;
if (!value_reader.ReadTag(&connection_option)) {
- *error_details = "Failed to read a Google connection option";
+ *error_details = "Failed to read a google_connection_options";
return false;
}
out->google_connection_options.value().push_back(connection_option);
@@ -1139,11 +1347,18 @@ bool ParseTransportParameters(ParsedQuicVersion version,
} break;
case TransportParameters::kGoogleUserAgentId:
if (out->user_agent_id.has_value()) {
- *error_details = "Received a second user agent ID";
+ *error_details = "Received a second user_agent_id";
return false;
}
out->user_agent_id = std::string(value_reader.ReadRemainingPayload());
break;
+ case TransportParameters::kGoogleSupportHandshakeDone:
+ if (out->support_handshake_done) {
+ *error_details = "Received a second support_handshake_done";
+ return false;
+ }
+ out->support_handshake_done = true;
+ break;
case TransportParameters::kGoogleQuicParam: {
if (out->google_quic_params) {
*error_details = "Received a second Google parameter";
@@ -1208,4 +1423,87 @@ bool ParseTransportParameters(ParsedQuicVersion version,
return true;
}
+namespace {
+
+bool DigestUpdateIntegerParam(
+ EVP_MD_CTX* hash_ctx,
+ const TransportParameters::IntegerParameter& param) {
+ uint64_t value = param.value();
+ return EVP_DigestUpdate(hash_ctx, &value, sizeof(value));
+}
+
+} // namespace
+
+bool SerializeTransportParametersForTicket(
+ const TransportParameters& in,
+ const std::vector<uint8_t>& application_data,
+ std::vector<uint8_t>* out) {
+ std::string error_details;
+ if (!in.AreValid(&error_details)) {
+ QUIC_BUG << "Not serializing invalid transport parameters: "
+ << error_details;
+ return false;
+ }
+
+ out->resize(SHA256_DIGEST_LENGTH + 1);
+ const uint8_t serialization_version = 0;
+ (*out)[0] = serialization_version;
+
+ bssl::ScopedEVP_MD_CTX hash_ctx;
+ // Write application data:
+ uint64_t app_data_len = application_data.size();
+ const uint64_t parameter_version = 0;
+ // The format of the input to the hash function is as follows:
+ // - The application data, prefixed with a 64-bit length field.
+ // - Transport parameters:
+ // - A 64-bit version field indicating which version of encoding is used
+ // for transport parameters.
+ // - A list of 64-bit integers representing the relevant parameters.
+ //
+ // When changing which parameters are included, additional parameters can be
+ // added to the end of the list without changing the version field. New
+ // parameters that are variable length must be length prefixed. If
+ // parameters are removed from the list, the version field must be
+ // incremented.
+ //
+ // Integers happen to be written in host byte order, not network byte order.
+ if (!EVP_DigestInit(hash_ctx.get(), EVP_sha256()) ||
+ !EVP_DigestUpdate(hash_ctx.get(), &app_data_len, sizeof(app_data_len)) ||
+ !EVP_DigestUpdate(hash_ctx.get(), application_data.data(),
+ application_data.size()) ||
+ !EVP_DigestUpdate(hash_ctx.get(), &parameter_version,
+ sizeof(parameter_version))) {
+ QUIC_BUG << "Unexpected failure of EVP_Digest functions when hashing "
+ "Transport Parameters for ticket";
+ return false;
+ }
+
+ // Write transport parameters specified by draft-ietf-quic-transport-28,
+ // section 7.4.1, that are remembered for 0-RTT.
+ if (!DigestUpdateIntegerParam(hash_ctx.get(), in.initial_max_data) ||
+ !DigestUpdateIntegerParam(hash_ctx.get(),
+ in.initial_max_stream_data_bidi_local) ||
+ !DigestUpdateIntegerParam(hash_ctx.get(),
+ in.initial_max_stream_data_bidi_remote) ||
+ !DigestUpdateIntegerParam(hash_ctx.get(),
+ in.initial_max_stream_data_uni) ||
+ !DigestUpdateIntegerParam(hash_ctx.get(), in.initial_max_streams_bidi) ||
+ !DigestUpdateIntegerParam(hash_ctx.get(), in.initial_max_streams_uni) ||
+ !DigestUpdateIntegerParam(hash_ctx.get(),
+ in.active_connection_id_limit)) {
+ QUIC_BUG << "Unexpected failure of EVP_Digest functions when hashing "
+ "Transport Parameters for ticket";
+ return false;
+ }
+ uint8_t disable_active_migration = in.disable_active_migration ? 1 : 0;
+ if (!EVP_DigestUpdate(hash_ctx.get(), &disable_active_migration,
+ sizeof(disable_active_migration)) ||
+ !EVP_DigestFinal(hash_ctx.get(), out->data() + 1, nullptr)) {
+ QUIC_BUG << "Unexpected failure of EVP_Digest functions when hashing "
+ "Transport Parameters for ticket";
+ return false;
+ }
+ return true;
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h
index 9dec484a552..093bb09de2a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h
@@ -28,7 +28,7 @@ struct QUIC_EXPORT_PRIVATE TransportParameters {
// The identifier used to differentiate transport parameters.
enum TransportParameterId : uint64_t;
// A map used to specify custom parameters.
- using ParameterMap = QuicUnorderedMap<TransportParameterId, std::string>;
+ using ParameterMap = QuicHashMap<TransportParameterId, std::string>;
// Represents an individual QUIC transport parameter that only encodes a
// variable length integer. Can only be created inside the constructor for
// TransportParameters.
@@ -132,17 +132,17 @@ struct QUIC_EXPORT_PRIVATE TransportParameters {
// The value of the Destination Connection ID field from the first
// Initial packet sent by the client.
- quiche::QuicheOptional<QuicConnectionId> original_connection_id;
+ quiche::QuicheOptional<QuicConnectionId> original_destination_connection_id;
- // Idle timeout expressed in milliseconds.
- IntegerParameter idle_timeout_milliseconds;
+ // Maximum idle timeout expressed in milliseconds.
+ IntegerParameter max_idle_timeout_ms;
// Stateless reset token used in verifying stateless resets.
std::vector<uint8_t> stateless_reset_token;
// Limits the size of packets that the endpoint is willing to receive.
// This indicates that packets larger than this limit will be dropped.
- IntegerParameter max_packet_size;
+ IntegerParameter max_udp_payload_size;
// Contains the initial value for the maximum amount of data that can
// be sent on the connection.
@@ -171,7 +171,7 @@ struct QUIC_EXPORT_PRIVATE TransportParameters {
IntegerParameter max_ack_delay;
// Indicates lack of support for connection migration.
- bool disable_migration;
+ bool disable_active_migration;
// Used to effect a change in server address at the end of the handshake.
std::unique_ptr<PreferredAddress> preferred_address;
@@ -180,6 +180,14 @@ struct QUIC_EXPORT_PRIVATE TransportParameters {
// to store.
IntegerParameter active_connection_id_limit;
+ // The value that the endpoint included in the Source Connection ID field of
+ // the first Initial packet it sent.
+ quiche::QuicheOptional<QuicConnectionId> initial_source_connection_id;
+
+ // The value that the server included in the Source Connection ID field of a
+ // Retry packet it sent.
+ quiche::QuicheOptional<QuicConnectionId> retry_source_connection_id;
+
// Indicates support for the DATAGRAM frame and the maximum frame size that
// the sender accepts. See draft-ietf-quic-datagram.
IntegerParameter max_datagram_frame_size;
@@ -194,6 +202,9 @@ struct QUIC_EXPORT_PRIVATE TransportParameters {
// Google-specific user agent identifier.
quiche::QuicheOptional<std::string> user_agent_id;
+ // Google-specific handshake done support. This is only used for T050.
+ bool support_handshake_done;
+
// Transport parameters used by Google QUIC but not IETF QUIC. This is
// serialized into a TransportParameter struct with a TransportParameterId of
// kGoogleQuicParamId.
@@ -235,6 +246,19 @@ QUIC_EXPORT_PRIVATE bool ParseTransportParameters(ParsedQuicVersion version,
TransportParameters* out,
std::string* error_details);
+// Serializes |in| and |application_data| in a deterministic format so that
+// multiple calls to SerializeTransportParametersForTicket with the same inputs
+// will generate the same output, and if the inputs differ, then the output will
+// differ. The output of this function is used by the server in
+// SSL_set_quic_early_data_context to determine whether early data should be
+// accepted: Early data will only be accepted if the inputs to this function
+// match what they were on the connection that issued an early data capable
+// ticket.
+QUIC_EXPORT_PRIVATE bool SerializeTransportParametersForTicket(
+ const TransportParameters& in,
+ const std::vector<uint8_t>& application_data,
+ std::vector<uint8_t>* out);
+
} // namespace quic
#endif // QUICHE_QUIC_CORE_CRYPTO_TRANSPORT_PARAMETERS_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc
index 1fc1f5c5c93..39919532dc6 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc
@@ -44,6 +44,7 @@ const uint64_t kFakeInitialRoundTripTime = 53;
const uint8_t kFakePreferredStatelessResetTokenData[16] = {
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F};
+const bool kFakeSupportHandshakeDone = true;
const auto kCustomParameter1 =
static_cast<TransportParameters::TransportParameterId>(0xffcd);
@@ -52,10 +53,18 @@ const auto kCustomParameter2 =
static_cast<TransportParameters::TransportParameterId>(0xff34);
const char* kCustomParameter2Value = "bar";
-QuicConnectionId CreateFakeOriginalConnectionId() {
+QuicConnectionId CreateFakeOriginalDestinationConnectionId() {
return TestConnectionId(0x1337);
}
+QuicConnectionId CreateFakeInitialSourceConnectionId() {
+ return TestConnectionId(0x2345);
+}
+
+QuicConnectionId CreateFakeRetrySourceConnectionId() {
+ return TestConnectionId(0x9876);
+}
+
QuicConnectionId CreateFakePreferredConnectionId() {
return TestConnectionId(0xBEEF);
}
@@ -151,8 +160,8 @@ TEST_P(TransportParametersTest, Comparator) {
new_params.perspective = Perspective::IS_CLIENT;
orig_params.version = kFakeVersionLabel;
new_params.version = kFakeVersionLabel;
- orig_params.disable_migration = true;
- new_params.disable_migration = true;
+ orig_params.disable_active_migration = true;
+ new_params.disable_active_migration = true;
EXPECT_EQ(orig_params, new_params);
EXPECT_TRUE(orig_params == new_params);
EXPECT_FALSE(orig_params != new_params);
@@ -172,12 +181,12 @@ TEST_P(TransportParametersTest, Comparator) {
EXPECT_FALSE(orig_params != new_params);
// Test comparison on IntegerParameters.
- orig_params.max_packet_size.set_value(kFakeMaxPacketSize);
- new_params.max_packet_size.set_value(kFakeMaxPacketSize + 1);
+ orig_params.max_udp_payload_size.set_value(kFakeMaxPacketSize);
+ new_params.max_udp_payload_size.set_value(kFakeMaxPacketSize + 1);
EXPECT_NE(orig_params, new_params);
EXPECT_FALSE(orig_params == new_params);
EXPECT_TRUE(orig_params != new_params);
- new_params.max_packet_size.set_value(kFakeMaxPacketSize);
+ new_params.max_udp_payload_size.set_value(kFakeMaxPacketSize);
EXPECT_EQ(orig_params, new_params);
EXPECT_TRUE(orig_params == new_params);
EXPECT_FALSE(orig_params != new_params);
@@ -222,6 +231,23 @@ TEST_P(TransportParametersTest, Comparator) {
EXPECT_EQ(orig_params, new_params);
EXPECT_TRUE(orig_params == new_params);
EXPECT_FALSE(orig_params != new_params);
+
+ // Test comparison on connection IDs.
+ orig_params.initial_source_connection_id =
+ CreateFakeInitialSourceConnectionId();
+ new_params.initial_source_connection_id = QUICHE_NULLOPT;
+ EXPECT_NE(orig_params, new_params);
+ EXPECT_FALSE(orig_params == new_params);
+ EXPECT_TRUE(orig_params != new_params);
+ new_params.initial_source_connection_id = TestConnectionId(0xbadbad);
+ EXPECT_NE(orig_params, new_params);
+ EXPECT_FALSE(orig_params == new_params);
+ EXPECT_TRUE(orig_params != new_params);
+ new_params.initial_source_connection_id =
+ CreateFakeInitialSourceConnectionId();
+ EXPECT_EQ(orig_params, new_params);
+ EXPECT_TRUE(orig_params == new_params);
+ EXPECT_FALSE(orig_params != new_params);
}
TEST_P(TransportParametersTest, CopyConstructor) {
@@ -230,10 +256,11 @@ TEST_P(TransportParametersTest, CopyConstructor) {
orig_params.version = kFakeVersionLabel;
orig_params.supported_versions.push_back(kFakeVersionLabel);
orig_params.supported_versions.push_back(kFakeVersionLabel2);
- orig_params.original_connection_id = CreateFakeOriginalConnectionId();
- orig_params.idle_timeout_milliseconds.set_value(kFakeIdleTimeoutMilliseconds);
+ orig_params.original_destination_connection_id =
+ CreateFakeOriginalDestinationConnectionId();
+ orig_params.max_idle_timeout_ms.set_value(kFakeIdleTimeoutMilliseconds);
orig_params.stateless_reset_token = CreateFakeStatelessResetToken();
- orig_params.max_packet_size.set_value(kFakeMaxPacketSize);
+ orig_params.max_udp_payload_size.set_value(kFakeMaxPacketSize);
orig_params.initial_max_data.set_value(kFakeInitialMaxData);
orig_params.initial_max_stream_data_bidi_local.set_value(
kFakeInitialMaxStreamDataBidiLocal);
@@ -245,13 +272,17 @@ TEST_P(TransportParametersTest, CopyConstructor) {
orig_params.initial_max_streams_uni.set_value(kFakeInitialMaxStreamsUni);
orig_params.ack_delay_exponent.set_value(kFakeAckDelayExponent);
orig_params.max_ack_delay.set_value(kFakeMaxAckDelay);
- orig_params.disable_migration = kFakeDisableMigration;
+ orig_params.disable_active_migration = kFakeDisableMigration;
orig_params.preferred_address = CreateFakePreferredAddress();
orig_params.active_connection_id_limit.set_value(
kFakeActiveConnectionIdLimit);
+ orig_params.initial_source_connection_id =
+ CreateFakeInitialSourceConnectionId();
+ orig_params.retry_source_connection_id = CreateFakeRetrySourceConnectionId();
orig_params.initial_round_trip_time_us.set_value(kFakeInitialRoundTripTime);
orig_params.google_connection_options = CreateFakeGoogleConnectionOptions();
orig_params.user_agent_id = CreateFakeUserAgentId();
+ orig_params.support_handshake_done = kFakeSupportHandshakeDone;
orig_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value;
orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value;
@@ -263,8 +294,8 @@ TEST_P(TransportParametersTest, RoundTripClient) {
TransportParameters orig_params;
orig_params.perspective = Perspective::IS_CLIENT;
orig_params.version = kFakeVersionLabel;
- orig_params.idle_timeout_milliseconds.set_value(kFakeIdleTimeoutMilliseconds);
- orig_params.max_packet_size.set_value(kFakeMaxPacketSize);
+ orig_params.max_idle_timeout_ms.set_value(kFakeIdleTimeoutMilliseconds);
+ orig_params.max_udp_payload_size.set_value(kFakeMaxPacketSize);
orig_params.initial_max_data.set_value(kFakeInitialMaxData);
orig_params.initial_max_stream_data_bidi_local.set_value(
kFakeInitialMaxStreamDataBidiLocal);
@@ -276,12 +307,15 @@ TEST_P(TransportParametersTest, RoundTripClient) {
orig_params.initial_max_streams_uni.set_value(kFakeInitialMaxStreamsUni);
orig_params.ack_delay_exponent.set_value(kFakeAckDelayExponent);
orig_params.max_ack_delay.set_value(kFakeMaxAckDelay);
- orig_params.disable_migration = kFakeDisableMigration;
+ orig_params.disable_active_migration = kFakeDisableMigration;
orig_params.active_connection_id_limit.set_value(
kFakeActiveConnectionIdLimit);
+ orig_params.initial_source_connection_id =
+ CreateFakeInitialSourceConnectionId();
orig_params.initial_round_trip_time_us.set_value(kFakeInitialRoundTripTime);
orig_params.google_connection_options = CreateFakeGoogleConnectionOptions();
orig_params.user_agent_id = CreateFakeUserAgentId();
+ orig_params.support_handshake_done = kFakeSupportHandshakeDone;
orig_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value;
orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value;
@@ -305,10 +339,11 @@ TEST_P(TransportParametersTest, RoundTripServer) {
orig_params.version = kFakeVersionLabel;
orig_params.supported_versions.push_back(kFakeVersionLabel);
orig_params.supported_versions.push_back(kFakeVersionLabel2);
- orig_params.original_connection_id = CreateFakeOriginalConnectionId();
- orig_params.idle_timeout_milliseconds.set_value(kFakeIdleTimeoutMilliseconds);
+ orig_params.original_destination_connection_id =
+ CreateFakeOriginalDestinationConnectionId();
+ orig_params.max_idle_timeout_ms.set_value(kFakeIdleTimeoutMilliseconds);
orig_params.stateless_reset_token = CreateFakeStatelessResetToken();
- orig_params.max_packet_size.set_value(kFakeMaxPacketSize);
+ orig_params.max_udp_payload_size.set_value(kFakeMaxPacketSize);
orig_params.initial_max_data.set_value(kFakeInitialMaxData);
orig_params.initial_max_stream_data_bidi_local.set_value(
kFakeInitialMaxStreamDataBidiLocal);
@@ -320,10 +355,13 @@ TEST_P(TransportParametersTest, RoundTripServer) {
orig_params.initial_max_streams_uni.set_value(kFakeInitialMaxStreamsUni);
orig_params.ack_delay_exponent.set_value(kFakeAckDelayExponent);
orig_params.max_ack_delay.set_value(kFakeMaxAckDelay);
- orig_params.disable_migration = kFakeDisableMigration;
+ orig_params.disable_active_migration = kFakeDisableMigration;
orig_params.preferred_address = CreateFakePreferredAddress();
orig_params.active_connection_id_limit.set_value(
kFakeActiveConnectionIdLimit);
+ orig_params.initial_source_connection_id =
+ CreateFakeInitialSourceConnectionId();
+ orig_params.retry_source_connection_id = CreateFakeRetrySourceConnectionId();
orig_params.google_connection_options = CreateFakeGoogleConnectionOptions();
std::vector<uint8_t> serialized;
@@ -354,10 +392,10 @@ TEST_P(TransportParametersTest, AreValid) {
params.perspective = Perspective::IS_CLIENT;
EXPECT_TRUE(params.AreValid(&error_details));
EXPECT_TRUE(error_details.empty());
- params.idle_timeout_milliseconds.set_value(kFakeIdleTimeoutMilliseconds);
+ params.max_idle_timeout_ms.set_value(kFakeIdleTimeoutMilliseconds);
EXPECT_TRUE(params.AreValid(&error_details));
EXPECT_TRUE(error_details.empty());
- params.idle_timeout_milliseconds.set_value(601000);
+ params.max_idle_timeout_ms.set_value(601000);
EXPECT_TRUE(params.AreValid(&error_details));
EXPECT_TRUE(error_details.empty());
}
@@ -367,27 +405,27 @@ TEST_P(TransportParametersTest, AreValid) {
params.perspective = Perspective::IS_CLIENT;
EXPECT_TRUE(params.AreValid(&error_details));
EXPECT_TRUE(error_details.empty());
- params.max_packet_size.set_value(1200);
+ params.max_udp_payload_size.set_value(1200);
EXPECT_TRUE(params.AreValid(&error_details));
EXPECT_TRUE(error_details.empty());
- params.max_packet_size.set_value(65535);
+ params.max_udp_payload_size.set_value(65535);
EXPECT_TRUE(params.AreValid(&error_details));
EXPECT_TRUE(error_details.empty());
- params.max_packet_size.set_value(9999999);
+ params.max_udp_payload_size.set_value(9999999);
EXPECT_TRUE(params.AreValid(&error_details));
EXPECT_TRUE(error_details.empty());
- params.max_packet_size.set_value(0);
+ params.max_udp_payload_size.set_value(0);
error_details = "";
EXPECT_FALSE(params.AreValid(&error_details));
- EXPECT_EQ(
- error_details,
- "Invalid transport parameters [Client max_packet_size 0 (Invalid)]");
- params.max_packet_size.set_value(1199);
+ EXPECT_EQ(error_details,
+ "Invalid transport parameters [Client max_udp_payload_size 0 "
+ "(Invalid)]");
+ params.max_udp_payload_size.set_value(1199);
error_details = "";
EXPECT_FALSE(params.AreValid(&error_details));
- EXPECT_EQ(
- error_details,
- "Invalid transport parameters [Client max_packet_size 1199 (Invalid)]");
+ EXPECT_EQ(error_details,
+ "Invalid transport parameters [Client max_udp_payload_size 1199 "
+ "(Invalid)]");
}
{
TransportParameters params;
@@ -436,9 +474,9 @@ TEST_P(TransportParametersTest, NoClientParamsWithStatelessResetToken) {
TransportParameters orig_params;
orig_params.perspective = Perspective::IS_CLIENT;
orig_params.version = kFakeVersionLabel;
- orig_params.idle_timeout_milliseconds.set_value(kFakeIdleTimeoutMilliseconds);
+ orig_params.max_idle_timeout_ms.set_value(kFakeIdleTimeoutMilliseconds);
orig_params.stateless_reset_token = CreateFakeStatelessResetToken();
- orig_params.max_packet_size.set_value(kFakeMaxPacketSize);
+ orig_params.max_udp_payload_size.set_value(kFakeMaxPacketSize);
std::vector<uint8_t> out;
bool ok;
@@ -452,12 +490,12 @@ TEST_P(TransportParametersTest, NoClientParamsWithStatelessResetToken) {
TEST_P(TransportParametersTest, ParseClientParams) {
// clang-format off
const uint8_t kClientParamsOld[] = {
- 0x00, 0x6a, // length of the parameters array that follows
- // idle_timeout
+ 0x00, 0x7A, // length of the parameters array that follows
+ // max_idle_timeout
0x00, 0x01, // parameter id
0x00, 0x02, // length
0x6e, 0xec, // value
- // max_packet_size
+ // max_udp_payload_size
0x00, 0x03, // parameter id
0x00, 0x02, // length
0x63, 0x29, // value
@@ -493,13 +531,17 @@ TEST_P(TransportParametersTest, ParseClientParams) {
0x00, 0x0b, // parameter id
0x00, 0x01, // length
0x33, // value
- // disable_migration
+ // disable_active_migration
0x00, 0x0c, // parameter id
0x00, 0x00, // length
// active_connection_id_limit
0x00, 0x0e, // parameter id
0x00, 0x01, // length
0x34, // value
+ // initial_source_connection_id
+ 0x00, 0x0f, // parameter id
+ 0x00, 0x08, // length
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45,
// initial_round_trip_time_us
0x31, 0x27, // parameter id
0x00, 0x01, // length
@@ -514,17 +556,20 @@ TEST_P(TransportParametersTest, ParseClientParams) {
0x31, 0x29, // parameter id
0x00, 0x08, // length
'F', 'a', 'k', 'e', 'U', 'A', 'I', 'D', // value
+ // support_handshake_done
+ 0x31, 0x2A, // parameter id
+ 0x00, 0x00, // value
// Google version extension
0x47, 0x52, // parameter id
0x00, 0x04, // length
0x01, 0x23, 0x45, 0x67, // initial version
};
const uint8_t kClientParams[] = {
- // idle_timeout
+ // max_idle_timeout
0x01, // parameter id
0x02, // length
0x6e, 0xec, // value
- // max_packet_size
+ // max_udp_payload_size
0x03, // parameter id
0x02, // length
0x63, 0x29, // value
@@ -560,13 +605,17 @@ TEST_P(TransportParametersTest, ParseClientParams) {
0x0b, // parameter id
0x01, // length
0x33, // value
- // disable_migration
+ // disable_active_migration
0x0c, // parameter id
0x00, // length
// active_connection_id_limit
0x0e, // parameter id
0x01, // length
0x34, // value
+ // initial_source_connection_id
+ 0x0f, // parameter id
+ 0x08, // length
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45,
// initial_round_trip_time_us
0x71, 0x27, // parameter id
0x01, // length
@@ -581,6 +630,9 @@ TEST_P(TransportParametersTest, ParseClientParams) {
0x71, 0x29, // parameter id
0x08, // length
'F', 'a', 'k', 'e', 'U', 'A', 'I', 'D', // value
+ // support_handshake_done
+ 0x71, 0x2A, // parameter id
+ 0x00, // length
// Google version extension
0x80, 0x00, 0x47, 0x52, // parameter id
0x04, // length
@@ -604,11 +656,11 @@ TEST_P(TransportParametersTest, ParseClientParams) {
EXPECT_EQ(Perspective::IS_CLIENT, new_params.perspective);
EXPECT_EQ(kFakeVersionLabel, new_params.version);
EXPECT_TRUE(new_params.supported_versions.empty());
- EXPECT_FALSE(new_params.original_connection_id.has_value());
+ EXPECT_FALSE(new_params.original_destination_connection_id.has_value());
EXPECT_EQ(kFakeIdleTimeoutMilliseconds,
- new_params.idle_timeout_milliseconds.value());
+ new_params.max_idle_timeout_ms.value());
EXPECT_TRUE(new_params.stateless_reset_token.empty());
- EXPECT_EQ(kFakeMaxPacketSize, new_params.max_packet_size.value());
+ EXPECT_EQ(kFakeMaxPacketSize, new_params.max_udp_payload_size.value());
EXPECT_EQ(kFakeInitialMaxData, new_params.initial_max_data.value());
EXPECT_EQ(kFakeInitialMaxStreamDataBidiLocal,
new_params.initial_max_stream_data_bidi_local.value());
@@ -622,9 +674,13 @@ TEST_P(TransportParametersTest, ParseClientParams) {
new_params.initial_max_streams_uni.value());
EXPECT_EQ(kFakeAckDelayExponent, new_params.ack_delay_exponent.value());
EXPECT_EQ(kFakeMaxAckDelay, new_params.max_ack_delay.value());
- EXPECT_EQ(kFakeDisableMigration, new_params.disable_migration);
+ EXPECT_EQ(kFakeDisableMigration, new_params.disable_active_migration);
EXPECT_EQ(kFakeActiveConnectionIdLimit,
new_params.active_connection_id_limit.value());
+ ASSERT_TRUE(new_params.initial_source_connection_id.has_value());
+ EXPECT_EQ(CreateFakeInitialSourceConnectionId(),
+ new_params.initial_source_connection_id.value());
+ EXPECT_FALSE(new_params.retry_source_connection_id.has_value());
EXPECT_EQ(kFakeInitialRoundTripTime,
new_params.initial_round_trip_time_us.value());
ASSERT_TRUE(new_params.google_connection_options.has_value());
@@ -632,6 +688,7 @@ TEST_P(TransportParametersTest, ParseClientParams) {
new_params.google_connection_options.value());
ASSERT_TRUE(new_params.user_agent_id.has_value());
EXPECT_EQ(CreateFakeUserAgentId(), new_params.user_agent_id.value());
+ EXPECT_TRUE(new_params.support_handshake_done);
}
TEST_P(TransportParametersTest,
@@ -639,7 +696,7 @@ TEST_P(TransportParametersTest,
// clang-format off
const uint8_t kClientParamsWithFullTokenOld[] = {
0x00, 0x26, // length parameters array that follows
- // idle_timeout
+ // max_idle_timeout
0x00, 0x01, // parameter id
0x00, 0x02, // length
0x6e, 0xec, // value
@@ -648,7 +705,7 @@ TEST_P(TransportParametersTest,
0x00, 0x10, // length
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
- // max_packet_size
+ // max_udp_payload_size
0x00, 0x03, // parameter id
0x00, 0x02, // length
0x63, 0x29, // value
@@ -658,7 +715,7 @@ TEST_P(TransportParametersTest,
0x40, 0x65, // value
};
const uint8_t kClientParamsWithFullToken[] = {
- // idle_timeout
+ // max_idle_timeout
0x01, // parameter id
0x02, // length
0x6e, 0xec, // value
@@ -667,7 +724,7 @@ TEST_P(TransportParametersTest,
0x10, // length
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
- // max_packet_size
+ // max_udp_payload_size
0x03, // parameter id
0x02, // length
0x63, 0x29, // value
@@ -698,14 +755,14 @@ TEST_P(TransportParametersTest,
// clang-format off
const uint8_t kClientParamsWithEmptyTokenOld[] = {
0x00, 0x16, // length parameters array that follows
- // idle_timeout
+ // max_idle_timeout
0x00, 0x01, // parameter id
0x00, 0x02, // length
0x6e, 0xec, // value
// stateless_reset_token
0x00, 0x02, // parameter id
0x00, 0x00,
- // max_packet_size
+ // max_udp_payload_size
0x00, 0x03, // parameter id
0x00, 0x02, // length
0x63, 0x29, // value
@@ -715,14 +772,14 @@ TEST_P(TransportParametersTest,
0x40, 0x65, // value
};
const uint8_t kClientParamsWithEmptyToken[] = {
- // idle_timeout
+ // max_idle_timeout
0x01, // parameter id
0x02, // length
0x6e, 0xec, // value
// stateless_reset_token
0x02, // parameter id
0x00, // length
- // max_packet_size
+ // max_udp_payload_size
0x03, // parameter id
0x02, // length
0x63, 0x29, // value
@@ -746,36 +803,36 @@ TEST_P(TransportParametersTest,
client_params, client_params_length,
&out_params, &error_details));
EXPECT_EQ(error_details,
- "Received stateless reset token of invalid length 0");
+ "Received stateless_reset_token of invalid length 0");
}
TEST_P(TransportParametersTest, ParseClientParametersRepeated) {
// clang-format off
const uint8_t kClientParamsRepeatedOld[] = {
0x00, 0x12, // length parameters array that follows
- // idle_timeout
+ // max_idle_timeout
0x00, 0x01, // parameter id
0x00, 0x02, // length
0x6e, 0xec, // value
- // max_packet_size
+ // max_udp_payload_size
0x00, 0x03, // parameter id
0x00, 0x02, // length
0x63, 0x29, // value
- // idle_timeout (repeated)
+ // max_idle_timeout (repeated)
0x00, 0x01, // parameter id
0x00, 0x02, // length
0x6e, 0xec, // value
};
const uint8_t kClientParamsRepeated[] = {
- // idle_timeout
+ // max_idle_timeout
0x01, // parameter id
0x02, // length
0x6e, 0xec, // value
- // max_packet_size
+ // max_udp_payload_size
0x03, // parameter id
0x02, // length
0x63, 0x29, // value
- // idle_timeout (repeated)
+ // max_idle_timeout (repeated)
0x01, // parameter id
0x02, // length
0x6e, 0xec, // value
@@ -793,18 +850,18 @@ TEST_P(TransportParametersTest, ParseClientParametersRepeated) {
EXPECT_FALSE(ParseTransportParameters(version_, Perspective::IS_CLIENT,
client_params, client_params_length,
&out_params, &error_details));
- EXPECT_EQ(error_details, "Received a second idle_timeout");
+ EXPECT_EQ(error_details, "Received a second max_idle_timeout");
}
TEST_P(TransportParametersTest, ParseServerParams) {
// clang-format off
const uint8_t kServerParamsOld[] = {
- 0x00, 0xb7, // length of parameters array that follows
- // original_connection_id
+ 0x00, 0xd3, // length of parameters array that follows
+ // original_destination_connection_id
0x00, 0x00, // parameter id
0x00, 0x08, // length
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x37,
- // idle_timeout
+ // max_idle_timeout
0x00, 0x01, // parameter id
0x00, 0x02, // length
0x6e, 0xec, // value
@@ -813,7 +870,7 @@ TEST_P(TransportParametersTest, ParseServerParams) {
0x00, 0x10, // length
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
- // max_packet_size
+ // max_udp_payload_size
0x00, 0x03, // parameter id
0x00, 0x02, // length
0x63, 0x29, // value
@@ -849,7 +906,7 @@ TEST_P(TransportParametersTest, ParseServerParams) {
0x00, 0x0b, // parameter id
0x00, 0x01, // length
0x33, // value
- // disable_migration
+ // disable_active_migration
0x00, 0x0c, // parameter id
0x00, 0x00, // length
// preferred_address
@@ -868,12 +925,23 @@ TEST_P(TransportParametersTest, ParseServerParams) {
0x00, 0x0e, // parameter id
0x00, 0x01, // length
0x34, // value
+ // initial_source_connection_id
+ 0x00, 0x0f, // parameter id
+ 0x00, 0x08, // length
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45,
+ // retry_source_connection_id
+ 0x00, 0x10, // parameter id
+ 0x00, 0x08, // length
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x76,
// google_connection_options
0x31, 0x28, // parameter id
0x00, 0x0c, // length
'A', 'L', 'P', 'N', // value
'E', 'F', 'G', 0x00,
'H', 'I', 'J', 0xff,
+ // support_handshake_done
+ 0x31, 0x2A, // parameter id
+ 0x00, 0x00, // value
// Google version extension
0x47, 0x52, // parameter id
0x00, 0x0d, // length
@@ -883,11 +951,11 @@ TEST_P(TransportParametersTest, ParseServerParams) {
0x89, 0xab, 0xcd, 0xef,
};
const uint8_t kServerParams[] = {
- // original_connection_id
+ // original_destination_connection_id
0x00, // parameter id
0x08, // length
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x37,
- // idle_timeout
+ // max_idle_timeout
0x01, // parameter id
0x02, // length
0x6e, 0xec, // value
@@ -896,7 +964,7 @@ TEST_P(TransportParametersTest, ParseServerParams) {
0x10, // length
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
- // max_packet_size
+ // max_udp_payload_size
0x03, // parameter id
0x02, // length
0x63, 0x29, // value
@@ -932,7 +1000,7 @@ TEST_P(TransportParametersTest, ParseServerParams) {
0x0b, // parameter id
0x01, // length
0x33, // value
- // disable_migration
+ // disable_active_migration
0x0c, // parameter id
0x00, // length
// preferred_address
@@ -951,12 +1019,23 @@ TEST_P(TransportParametersTest, ParseServerParams) {
0x0e, // parameter id
0x01, // length
0x34, // value
+ // initial_source_connection_id
+ 0x0f, // parameter id
+ 0x08, // length
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45,
+ // retry_source_connection_id
+ 0x10, // parameter id
+ 0x08, // length
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x76,
// google_connection_options
0x71, 0x28, // parameter id
0x0c, // length
'A', 'L', 'P', 'N', // value
'E', 'F', 'G', 0x00,
'H', 'I', 'J', 0xff,
+ // support_handshake_done
+ 0x71, 0x2A, // parameter id
+ 0x00, // length
// Google version extension
0x80, 0x00, 0x47, 0x52, // parameter id
0x0d, // length
@@ -985,13 +1064,13 @@ TEST_P(TransportParametersTest, ParseServerParams) {
EXPECT_EQ(2u, new_params.supported_versions.size());
EXPECT_EQ(kFakeVersionLabel, new_params.supported_versions[0]);
EXPECT_EQ(kFakeVersionLabel2, new_params.supported_versions[1]);
- ASSERT_TRUE(new_params.original_connection_id.has_value());
- EXPECT_EQ(CreateFakeOriginalConnectionId(),
- new_params.original_connection_id.value());
+ ASSERT_TRUE(new_params.original_destination_connection_id.has_value());
+ EXPECT_EQ(CreateFakeOriginalDestinationConnectionId(),
+ new_params.original_destination_connection_id.value());
EXPECT_EQ(kFakeIdleTimeoutMilliseconds,
- new_params.idle_timeout_milliseconds.value());
+ new_params.max_idle_timeout_ms.value());
EXPECT_EQ(CreateFakeStatelessResetToken(), new_params.stateless_reset_token);
- EXPECT_EQ(kFakeMaxPacketSize, new_params.max_packet_size.value());
+ EXPECT_EQ(kFakeMaxPacketSize, new_params.max_udp_payload_size.value());
EXPECT_EQ(kFakeInitialMaxData, new_params.initial_max_data.value());
EXPECT_EQ(kFakeInitialMaxStreamDataBidiLocal,
new_params.initial_max_stream_data_bidi_local.value());
@@ -1005,7 +1084,7 @@ TEST_P(TransportParametersTest, ParseServerParams) {
new_params.initial_max_streams_uni.value());
EXPECT_EQ(kFakeAckDelayExponent, new_params.ack_delay_exponent.value());
EXPECT_EQ(kFakeMaxAckDelay, new_params.max_ack_delay.value());
- EXPECT_EQ(kFakeDisableMigration, new_params.disable_migration);
+ EXPECT_EQ(kFakeDisableMigration, new_params.disable_active_migration);
ASSERT_NE(nullptr, new_params.preferred_address.get());
EXPECT_EQ(CreateFakeV4SocketAddress(),
new_params.preferred_address->ipv4_socket_address);
@@ -1017,21 +1096,28 @@ TEST_P(TransportParametersTest, ParseServerParams) {
new_params.preferred_address->stateless_reset_token);
EXPECT_EQ(kFakeActiveConnectionIdLimit,
new_params.active_connection_id_limit.value());
+ ASSERT_TRUE(new_params.initial_source_connection_id.has_value());
+ EXPECT_EQ(CreateFakeInitialSourceConnectionId(),
+ new_params.initial_source_connection_id.value());
+ ASSERT_TRUE(new_params.retry_source_connection_id.has_value());
+ EXPECT_EQ(CreateFakeRetrySourceConnectionId(),
+ new_params.retry_source_connection_id.value());
ASSERT_TRUE(new_params.google_connection_options.has_value());
EXPECT_EQ(CreateFakeGoogleConnectionOptions(),
new_params.google_connection_options.value());
EXPECT_FALSE(new_params.user_agent_id.has_value());
+ EXPECT_TRUE(new_params.support_handshake_done);
}
TEST_P(TransportParametersTest, ParseServerParametersRepeated) {
// clang-format off
const uint8_t kServerParamsRepeatedOld[] = {
0x00, 0x2c, // length of parameters array that follows
- // original_connection_id
+ // original_destination_connection_id
0x00, 0x00, // parameter id
0x00, 0x08, // length
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x37,
- // idle_timeout
+ // max_idle_timeout
0x00, 0x01, // parameter id
0x00, 0x02, // length
0x6e, 0xec, // value
@@ -1040,17 +1126,17 @@ TEST_P(TransportParametersTest, ParseServerParametersRepeated) {
0x00, 0x10, // length
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
- // idle_timeout (repeated)
+ // max_idle_timeout (repeated)
0x00, 0x01, // parameter id
0x00, 0x02, // length
0x6e, 0xec, // value
};
const uint8_t kServerParamsRepeated[] = {
- // original_connection_id
+ // original_destination_connection_id
0x00, // parameter id
0x08, // length
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x37,
- // idle_timeout
+ // max_idle_timeout
0x01, // parameter id
0x02, // length
0x6e, 0xec, // value
@@ -1059,7 +1145,7 @@ TEST_P(TransportParametersTest, ParseServerParametersRepeated) {
0x10, // length
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
- // idle_timeout (repeated)
+ // max_idle_timeout (repeated)
0x01, // parameter id
0x02, // length
0x6e, 0xec, // value
@@ -1077,7 +1163,7 @@ TEST_P(TransportParametersTest, ParseServerParametersRepeated) {
EXPECT_FALSE(ParseTransportParameters(version_, Perspective::IS_SERVER,
server_params, server_params_length,
&out_params, &error_details));
- EXPECT_EQ(error_details, "Received a second idle_timeout");
+ EXPECT_EQ(error_details, "Received a second max_idle_timeout");
}
TEST_P(TransportParametersTest,
@@ -1085,10 +1171,10 @@ TEST_P(TransportParametersTest,
// clang-format off
const uint8_t kServerParamsEmptyOriginalConnectionIdOld[] = {
0x00, 0x1e, // length of parameters array that follows
- // original_connection_id
+ // original_destination_connection_id
0x00, 0x00, // parameter id
0x00, 0x00, // length
- // idle_timeout
+ // max_idle_timeout
0x00, 0x01, // parameter id
0x00, 0x02, // length
0x6e, 0xec, // value
@@ -1099,10 +1185,10 @@ TEST_P(TransportParametersTest,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
};
const uint8_t kServerParamsEmptyOriginalConnectionId[] = {
- // original_connection_id
+ // original_destination_connection_id
0x00, // parameter id
0x00, // length
- // idle_timeout
+ // max_idle_timeout
0x01, // parameter id
0x02, // length
0x6e, 0xec, // value
@@ -1129,15 +1215,16 @@ TEST_P(TransportParametersTest,
server_params, server_params_length,
&out_params, &error_details))
<< error_details;
- ASSERT_TRUE(out_params.original_connection_id.has_value());
- EXPECT_EQ(out_params.original_connection_id.value(), EmptyQuicConnectionId());
+ ASSERT_TRUE(out_params.original_destination_connection_id.has_value());
+ EXPECT_EQ(out_params.original_destination_connection_id.value(),
+ EmptyQuicConnectionId());
}
TEST_P(TransportParametersTest, CryptoHandshakeMessageRoundtrip) {
TransportParameters orig_params;
orig_params.perspective = Perspective::IS_CLIENT;
orig_params.version = kFakeVersionLabel;
- orig_params.max_packet_size.set_value(kFakeMaxPacketSize);
+ orig_params.max_udp_payload_size.set_value(kFakeMaxPacketSize);
orig_params.google_quic_params = std::make_unique<CryptoHandshakeMessage>();
const std::string kTestString = "test string";
@@ -1166,7 +1253,132 @@ TEST_P(TransportParametersTest, CryptoHandshakeMessageRoundtrip) {
IsQuicNoError());
EXPECT_EQ(test_value, kTestValue);
EXPECT_EQ(kFakeVersionLabel, new_params.version);
- EXPECT_EQ(kFakeMaxPacketSize, new_params.max_packet_size.value());
+ EXPECT_EQ(kFakeMaxPacketSize, new_params.max_udp_payload_size.value());
+}
+
+TEST_P(TransportParametersTest, VeryLongCustomParameter) {
+ // Ensure we can handle a 70KB custom parameter on both send and receive.
+ size_t custom_value_length = 70000;
+ if (!version_.HasVarIntTransportParams()) {
+ // These versions encode lengths as uint16 so they cannot send as much.
+ custom_value_length = 65000;
+ }
+ std::string custom_value(custom_value_length, '?');
+ TransportParameters orig_params;
+ orig_params.perspective = Perspective::IS_CLIENT;
+ orig_params.version = kFakeVersionLabel;
+ orig_params.custom_parameters[kCustomParameter1] = custom_value;
+
+ std::vector<uint8_t> serialized;
+ ASSERT_TRUE(SerializeTransportParameters(version_, orig_params, &serialized));
+
+ TransportParameters new_params;
+ std::string error_details;
+ ASSERT_TRUE(ParseTransportParameters(version_, Perspective::IS_CLIENT,
+ serialized.data(), serialized.size(),
+ &new_params, &error_details))
+ << error_details;
+ EXPECT_TRUE(error_details.empty());
+ RemoveGreaseParameters(&new_params);
+ EXPECT_EQ(new_params, orig_params);
+}
+
+class TransportParametersTicketSerializationTest : public QuicTest {
+ protected:
+ void SetUp() override {
+ original_params_.perspective = Perspective::IS_SERVER;
+ original_params_.version = kFakeVersionLabel;
+ original_params_.supported_versions.push_back(kFakeVersionLabel);
+ original_params_.supported_versions.push_back(kFakeVersionLabel2);
+ original_params_.original_destination_connection_id =
+ CreateFakeOriginalDestinationConnectionId();
+ original_params_.max_idle_timeout_ms.set_value(
+ kFakeIdleTimeoutMilliseconds);
+ original_params_.stateless_reset_token = CreateFakeStatelessResetToken();
+ original_params_.max_udp_payload_size.set_value(kFakeMaxPacketSize);
+ original_params_.initial_max_data.set_value(kFakeInitialMaxData);
+ original_params_.initial_max_stream_data_bidi_local.set_value(
+ kFakeInitialMaxStreamDataBidiLocal);
+ original_params_.initial_max_stream_data_bidi_remote.set_value(
+ kFakeInitialMaxStreamDataBidiRemote);
+ original_params_.initial_max_stream_data_uni.set_value(
+ kFakeInitialMaxStreamDataUni);
+ original_params_.initial_max_streams_bidi.set_value(
+ kFakeInitialMaxStreamsBidi);
+ original_params_.initial_max_streams_uni.set_value(
+ kFakeInitialMaxStreamsUni);
+ original_params_.ack_delay_exponent.set_value(kFakeAckDelayExponent);
+ original_params_.max_ack_delay.set_value(kFakeMaxAckDelay);
+ original_params_.disable_active_migration = kFakeDisableMigration;
+ original_params_.preferred_address = CreateFakePreferredAddress();
+ original_params_.active_connection_id_limit.set_value(
+ kFakeActiveConnectionIdLimit);
+ original_params_.initial_source_connection_id =
+ CreateFakeInitialSourceConnectionId();
+ original_params_.retry_source_connection_id =
+ CreateFakeRetrySourceConnectionId();
+ original_params_.google_connection_options =
+ CreateFakeGoogleConnectionOptions();
+
+ ASSERT_TRUE(SerializeTransportParametersForTicket(
+ original_params_, application_state_, &original_serialized_params_));
+ }
+
+ TransportParameters original_params_;
+ std::vector<uint8_t> application_state_ = {0, 1};
+ std::vector<uint8_t> original_serialized_params_;
+};
+
+TEST_F(TransportParametersTicketSerializationTest,
+ StatelessResetTokenDoesntChangeOutput) {
+ // Test that changing the stateless reset token doesn't change the ticket
+ // serialization.
+ TransportParameters new_params = original_params_;
+ new_params.stateless_reset_token = CreateFakePreferredStatelessResetToken();
+ EXPECT_NE(new_params, original_params_);
+
+ std::vector<uint8_t> serialized;
+ ASSERT_TRUE(SerializeTransportParametersForTicket(
+ new_params, application_state_, &serialized));
+ EXPECT_EQ(original_serialized_params_, serialized);
+}
+
+TEST_F(TransportParametersTicketSerializationTest,
+ ConnectionIDDoesntChangeOutput) {
+ // Changing original destination CID doesn't change serialization.
+ TransportParameters new_params = original_params_;
+ new_params.original_destination_connection_id = TestConnectionId(0xCAFE);
+ EXPECT_NE(new_params, original_params_);
+
+ std::vector<uint8_t> serialized;
+ ASSERT_TRUE(SerializeTransportParametersForTicket(
+ new_params, application_state_, &serialized));
+ EXPECT_EQ(original_serialized_params_, serialized);
+}
+
+TEST_F(TransportParametersTicketSerializationTest, StreamLimitChangesOutput) {
+ // Changing a stream limit does change the serialization.
+ TransportParameters new_params = original_params_;
+ new_params.initial_max_stream_data_bidi_local.set_value(
+ kFakeInitialMaxStreamDataBidiLocal + 1);
+ EXPECT_NE(new_params, original_params_);
+
+ std::vector<uint8_t> serialized;
+ ASSERT_TRUE(SerializeTransportParametersForTicket(
+ new_params, application_state_, &serialized));
+ EXPECT_NE(original_serialized_params_, serialized);
+}
+
+TEST_F(TransportParametersTicketSerializationTest,
+ ApplicationStateChangesOutput) {
+ // Changing the application state changes the serialization.
+ std::vector<uint8_t> new_application_state = {0};
+ EXPECT_NE(new_application_state, application_state_);
+
+ std::vector<uint8_t> serialized;
+ ASSERT_TRUE(SerializeTransportParametersForTicket(
+ original_params_, new_application_state, &serialized));
+ EXPECT_NE(original_serialized_params_, serialized);
}
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.cc
new file mode 100644
index 00000000000..b8c7efafa98
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.cc
@@ -0,0 +1,20 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h"
+#include <cstdint>
+#include <limits>
+
+namespace quic {
+
+std::ostream& operator<<(std::ostream& os, const QuicAckFrequencyFrame& frame) {
+ os << "{ control_frame_id: " << frame.control_frame_id
+ << ", sequence_number: " << frame.sequence_number
+ << ", packet_tolerance: " << frame.packet_tolerance
+ << ", max_ack_delay_ms: " << frame.max_ack_delay.ToMilliseconds()
+ << ", ignore_order: " << frame.ignore_order << " }\n";
+ return os;
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h
new file mode 100644
index 00000000000..52b70daff2e
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_ACK_FREQUENCY_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_ACK_FREQUENCY_FRAME_H_
+
+#include <cstdint>
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/core/quic_time.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+
+namespace quic {
+
+// A frame that allows sender control of acknowledgement delays.
+struct QUIC_EXPORT_PRIVATE QuicAckFrequencyFrame {
+ friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+ std::ostream& os,
+ const QuicAckFrequencyFrame& ack_frequency_frame);
+
+ // A unique identifier of this control frame. 0 when this frame is received,
+ // and non-zero when sent.
+ QuicControlFrameId control_frame_id = kInvalidControlFrameId;
+
+ // If true, do not ack immediately upon observeation of packet reordering.
+ bool ignore_order = false;
+
+ // Sequence number assigned to the ACK_FREQUENCY frame by the sender to allow
+ // receivers to ignore obsolete frames.
+ uint64_t sequence_number = 0;
+
+ // The maximum number of ack-eliciting packets after which the receiver sends
+ // an acknowledgement. Invald if == 0.
+ uint64_t packet_tolerance = 0;
+
+ // The maximum time that ack packets can be delayed.
+ QuicTime::Delta max_ack_delay = QuicTime::Delta::Zero();
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_ACK_FREQUENCY_FRAME_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.cc
index 81b3e18a6b2..bef5f286d23 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.cc
@@ -32,8 +32,7 @@ QuicCryptoFrame::~QuicCryptoFrame() {}
std::ostream& operator<<(std::ostream& os,
const QuicCryptoFrame& stream_frame) {
- os << "{ level: " << EncryptionLevelToString(stream_frame.level)
- << ", offset: " << stream_frame.offset
+ os << "{ level: " << stream_frame.level << ", offset: " << stream_frame.offset
<< ", length: " << stream_frame.data_length << " }\n";
return os;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc
index d40202f1930..99b0963a2dc 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc
@@ -6,6 +6,7 @@
#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h"
#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
@@ -75,6 +76,9 @@ QuicFrame::QuicFrame(QuicMessageFrame* frame)
QuicFrame::QuicFrame(QuicNewTokenFrame* frame)
: type(NEW_TOKEN_FRAME), new_token_frame(frame) {}
+QuicFrame::QuicFrame(QuicAckFrequencyFrame* frame)
+ : type(ACK_FREQUENCY_FRAME), ack_frequency_frame(frame) {}
+
void DeleteFrames(QuicFrames* frames) {
for (QuicFrame& frame : *frames) {
DeleteFrame(&frame);
@@ -136,7 +140,9 @@ void DeleteFrame(QuicFrame* frame) {
case NEW_TOKEN_FRAME:
delete frame->new_token_frame;
break;
-
+ case ACK_FREQUENCY_FRAME:
+ delete frame->ack_frequency_frame;
+ break;
case NUM_FRAME_TYPES:
DCHECK(false) << "Cannot delete type: " << frame->type;
}
@@ -164,6 +170,7 @@ bool IsControlFrame(QuicFrameType type) {
case PING_FRAME:
case STOP_SENDING_FRAME:
case HANDSHAKE_DONE_FRAME:
+ case ACK_FREQUENCY_FRAME:
return true;
default:
return false;
@@ -190,6 +197,8 @@ QuicControlFrameId GetControlFrameId(const QuicFrame& frame) {
return frame.stop_sending_frame->control_frame_id;
case HANDSHAKE_DONE_FRAME:
return frame.handshake_done_frame.control_frame_id;
+ case ACK_FREQUENCY_FRAME:
+ return frame.ack_frequency_frame->control_frame_id;
default:
return kInvalidControlFrameId;
}
@@ -224,6 +233,9 @@ void SetControlFrameId(QuicControlFrameId control_frame_id, QuicFrame* frame) {
case HANDSHAKE_DONE_FRAME:
frame->handshake_done_frame.control_frame_id = control_frame_id;
return;
+ case ACK_FREQUENCY_FRAME:
+ frame->ack_frequency_frame->control_frame_id = control_frame_id;
+ return;
default:
QUIC_BUG
<< "Try to set control frame id of a frame without control frame id";
@@ -261,6 +273,9 @@ QuicFrame CopyRetransmittableControlFrame(const QuicFrame& frame) {
copy = QuicFrame(
QuicHandshakeDoneFrame(frame.handshake_done_frame.control_frame_id));
break;
+ case ACK_FREQUENCY_FRAME:
+ copy = QuicFrame(new QuicAckFrequencyFrame(*frame.ack_frequency_frame));
+ break;
default:
QUIC_BUG << "Try to copy a non-retransmittable control frame: " << frame;
copy = QuicFrame(QuicPingFrame(kInvalidControlFrameId));
@@ -352,6 +367,9 @@ QuicFrame CopyQuicFrame(QuicBufferAllocator* allocator,
copy = QuicFrame(
QuicHandshakeDoneFrame(frame.handshake_done_frame.control_frame_id));
break;
+ case ACK_FREQUENCY_FRAME:
+ copy = QuicFrame(new QuicAckFrequencyFrame(*frame.ack_frequency_frame));
+ break;
default:
QUIC_BUG << "Cannot copy frame: " << frame;
copy = QuicFrame(QuicPingFrame(kInvalidControlFrameId));
@@ -451,6 +469,9 @@ std::ostream& operator<<(std::ostream& os, const QuicFrame& frame) {
case HANDSHAKE_DONE_FRAME:
os << "type { HANDSHAKE_DONE_FRAME } " << frame.handshake_done_frame;
break;
+ case ACK_FREQUENCY_FRAME:
+ os << "type { ACK_FREQUENCY_FRAME } " << *(frame.ack_frequency_frame);
+ break;
default: {
QUIC_LOG(ERROR) << "Unknown frame type: " << frame.type;
break;
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h
index 756b69f1db0..a8aabfc4ca5 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h
@@ -9,6 +9,7 @@
#include <vector>
#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h"
#include "net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.h"
#include "net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h"
#include "net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.h"
@@ -62,6 +63,7 @@ struct QUIC_EXPORT_PRIVATE QuicFrame {
explicit QuicFrame(QuicStopSendingFrame* frame);
explicit QuicFrame(QuicMessageFrame* message_frame);
explicit QuicFrame(QuicCryptoFrame* crypto_frame);
+ explicit QuicFrame(QuicAckFrequencyFrame* ack_frequency_frame);
QUIC_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
const QuicFrame& frame);
@@ -102,6 +104,7 @@ struct QUIC_EXPORT_PRIVATE QuicFrame {
QuicStopSendingFrame* stop_sending_frame;
QuicMessageFrame* message_frame;
QuicCryptoFrame* crypto_frame;
+ QuicAckFrequencyFrame* ack_frequency_frame;
QuicNewTokenFrame* new_token_frame;
};
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc
index 22322ed8ee2..3f04c8c0704 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc
@@ -15,6 +15,7 @@
#include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h"
#include "net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h"
#include "net/third_party/quiche/src/quic/core/quic_interval.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
@@ -243,6 +244,25 @@ TEST_F(QuicFramesTest, HandshakeDoneFrameToString) {
EXPECT_TRUE(IsControlFrame(frame.type));
}
+TEST_F(QuicFramesTest, QuicAckFreuqncyFrameToString) {
+ QuicAckFrequencyFrame ack_frequency_frame;
+ ack_frequency_frame.sequence_number = 1;
+ ack_frequency_frame.packet_tolerance = 2;
+ ack_frequency_frame.max_ack_delay = QuicTime::Delta::FromMilliseconds(25);
+ ack_frequency_frame.ignore_order = false;
+ QuicFrame frame(&ack_frequency_frame);
+ ASSERT_EQ(ACK_FREQUENCY_FRAME, frame.type);
+ SetControlFrameId(6, &frame);
+ EXPECT_EQ(6u, GetControlFrameId(frame));
+ std::ostringstream stream;
+ stream << *frame.ack_frequency_frame;
+ EXPECT_EQ(
+ "{ control_frame_id: 6, sequence_number: 1, packet_tolerance: 2, "
+ "max_ack_delay_ms: 25, ignore_order: 0 }\n",
+ stream.str());
+ EXPECT_TRUE(IsControlFrame(frame.type));
+}
+
TEST_F(QuicFramesTest, StreamFrameToString) {
QuicStreamFrame frame;
frame.stream_id = 1;
@@ -558,6 +578,9 @@ TEST_F(QuicFramesTest, CopyQuicFrames) {
case HANDSHAKE_DONE_FRAME:
frames.push_back(QuicFrame(QuicHandshakeDoneFrame()));
break;
+ case ACK_FREQUENCY_FRAME:
+ frames.push_back(QuicFrame(new QuicAckFrequencyFrame()));
+ break;
default:
ASSERT_TRUE(false)
<< "Please fix CopyQuicFrames if a new frame type is added.";
diff --git a/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h b/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h
index 0e8e0454483..bfc87610fd4 100644
--- a/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h
+++ b/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h
@@ -5,6 +5,7 @@
#ifndef QUICHE_QUIC_CORE_HANDSHAKER_DELEGATE_INTERFACE_H_
#define QUICHE_QUIC_CORE_HANDSHAKER_DELEGATE_INTERFACE_H_
+#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
namespace quic {
@@ -54,6 +55,22 @@ class QUIC_EXPORT_PRIVATE HandshakerDelegateInterface {
// encryption level and 2) a server successfully processes a forward secure
// packet.
virtual void NeuterHandshakeData() = 0;
+
+ // Called when 0-RTT data is rejected by the server. This is only called in
+ // TLS handshakes and only called on clients.
+ virtual void OnZeroRttRejected() = 0;
+
+ // Fills in |params| with values from the delegate's QuicConfig.
+ // Returns whether the operation succeeded.
+ virtual bool FillTransportParameters(TransportParameters* params) = 0;
+
+ // Read |params| and apply the values to the delegate's QuicConfig.
+ // On failure, returns a QuicErrorCode and saves a detailed error in
+ // |error_details|.
+ virtual QuicErrorCode ProcessTransportParameters(
+ const TransportParameters& params,
+ bool is_resumption,
+ std::string* error_details) = 0;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc
index 782394427f4..8d274d03739 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc
@@ -37,7 +37,9 @@
#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
#include "net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.h"
#include "net/third_party/quiche/src/quic/test_tools/packet_reordering_writer.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_client_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h"
@@ -55,6 +57,7 @@
#include "net/third_party/quiche/src/quic/test_tools/quic_test_server.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
#include "net/third_party/quiche/src/quic/test_tools/server_thread.h"
+#include "net/third_party/quiche/src/quic/test_tools/simple_session_cache.h"
#include "net/third_party/quiche/src/quic/tools/quic_backend_response.h"
#include "net/third_party/quiche/src/quic/tools/quic_client.h"
#include "net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h"
@@ -70,6 +73,9 @@ using spdy::SpdyFramer;
using spdy::SpdyHeaderBlock;
using spdy::SpdySerializedFrame;
using spdy::SpdySettingsIR;
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::NiceMock;
namespace quic {
namespace test {
@@ -77,6 +83,7 @@ namespace {
const char kFooResponseBody[] = "Artichoke hearts make me happy.";
const char kBarResponseBody[] = "Palm hearts are pretty delicious, also.";
+const char kTestUserAgentId[] = "quic/core/http/end_to_end_test.cc";
const float kSessionToStreamRatio = 1.5;
// Run all tests with the cross products of all versions.
@@ -191,6 +198,16 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
AddToCache("/foo", 200, kFooResponseBody);
AddToCache("/bar", 200, kBarResponseBody);
+ // Enable fixes for bugs found in tests and prod.
+ SetQuicReloadableFlag(quic_donot_change_queued_ack, true);
+ SetQuicReloadableFlag(quic_fix_last_inflight_packets_sent_time, true);
+ SetQuicReloadableFlag(quic_fix_server_pto_timeout, true);
+ SetQuicReloadableFlag(quic_do_not_retransmit_immediately_on_zero_rtt_reject,
+ true);
+
+ SetQuicReloadableFlag(quic_support_handshake_done_in_t050, true);
+ SetQuicReloadableFlag(quic_enable_tls_resumption, true);
+ SetQuicReloadableFlag(quic_enable_zero_rtt_for_tls, true);
}
~EndToEndTest() override { QuicRecyclePort(server_address_.port()); }
@@ -203,7 +220,9 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
QuicTestClient* client =
new QuicTestClient(server_address_, server_hostname_, client_config_,
client_supported_versions_,
- crypto_test_utils::ProofVerifierForTesting());
+ crypto_test_utils::ProofVerifierForTesting(),
+ std::make_unique<SimpleSessionCache>());
+ client->SetUserAgentID(kTestUserAgentId);
client->UseWriter(writer);
if (!pre_shared_key_client_.empty()) {
client->client()->SetPreSharedKey(pre_shared_key_client_);
@@ -441,6 +460,13 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
EXPECT_EQ(0u, server_stats.packets_lost);
}
EXPECT_EQ(0u, server_stats.packets_discarded);
+ if (GetQuicReloadableFlag(quic_save_user_agent_in_quic_session)) {
+ EXPECT_EQ(
+ GetServerSession()->user_agent_id().value_or("MissingUserAgent"),
+ kTestUserAgentId);
+ } else {
+ EXPECT_FALSE(GetServerSession()->user_agent_id().has_value());
+ }
// TODO(ianswett): Restore the check for packets_dropped equals 0.
// The expect for packets received is equal to packets processed fails
// due to version negotiation packets.
@@ -529,7 +555,7 @@ INSTANTIATE_TEST_SUITE_P(EndToEndTests,
TEST_P(EndToEndTest, HandshakeSuccessful) {
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
server_thread_->WaitForCryptoHandshakeConfirmed();
QuicCryptoStream* crypto_stream =
QuicSessionPeer::GetMutableCryptoStream(GetClientSession());
@@ -568,7 +594,7 @@ TEST_P(EndToEndTest, SimpleRequestResponse) {
TEST_P(EndToEndTest, HandshakeConfirmed) {
ASSERT_TRUE(Initialize());
- if (!version_.HasHandshakeDone()) {
+ if (!version_.UsesTls()) {
return;
}
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
@@ -599,44 +625,27 @@ TEST_P(EndToEndTest, SendAndReceiveCoalescedPackets) {
// Simple transaction, but set a non-default ack delay at the client
// and ensure it gets to the server.
TEST_P(EndToEndTest, SimpleRequestResponseWithAckDelayChange) {
- if (version_.UsesTls()) {
- // TODO(b/155316241): Enable this test for TLS.
- Initialize();
- return;
- }
// Force the ACK delay to be something other than the default.
- // Note that it is sent only if doing IETF QUIC.
- client_config_.SetMaxAckDelayToSendMs(kDefaultDelayedAckTimeMs + 100u);
+ constexpr uint32_t kClientMaxAckDelay = kDefaultDelayedAckTimeMs + 100u;
+ client_config_.SetMaxAckDelayToSendMs(kClientMaxAckDelay);
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
EXPECT_FALSE(client_->client()->EarlyDataAccepted());
EXPECT_FALSE(client_->client()->ReceivedInchoateReject());
- if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
- EXPECT_EQ(kDefaultDelayedAckTimeMs + 100u,
- GetSentPacketManagerFromFirstServerSession()
- ->peer_max_ack_delay()
- .ToMilliseconds());
- } else {
- EXPECT_EQ(kDefaultDelayedAckTimeMs,
- GetSentPacketManagerFromFirstServerSession()
- ->peer_max_ack_delay()
- .ToMilliseconds());
- }
+ EXPECT_EQ(kClientMaxAckDelay, GetSentPacketManagerFromFirstServerSession()
+ ->peer_max_ack_delay()
+ .ToMilliseconds());
}
// Simple transaction, but set a non-default ack exponent at the client
// and ensure it gets to the server.
TEST_P(EndToEndTest, SimpleRequestResponseWithAckExponentChange) {
- if (version_.UsesTls()) {
- // TODO(b/155316241): Enable this test for TLS.
- Initialize();
- return;
- }
- const uint32_t kClientAckDelayExponent = kDefaultAckDelayExponent + 100u;
+ const uint32_t kClientAckDelayExponent = 19;
+ EXPECT_NE(kClientAckDelayExponent, kDefaultAckDelayExponent);
// Force the ACK exponent to be something other than the default.
- // Note that it is sent only if doing IETF QUIC.
+ // Note that it is sent only with QUIC+TLS.
client_config_.SetAckDelayExponentToSend(kClientAckDelayExponent);
ASSERT_TRUE(Initialize());
@@ -645,12 +654,12 @@ TEST_P(EndToEndTest, SimpleRequestResponseWithAckExponentChange) {
EXPECT_FALSE(client_->client()->EarlyDataAccepted());
EXPECT_FALSE(client_->client()->ReceivedInchoateReject());
- if (VersionHasIetfQuicFrames(version_.transport_version)) {
- // Should be only for IETF QUIC.
+ if (version_.UsesTls()) {
+ // Should be only sent with QUIC+TLS.
EXPECT_EQ(kClientAckDelayExponent,
GetServerConnection()->framer().peer_ack_delay_exponent());
} else {
- // No change for Google QUIC.
+ // No change for QUIC_CRYPTO.
EXPECT_EQ(kDefaultAckDelayExponent,
GetServerConnection()->framer().peer_ack_delay_exponent());
}
@@ -662,9 +671,9 @@ TEST_P(EndToEndTest, SimpleRequestResponseWithAckExponentChange) {
TEST_P(EndToEndTest, SimpleRequestResponseForcedVersionNegotiation) {
client_supported_versions_.insert(client_supported_versions_.begin(),
QuicVersionReservedForNegotiation());
- testing::NiceMock<MockQuicConnectionDebugVisitor> visitor;
+ NiceMock<MockQuicConnectionDebugVisitor> visitor;
connection_debug_visitor_ = &visitor;
- EXPECT_CALL(visitor, OnVersionNegotiationPacket(testing::_)).Times(1);
+ EXPECT_CALL(visitor, OnVersionNegotiationPacket(_)).Times(1);
ASSERT_TRUE(Initialize());
ASSERT_TRUE(ServerSendsVersionNegotiation());
@@ -1103,7 +1112,7 @@ TEST_P(EndToEndTest, PostMissingBytes) {
TEST_P(EndToEndTest, LargePostNoPacketLoss) {
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
// 1 MB body.
std::string body(1024 * 1024, 'a');
@@ -1124,7 +1133,7 @@ TEST_P(EndToEndTest, LargePostNoPacketLoss1sRTT) {
ASSERT_TRUE(Initialize());
SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(1000));
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
// 100 KB body.
std::string body(100 * 1024, 'a');
@@ -1145,9 +1154,7 @@ TEST_P(EndToEndTest, LargePostWithPacketLoss) {
// brutal.
SetPacketLossPercentage(5);
ASSERT_TRUE(Initialize());
-
- // Wait for the server SHLO before upping the packet loss.
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForHandshakeConfirmed());
SetPacketLossPercentage(30);
// 10 KB body.
@@ -1166,9 +1173,7 @@ TEST_P(EndToEndTest, LargePostWithPacketLoss) {
// Regression test for b/80090281.
TEST_P(EndToEndTest, LargePostWithPacketLossAndAlwaysBundleWindowUpdates) {
ASSERT_TRUE(Initialize());
-
- // Wait for the server SHLO before upping the packet loss.
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForHandshakeConfirmed());
server_thread_->WaitForCryptoHandshakeConfirmed();
// Normally server only bundles a retransmittable frame once every other
@@ -1199,9 +1204,7 @@ TEST_P(EndToEndTest, LargePostWithPacketLossAndBlockedSocket) {
// b/10126687 is fixed, losing handshake packets is pretty brutal.
SetPacketLossPercentage(5);
ASSERT_TRUE(Initialize());
-
- // Wait for the server SHLO before upping the packet loss.
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForHandshakeConfirmed());
SetPacketLossPercentage(10);
client_writer_->set_fake_blocked_socket_percentage(10);
@@ -1219,8 +1222,7 @@ TEST_P(EndToEndTest, LargePostWithPacketLossAndBlockedSocket) {
TEST_P(EndToEndTest, LargePostNoPacketLossWithDelayAndReordering) {
ASSERT_TRUE(Initialize());
-
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForHandshakeConfirmed());
// Both of these must be called when the writer is not actively used.
SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
SetReorderPercentage(30);
@@ -1238,11 +1240,6 @@ TEST_P(EndToEndTest, LargePostNoPacketLossWithDelayAndReordering) {
}
TEST_P(EndToEndTest, LargePostZeroRTTFailure) {
- if (version_.UsesTls()) {
- // TODO(b/152551499): Re-enable this test when TLS supports 0-RTT.
- Initialize();
- return;
- }
// Send a request and then disconnect. This prepares the client to attempt
// a 0-RTT handshake for the next request.
ASSERT_TRUE(Initialize());
@@ -1265,7 +1262,7 @@ TEST_P(EndToEndTest, LargePostZeroRTTFailure) {
// The 0-RTT handshake should succeed.
client_->Connect();
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
ASSERT_TRUE(client_->client()->connected());
EXPECT_EQ(kFooResponseBody,
client_->SendCustomSynchronousRequest(headers, body));
@@ -1281,7 +1278,7 @@ TEST_P(EndToEndTest, LargePostZeroRTTFailure) {
StartServer();
client_->Connect();
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
ASSERT_TRUE(client_->client()->connected());
EXPECT_EQ(kFooResponseBody,
client_->SendCustomSynchronousRequest(headers, body));
@@ -1294,11 +1291,6 @@ TEST_P(EndToEndTest, LargePostZeroRTTFailure) {
}
TEST_P(EndToEndTest, SynchronousRequestZeroRTTFailure) {
- if (version_.UsesTls()) {
- // TODO(b/152551499): Re-enable this test when TLS supports 0-RTT.
- Initialize();
- return;
- }
// Send a request and then disconnect. This prepares the client to attempt
// a 0-RTT handshake for the next request.
ASSERT_TRUE(Initialize());
@@ -1313,7 +1305,7 @@ TEST_P(EndToEndTest, SynchronousRequestZeroRTTFailure) {
// The 0-RTT handshake should succeed.
client_->Connect();
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
ASSERT_TRUE(client_->client()->connected());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
@@ -1328,7 +1320,7 @@ TEST_P(EndToEndTest, SynchronousRequestZeroRTTFailure) {
StartServer();
client_->Connect();
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
ASSERT_TRUE(client_->client()->connected());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
@@ -1360,14 +1352,10 @@ TEST_P(EndToEndTest, LargePostSynchronousRequest) {
EXPECT_FALSE(client_->client()->ReceivedInchoateReject());
client_->Disconnect();
- if (version_.UsesTls()) {
- // TODO(b/152551499): remove this when TLS supports 0-RTT.
- return;
- }
// The 0-RTT handshake should succeed.
client_->Connect();
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
ASSERT_TRUE(client_->client()->connected());
EXPECT_EQ(kFooResponseBody,
client_->SendCustomSynchronousRequest(headers, body));
@@ -1383,7 +1371,7 @@ TEST_P(EndToEndTest, LargePostSynchronousRequest) {
StartServer();
client_->Connect();
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
ASSERT_TRUE(client_->client()->connected());
EXPECT_EQ(kFooResponseBody,
client_->SendCustomSynchronousRequest(headers, body));
@@ -1413,7 +1401,7 @@ TEST_P(EndToEndTest, SetInitialReceivedConnectionOptions) {
initial_received_options));
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
server_thread_->WaitForCryptoHandshakeConfirmed();
EXPECT_FALSE(server_config_.SetInitialReceivedConnectionOptions(
@@ -1438,7 +1426,7 @@ TEST_P(EndToEndTest, LargePostSmallBandwidthLargeBuffer) {
server_writer_->set_max_bandwidth_and_buffer_size(
QuicBandwidth::FromBytesPerSecond(256 * 1024), 256 * 1024);
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
// 1 MB body.
std::string body(1024 * 1024, 'a');
@@ -1462,7 +1450,7 @@ TEST_P(EndToEndTest, DoNotSetSendAlarmIfConnectionFlowControlBlocked) {
// an infinite loop in the EpollServer, as the alarm fires and is immediately
// rescheduled.
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
// Ensure both stream and connection level are flow control blocked by setting
// the send window offset to 0.
@@ -1498,7 +1486,7 @@ TEST_P(EndToEndTest, DoNotSetSendAlarmIfConnectionFlowControlBlocked) {
TEST_P(EndToEndTest, InvalidStream) {
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
std::string body(kMaxOutgoingPacketSize, 'a');
SpdyHeaderBlock headers;
@@ -1523,7 +1511,7 @@ TEST_P(EndToEndTest, InvalidStream) {
// with overly large headers.
TEST_P(EndToEndTest, LargeHeaders) {
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
std::string body(kMaxOutgoingPacketSize, 'a');
SpdyHeaderBlock headers;
@@ -1552,7 +1540,7 @@ TEST_P(EndToEndTest, LargeHeaders) {
TEST_P(EndToEndTest, EarlyResponseWithQuicStreamNoError) {
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
std::string large_body(1024 * 1024, 'a');
SpdyHeaderBlock headers;
@@ -1618,7 +1606,7 @@ TEST_P(EndToEndTest, MaxDynamicStreamsLimitRespected) {
// not properly set up.
return;
}
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
// Make the client misbehave after negotiation.
const int kServerMaxStreams = kMaxStreamsMinimumIncrement + 1;
@@ -1654,7 +1642,7 @@ TEST_P(EndToEndTest, SetIndependentMaxDynamicStreamsLimits) {
server_config_.SetMaxUnidirectionalStreamsToSend(kServerMaxDynamicStreams);
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
// The client has received the server's limit and vice versa.
QuicSpdyClientSession* client_session = GetClientSession();
@@ -1711,7 +1699,7 @@ TEST_P(EndToEndTest, SetIndependentMaxDynamicStreamsLimits) {
TEST_P(EndToEndTest, NegotiateCongestionControl) {
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
CongestionControlType expected_congestion_control_type = kRenoBytes;
switch (GetParam().congestion_control_tag) {
@@ -1745,7 +1733,7 @@ TEST_P(EndToEndTest, ClientSuggestsRTT) {
client_config_.SetInitialRoundTripTimeUsToSend(kInitialRTT.ToMicroseconds());
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
server_thread_->WaitForCryptoHandshakeConfirmed();
// Pause the server so we can access the server's internals without races.
@@ -1774,7 +1762,7 @@ TEST_P(EndToEndTest, ClientSuggestsIgnoredRTT) {
client_config_.SetConnectionOptionsToSend(options);
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
server_thread_->WaitForCryptoHandshakeConfirmed();
// Pause the server so we can access the server's internals without races.
@@ -1801,7 +1789,7 @@ TEST_P(EndToEndTest, MaxInitialRTT) {
kMaxInitialRoundTripTimeUs);
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
server_thread_->WaitForCryptoHandshakeConfirmed();
// Pause the server so we can access the server's internals without races.
@@ -1827,7 +1815,7 @@ TEST_P(EndToEndTest, MinInitialRTT) {
client_config_.SetInitialRoundTripTimeUsToSend(0);
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
server_thread_->WaitForCryptoHandshakeConfirmed();
// Pause the server so we can access the server's internals without races.
@@ -1908,7 +1896,7 @@ TEST_P(EndToEndTest, ResetConnection) {
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
client_->ResetConnection();
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar"));
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
}
@@ -1923,7 +1911,7 @@ TEST_P(EndToEndTest, MaxStreamsUberTest) {
AddToCache("/large_response", 200, large_body);
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
SetPacketLossPercentage(10);
for (int i = 0; i < max_streams; ++i) {
@@ -1942,7 +1930,7 @@ TEST_P(EndToEndTest, StreamCancelErrorTest) {
AddToCache("/small_response", 200, small_body);
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
QuicSession* session = GetClientSession();
// Lose the request.
@@ -1952,11 +1940,7 @@ TEST_P(EndToEndTest, StreamCancelErrorTest) {
// Transmit the cancel, and ensure the connection is torn down properly.
SetPacketLossPercentage(0);
QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0);
- if (session->break_close_loop()) {
- session->ResetStream(stream_id, QUIC_STREAM_CANCELLED, 0);
- } else {
- session->SendRstStream(stream_id, QUIC_STREAM_CANCELLED, 0);
- }
+ session->ResetStream(stream_id, QUIC_STREAM_CANCELLED, 0);
// WaitForEvents waits 50ms and returns true if there are outstanding
// requests.
@@ -2050,7 +2034,7 @@ TEST_P(EndToEndTest, NegotiatedInitialCongestionWindow) {
ASSERT_TRUE(Initialize());
// Values are exchanged during crypto handshake, so wait for that to finish.
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
server_thread_->WaitForCryptoHandshakeConfirmed();
server_thread_->Pause();
@@ -2060,11 +2044,6 @@ TEST_P(EndToEndTest, NegotiatedInitialCongestionWindow) {
}
TEST_P(EndToEndTest, DifferentFlowControlWindows) {
- if (version_.UsesTls()) {
- // TODO(b/155316241): Enable this test for TLS.
- Initialize();
- return;
- }
// Client and server can set different initial flow control receive windows.
// These are sent in CHLO/SHLO. Tests that these values are exchanged properly
// in the crypto handshake.
@@ -2081,7 +2060,7 @@ TEST_P(EndToEndTest, DifferentFlowControlWindows) {
ASSERT_TRUE(Initialize());
// Values are exchanged during crypto handshake, so wait for that to finish.
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
server_thread_->WaitForCryptoHandshakeConfirmed();
// Open a data stream to make sure the stream level flow control is updated.
@@ -2089,17 +2068,28 @@ TEST_P(EndToEndTest, DifferentFlowControlWindows) {
WriteHeadersOnStream(stream);
stream->WriteOrBufferBody("hello", false);
- // Client should have the right values for server's receive window.
- EXPECT_EQ(kServerStreamIFCW,
- client_->client()
- ->client_session()
- ->config()
- ->ReceivedInitialStreamFlowControlWindowBytes());
- EXPECT_EQ(kServerSessionIFCW,
- client_->client()
- ->client_session()
- ->config()
- ->ReceivedInitialSessionFlowControlWindowBytes());
+ if (!version_.UsesTls()) {
+ // IFWA only exists with QUIC_CRYPTO.
+ // Client should have the right values for server's receive window.
+ ASSERT_TRUE(client_->client()
+ ->client_session()
+ ->config()
+ ->HasReceivedInitialStreamFlowControlWindowBytes());
+ EXPECT_EQ(kServerStreamIFCW,
+ client_->client()
+ ->client_session()
+ ->config()
+ ->ReceivedInitialStreamFlowControlWindowBytes());
+ ASSERT_TRUE(client_->client()
+ ->client_session()
+ ->config()
+ ->HasReceivedInitialSessionFlowControlWindowBytes());
+ EXPECT_EQ(kServerSessionIFCW,
+ client_->client()
+ ->client_session()
+ ->config()
+ ->ReceivedInitialSessionFlowControlWindowBytes());
+ }
EXPECT_EQ(kServerStreamIFCW, QuicFlowControllerPeer::SendWindowOffset(
stream->flow_controller()));
EXPECT_EQ(kServerSessionIFCW, QuicFlowControllerPeer::SendWindowOffset(
@@ -2107,23 +2097,24 @@ TEST_P(EndToEndTest, DifferentFlowControlWindows) {
// Server should have the right values for client's receive window.
server_thread_->Pause();
- QuicSession* session = GetServerSession();
- EXPECT_EQ(kClientStreamIFCW,
- session->config()->ReceivedInitialStreamFlowControlWindowBytes());
- EXPECT_EQ(kClientSessionIFCW,
- session->config()->ReceivedInitialSessionFlowControlWindowBytes());
+ QuicConfig server_config = *GetServerSession()->config();
EXPECT_EQ(kClientSessionIFCW, QuicFlowControllerPeer::SendWindowOffset(
- session->flow_controller()));
+ GetServerSession()->flow_controller()));
server_thread_->Resume();
+ if (version_.UsesTls()) {
+ // IFWA only exists with QUIC_CRYPTO.
+ return;
+ }
+ ASSERT_TRUE(server_config.HasReceivedInitialStreamFlowControlWindowBytes());
+ EXPECT_EQ(kClientStreamIFCW,
+ server_config.ReceivedInitialStreamFlowControlWindowBytes());
+ ASSERT_TRUE(server_config.HasReceivedInitialSessionFlowControlWindowBytes());
+ EXPECT_EQ(kClientSessionIFCW,
+ server_config.ReceivedInitialSessionFlowControlWindowBytes());
}
// Test negotiation of IFWA connection option.
TEST_P(EndToEndTest, NegotiatedServerInitialFlowControlWindow) {
- if (version_.UsesTls()) {
- // TODO(b/155316241): Enable this test for TLS.
- Initialize();
- return;
- }
const uint32_t kClientStreamIFCW = 123456;
const uint32_t kClientSessionIFCW = 234567;
set_client_initial_stream_flow_control_receive_window(kClientStreamIFCW);
@@ -2142,7 +2133,7 @@ TEST_P(EndToEndTest, NegotiatedServerInitialFlowControlWindow) {
ASSERT_TRUE(Initialize());
// Values are exchanged during crypto handshake, so wait for that to finish.
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
server_thread_->WaitForCryptoHandshakeConfirmed();
// Open a data stream to make sure the stream level flow control is updated.
@@ -2150,17 +2141,28 @@ TEST_P(EndToEndTest, NegotiatedServerInitialFlowControlWindow) {
WriteHeadersOnStream(stream);
stream->WriteOrBufferBody("hello", false);
- // Client should have the right values for server's receive window.
- EXPECT_EQ(kExpectedStreamIFCW,
- client_->client()
- ->client_session()
- ->config()
- ->ReceivedInitialStreamFlowControlWindowBytes());
- EXPECT_EQ(kExpectedSessionIFCW,
- client_->client()
- ->client_session()
- ->config()
- ->ReceivedInitialSessionFlowControlWindowBytes());
+ if (!version_.UsesTls()) {
+ // IFWA only exists with QUIC_CRYPTO.
+ // Client should have the right values for server's receive window.
+ ASSERT_TRUE(client_->client()
+ ->client_session()
+ ->config()
+ ->HasReceivedInitialStreamFlowControlWindowBytes());
+ EXPECT_EQ(kExpectedStreamIFCW,
+ client_->client()
+ ->client_session()
+ ->config()
+ ->ReceivedInitialStreamFlowControlWindowBytes());
+ ASSERT_TRUE(client_->client()
+ ->client_session()
+ ->config()
+ ->HasReceivedInitialSessionFlowControlWindowBytes());
+ EXPECT_EQ(kExpectedSessionIFCW,
+ client_->client()
+ ->client_session()
+ ->config()
+ ->ReceivedInitialSessionFlowControlWindowBytes());
+ }
EXPECT_EQ(kExpectedStreamIFCW, QuicFlowControllerPeer::SendWindowOffset(
stream->flow_controller()));
EXPECT_EQ(kExpectedSessionIFCW, QuicFlowControllerPeer::SendWindowOffset(
@@ -2182,7 +2184,7 @@ TEST_P(EndToEndTest, HeadersAndCryptoStreamsNoConnectionFlowControl) {
// Wait for crypto handshake to finish. This should have contributed to the
// crypto stream flow control window, but not affected the session flow
// control window.
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
server_thread_->WaitForCryptoHandshakeConfirmed();
QuicCryptoStream* crypto_stream =
@@ -2236,7 +2238,7 @@ TEST_P(EndToEndTest, FlowControlsSynced) {
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
server_thread_->WaitForCryptoHandshakeConfirmed();
QuicSpdySession* const client_session = GetClientSession();
@@ -2353,28 +2355,26 @@ TEST_P(EndToEndTest, RequestWithNoBodyWillNeverSendStreamFrameWithFIN) {
server_thread_->Resume();
}
-// A TestAckListener verifies that exactly |bytes_to_ack| bytes are acked during
-// its lifetime.
+// TestAckListener counts how many bytes are acked during its lifetime.
class TestAckListener : public QuicAckListenerInterface {
public:
- explicit TestAckListener(int bytes_to_ack) : bytes_to_ack_(bytes_to_ack) {}
+ TestAckListener() {}
void OnPacketAcked(int acked_bytes,
QuicTime::Delta /*delta_largest_observed*/) override {
- ASSERT_LE(acked_bytes, bytes_to_ack_);
- bytes_to_ack_ -= acked_bytes;
+ total_bytes_acked_ += acked_bytes;
}
void OnPacketRetransmitted(int /*retransmitted_bytes*/) override {}
- bool has_been_notified() const { return bytes_to_ack_ == 0; }
+ int total_bytes_acked() const { return total_bytes_acked_; }
protected:
// Object is ref counted.
- ~TestAckListener() override { EXPECT_EQ(0, bytes_to_ack_); }
+ ~TestAckListener() override {}
private:
- int bytes_to_ack_;
+ int total_bytes_acked_ = 0;
};
class TestResponseListener : public QuicSpdyClientBase::ResponseListener {
@@ -2388,22 +2388,35 @@ class TestResponseListener : public QuicSpdyClientBase::ResponseListener {
}
};
-// TODO(dschinazi) Fix this test's flakiness in Chrome.
-TEST_P(
- EndToEndTest,
- QUIC_TEST_DISABLED_IN_CHROME(AckNotifierWithPacketLossAndBlockedSocket)) {
+TEST_P(EndToEndTest, AckNotifierWithPacketLossAndBlockedSocket) {
// Verify that even in the presence of packet loss and occasionally blocked
// socket, an AckNotifierDelegate will get informed that the data it is
// interested in has been ACKed. This tests end-to-end ACK notification, and
// demonstrates that retransmissions do not break this functionality.
SetPacketLossPercentage(5);
ASSERT_TRUE(Initialize());
-
// Wait for the server SHLO before upping the packet loss.
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForHandshakeConfirmed());
SetPacketLossPercentage(30);
client_writer_->set_fake_blocked_socket_percentage(10);
+ // Wait for SETTINGS frame from server that sets QPACK dynamic table capacity
+ // to make sure request headers will be compressed using the dynamic table.
+ if (version_.UsesHttp3()) {
+ while (true) {
+ // Waits for up to 50 ms.
+ client_->client()->WaitForEvents();
+ if (!GetClientSession() || !GetClientSession()->qpack_encoder()) {
+ continue;
+ }
+ QpackHeaderTable* header_table =
+ QpackEncoderPeer::header_table(GetClientSession()->qpack_encoder());
+ if (QpackHeaderTablePeer::dynamic_table_capacity(header_table) > 0) {
+ break;
+ }
+ }
+ }
+
// Create a POST request and send the headers only.
SpdyHeaderBlock headers;
headers[":method"] = "POST";
@@ -2413,14 +2426,11 @@ TEST_P(
client_->SendMessage(headers, "", /*fin=*/false);
- // Size of headers on the request stream. Zero if headers are sent on the
- // header stream.
+ // Size of headers on the request stream. This is zero if headers are sent on
+ // the header stream.
size_t header_size = 0;
- if (VersionUsesHttp3(client_->client()
- ->client_session()
- ->connection()
- ->transport_version())) {
- // Determine size of compressed headers.
+ if (version_.UsesHttp3()) {
+ // Determine size of headers after QPACK compression in both scenarios.
NoopDecoderStreamErrorDelegate decoder_stream_error_delegate;
NoopQpackStreamSenderDelegate encoder_stream_sender_delegate;
QpackEncoder qpack_encoder(&decoder_stream_error_delegate);
@@ -2432,8 +2442,8 @@ TEST_P(
qpack_encoder.SetDynamicTableCapacity(kDefaultQpackMaxDynamicTableCapacity);
qpack_encoder.SetMaximumBlockedStreams(kDefaultMaximumBlockedStreams);
- std::string encoded_headers =
- qpack_encoder.EncodeHeaderList(/* stream_id = */ 0, headers, nullptr);
+ std::string encoded_headers = qpack_encoder.EncodeHeaderList(
+ /* stream_id = */ 0, headers, nullptr);
header_size = encoded_headers.size();
}
@@ -2442,9 +2452,11 @@ TEST_P(
std::string request_string = "a request body bigger than one packet" +
std::string(kMaxOutgoingPacketSize, '.');
+ const int expected_bytes_acked = header_size + request_string.length();
+
// The TestAckListener will cause a failure if not notified.
QuicReferenceCountedPointer<TestAckListener> ack_listener(
- new TestAckListener(header_size + request_string.length()));
+ new TestAckListener());
// Send the request, and register the delegate for ACKs.
client_->SendData(request_string, true, ack_listener);
@@ -2456,17 +2468,20 @@ TEST_P(
client_->SendSynchronousRequest("/bar");
// Make sure the delegate does get the notification it expects.
- while (!ack_listener->has_been_notified()) {
+ while (ack_listener->total_bytes_acked() < expected_bytes_acked) {
// Waits for up to 50 ms.
client_->client()->WaitForEvents();
}
+ EXPECT_EQ(ack_listener->total_bytes_acked(), expected_bytes_acked)
+ << " header_size " << header_size << " request length "
+ << request_string.length();
}
// Send a public reset from the server.
TEST_P(EndToEndTest, ServerSendPublicReset) {
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
QuicConnection* client_connection = GetClientConnection();
QuicConfig* config = client_->client()->session()->config();
EXPECT_TRUE(config->HasReceivedStatelessResetToken());
@@ -2504,7 +2519,7 @@ TEST_P(EndToEndTest, ServerSendPublicReset) {
TEST_P(EndToEndTest, ServerSendPublicResetWithDifferentConnectionId) {
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
QuicConnection* client_connection = GetClientConnection();
QuicConfig* config = client_->client()->session()->config();
EXPECT_TRUE(config->HasReceivedStatelessResetToken());
@@ -2517,7 +2532,7 @@ TEST_P(EndToEndTest, ServerSendPublicResetWithDifferentConnectionId) {
QuicFramer framer(server_supported_versions_, QuicTime::Zero(),
Perspective::IS_SERVER, kQuicDefaultConnectionIdLength);
std::unique_ptr<QuicEncryptedPacket> packet;
- testing::NiceMock<MockQuicConnectionDebugVisitor> visitor;
+ NiceMock<MockQuicConnectionDebugVisitor> visitor;
GetClientConnection()->set_debug_visitor(&visitor);
if (VersionHasIetfInvariantHeader(client_connection->transport_version())) {
packet = framer.BuildIetfStatelessResetPacket(incorrect_connection_id,
@@ -2581,7 +2596,7 @@ TEST_P(EndToEndTest, ClientSendPublicResetWithDifferentConnectionId) {
TEST_P(EndToEndTest, ServerSendVersionNegotiationWithDifferentConnectionId) {
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
// Send the version negotiation packet.
QuicConnection* client_connection = GetClientConnection();
@@ -2593,7 +2608,7 @@ TEST_P(EndToEndTest, ServerSendVersionNegotiationWithDifferentConnectionId) {
VersionHasIetfInvariantHeader(client_connection->transport_version()),
client_connection->version().HasLengthPrefixedConnectionIds(),
server_supported_versions_));
- testing::NiceMock<MockQuicConnectionDebugVisitor> visitor;
+ NiceMock<MockQuicConnectionDebugVisitor> visitor;
client_connection->set_debug_visitor(&visitor);
EXPECT_CALL(visitor, OnIncorrectConnectionId(incorrect_connection_id))
.Times(1);
@@ -2733,7 +2748,7 @@ TEST_P(EndToEndTest, BadEncryptedData) {
TEST_P(EndToEndTest, CanceledStreamDoesNotBecomeZombie) {
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
// Lose the request.
SetPacketLossPercentage(100);
SpdyHeaderBlock headers;
@@ -2934,7 +2949,7 @@ TEST_P(EndToEndTest, EarlyResponseFinRecording) {
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
// A POST that gets an early error response, after the headers are received
// and before the body is received, due to invalid content-length.
@@ -2982,7 +2997,7 @@ TEST_P(EndToEndTest, EarlyResponseFinRecording) {
TEST_P(EndToEndTest, Trailers) {
// Test sending and receiving HTTP/2 Trailers (trailing HEADERS frames).
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
// Set reordering to ensure that Trailers arriving before body is ok.
SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
@@ -3014,6 +3029,7 @@ class EndToEndTestServerPush : public EndToEndTest {
const size_t kNumMaxStreams = 10;
EndToEndTestServerPush() : EndToEndTest() {
+ SetQuicFlag(FLAGS_quic_enable_http3_server_push, true);
client_config_.SetMaxBidirectionalStreamsToSend(kNumMaxStreams);
server_config_.SetMaxBidirectionalStreamsToSend(kNumMaxStreams);
client_config_.SetMaxUnidirectionalStreamsToSend(kNumMaxStreams);
@@ -3068,7 +3084,7 @@ INSTANTIATE_TEST_SUITE_P(EndToEndTestsServerPush,
TEST_P(EndToEndTestServerPush, ServerPush) {
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
// Set reordering to ensure that body arriving before PUSH_PROMISE is ok.
SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
@@ -3092,10 +3108,7 @@ TEST_P(EndToEndTestServerPush, ServerPush) {
EXPECT_EQ(kBody, client_->SendSynchronousRequest(
"https://example.com/push_example"));
QuicStreamSequencer* sequencer;
- if (!VersionUsesHttp3(client_->client()
- ->client_session()
- ->connection()
- ->transport_version())) {
+ if (!version_.UsesHttp3()) {
QuicHeadersStream* headers_stream =
QuicSpdySessionPeer::GetHeadersStream(GetClientSession());
sequencer = QuicStreamPeer::sequencer(headers_stream);
@@ -3113,27 +3126,23 @@ TEST_P(EndToEndTestServerPush, ServerPush) {
QUIC_DVLOG(1) << "response body " << response_body;
EXPECT_EQ(expected_body, response_body);
}
- if (!VersionUsesHttp3(client_->client()
- ->client_session()
- ->connection()
- ->transport_version())) {
+ if (!version_.UsesHttp3()) {
EXPECT_FALSE(
QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
}
}
TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) {
- if (version_.UsesTls()) {
- // TODO(b/155316241): Enable this test for TLS.
- Initialize();
- return;
- }
// Tests that sending a request which has 4 push resources will trigger server
// to push those 4 resources and client can handle pushed resources and match
// them with requests later.
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
+ if (version_.UsesHttp3()) {
+ static_cast<QuicSpdySession*>(client_->client()->session())
+ ->SetMaxPushId(kMaxQuicStreamId);
+ }
// Set reordering to ensure that body arriving before PUSH_PROMISE is ok.
SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
@@ -3177,9 +3186,10 @@ TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) {
}
TEST_P(EndToEndTestServerPush, ServerPushOverLimitNonBlocking) {
- if (version_.UsesTls()) {
- // TODO(b/155316241): Enable this test for TLS.
- Initialize();
+ if (version_.UsesHttp3()) {
+ // TODO(b/142504641): Re-enable this test when we support push streams
+ // arriving before the corresponding promises.
+ ASSERT_TRUE(Initialize());
return;
}
// Tests that when streams are not blocked by flow control or congestion
@@ -3187,15 +3197,10 @@ TEST_P(EndToEndTestServerPush, ServerPushOverLimitNonBlocking) {
// streams should still work because all response streams get closed
// immediately after pushing resources.
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
-
- if (VersionUsesHttp3(client_->client()
- ->client_session()
- ->connection()
- ->transport_version())) {
- // TODO(b/142504641): Re-enable this test when we support push streams
- // arriving before the corresponding promises.
- return;
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
+ if (version_.UsesHttp3()) {
+ static_cast<QuicSpdySession*>(client_->client()->session())
+ ->SetMaxPushId(kMaxQuicStreamId);
}
// Set reordering to ensure that body arriving before PUSH_PROMISE is ok.
@@ -3240,11 +3245,6 @@ TEST_P(EndToEndTestServerPush, ServerPushOverLimitNonBlocking) {
}
TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) {
- if (version_.UsesTls()) {
- // TODO(b/155316241): Enable this test for TLS.
- Initialize();
- return;
- }
// Tests that when server tries to send more large resources(large enough to
// be blocked by flow control window or congestion control window) than max
// open outgoing streams , server can open upto max number of outgoing
@@ -3261,7 +3261,11 @@ TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) {
kBodySize * kNumMaxStreams + 1024);
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
+ if (version_.UsesHttp3()) {
+ static_cast<QuicSpdySession*>(client_->client()->session())
+ ->SetMaxPushId(kMaxQuicStreamId);
+ }
// Set reordering to ensure that body arriving before PUSH_PROMISE is ok.
SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
@@ -3293,9 +3297,13 @@ TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) {
// Check server session to see if it has max number of outgoing streams opened
// though more resources need to be pushed.
- server_thread_->Pause();
- EXPECT_EQ(kNumMaxStreams, GetServerSession()->GetNumOpenOutgoingStreams());
- server_thread_->Resume();
+ if (!version_.HasIetfQuicFrames()) {
+ server_thread_->Pause();
+ EXPECT_EQ(kNumMaxStreams,
+ QuicSessionPeer::GetStreamIdManager(GetServerSession())
+ ->num_open_outgoing_streams());
+ server_thread_->Resume();
+ }
EXPECT_EQ(1u, client_->num_requests());
EXPECT_EQ(1u, client_->num_responses());
@@ -3334,7 +3342,7 @@ TEST_P(EndToEndTest, DISABLED_TestHugePostWithPacketLoss) {
// within a short time.
client_->epoll_server()->set_timeout_in_us(0);
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
SetPacketLossPercentage(1);
// To avoid storing the whole request body in memory, use a loop to repeatedly
// send body size of kSizeBytes until the whole request body size is reached.
@@ -3392,7 +3400,7 @@ TEST_P(EndToEndTest, DISABLED_TestHugeResponseWithPacketLoss) {
initialized_ = true;
ASSERT_TRUE(client_->client()->connected());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
SetPacketLossPercentage(1);
client_->SendRequest("/huge_response");
client_->WaitForResponse();
@@ -3402,7 +3410,7 @@ TEST_P(EndToEndTest, DISABLED_TestHugeResponseWithPacketLoss) {
// Regression test for b/111515567
TEST_P(EndToEndTest, AgreeOnStopWaiting) {
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
QuicConnection* client_connection = GetClientConnection();
server_thread_->Pause();
@@ -3420,7 +3428,7 @@ TEST_P(EndToEndTest, AgreeOnStopWaitingWithNoStopWaitingOption) {
options.push_back(kNSTP);
client_config_.SetConnectionOptionsToSend(options);
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
QuicConnection* client_connection = GetClientConnection();
server_thread_->Pause();
@@ -3451,6 +3459,13 @@ TEST_P(EndToEndTest, ReleaseHeadersStreamBufferWhenIdle) {
TEST_P(EndToEndTest, WayTooLongRequestHeaders) {
ASSERT_TRUE(Initialize());
+ if (version_.UsesTls() && !version_.UsesHttp3()) {
+ // In T050, it took relatively long time for HPACK to compress the header
+ // while server will detect blackhole on NST message.
+ // TODO(b/157248143): remove this when the HPACK compression issue is
+ // understood.
+ return;
+ }
SpdyHeaderBlock headers;
headers[":method"] = "GET";
headers[":path"] = "/foo";
@@ -3493,7 +3508,7 @@ class WindowUpdateObserver : public QuicConnectionDebugVisitor {
TEST_P(EndToEndTest, WindowUpdateInAck) {
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
WindowUpdateObserver observer;
QuicConnection* client_connection = GetClientConnection();
client_connection->set_debug_visitor(&observer);
@@ -3514,7 +3529,7 @@ TEST_P(EndToEndTest, WindowUpdateInAck) {
TEST_P(EndToEndTest, SendStatelessResetTokenInShlo) {
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
QuicConfig* config = client_->client()->session()->config();
EXPECT_TRUE(config->HasReceivedStatelessResetToken());
EXPECT_EQ(QuicUtils::GenerateStatelessResetToken(
@@ -3526,10 +3541,6 @@ TEST_P(EndToEndTest, SendStatelessResetTokenInShlo) {
// Regression test for b/116200989.
TEST_P(EndToEndTest,
SendStatelessResetIfServerConnectionClosedLocallyDuringHandshake) {
- if (!GetQuicReloadableFlag(quic_notify_handshaker_on_connection_close)) {
- ASSERT_TRUE(Initialize());
- return;
- }
connect_to_server_on_initialize_ = false;
ASSERT_TRUE(Initialize());
@@ -3674,8 +3685,7 @@ TEST_P(EndToEndTest, QUIC_TEST_DISABLED_IN_CHROME(PreSharedKeyMismatch)) {
// 2. Crypto handshake has not completed, Initialize() returns true. The call
// to WaitForCryptoHandshakeConfirmed() will wait for the handshake and
// return whether it is successful.
- ASSERT_FALSE(Initialize() &&
- client_->client()->WaitForCryptoHandshakeConfirmed());
+ ASSERT_FALSE(Initialize() && client_->client()->WaitForOneRttKeysAvailable());
EXPECT_THAT(client_->connection_error(), IsError(QUIC_HANDSHAKE_TIMEOUT));
}
@@ -3696,8 +3706,7 @@ TEST_P(EndToEndTest, QUIC_TEST_DISABLED_IN_CHROME(PreSharedKeyNoClient)) {
return;
}
- ASSERT_FALSE(Initialize() &&
- client_->client()->WaitForCryptoHandshakeConfirmed());
+ ASSERT_FALSE(Initialize() && client_->client()->WaitForOneRttKeysAvailable());
EXPECT_THAT(client_->connection_error(), IsError(QUIC_HANDSHAKE_TIMEOUT));
}
@@ -3718,8 +3727,7 @@ TEST_P(EndToEndTest, QUIC_TEST_DISABLED_IN_CHROME(PreSharedKeyNoServer)) {
return;
}
- ASSERT_FALSE(Initialize() &&
- client_->client()->WaitForCryptoHandshakeConfirmed());
+ ASSERT_FALSE(Initialize() && client_->client()->WaitForOneRttKeysAvailable());
EXPECT_THAT(client_->connection_error(), IsError(QUIC_HANDSHAKE_TIMEOUT));
}
@@ -3738,7 +3746,7 @@ TEST_P(EndToEndTest, RequestAndStreamRstInOnePacket) {
server_hostname_, "/test_url", std::move(response_headers), response_body,
QuicBackendResponse::INCOMPLETE_RESPONSE);
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
client_->WaitForDelayedAcks();
QuicSession* session = GetClientSession();
@@ -3760,7 +3768,7 @@ TEST_P(EndToEndTest, RequestAndStreamRstInOnePacket) {
TEST_P(EndToEndTest, ResetStreamOnTtlExpires) {
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForHandshakeConfirmed());
SetPacketLossPercentage(30);
QuicSpdyClientStream* stream = client_->GetOrCreateStream();
@@ -3781,7 +3789,7 @@ TEST_P(EndToEndTest, SendMessages) {
return;
}
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
QuicSession* client_session = GetClientSession();
QuicConnection* client_connection = client_session->connection();
@@ -3911,16 +3919,14 @@ TEST_P(EndToEndPacketReorderingTest, ReorderedConnectivityProbing) {
server_connection->GetStats().num_connectivity_probing_received);
server_thread_->Resume();
- EXPECT_EQ(
+ // Server definitely responded to the connectivity probing. Sometime it also
+ // sends a padded ping that is not a connectivity probing, which is recognized
+ // as connectivity probing because client's self address is ANY.
+ EXPECT_LE(
1u, GetClientConnection()->GetStats().num_connectivity_probing_received);
}
TEST_P(EndToEndPacketReorderingTest, Buffer0RttRequest) {
- if (version_.UsesTls()) {
- // TODO(b/152551499): Re-enable this test when TLS supports 0-RTT.
- Initialize();
- return;
- }
ASSERT_TRUE(Initialize());
// Finish one request to make sure handshake established.
client_->SendSynchronousRequest("/foo");
@@ -3933,7 +3939,7 @@ TEST_P(EndToEndPacketReorderingTest, Buffer0RttRequest) {
// Only send out a CHLO.
client_->client()->Initialize();
client_->client()->StartConnect();
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
ASSERT_TRUE(client_->client()->connected());
// Send a request before handshake finishes.
@@ -3947,14 +3953,10 @@ TEST_P(EndToEndPacketReorderingTest, Buffer0RttRequest) {
client_->WaitForResponse();
EXPECT_EQ(kBarResponseBody, client_->response_body());
QuicConnectionStats client_stats = GetClientConnection()->GetStats();
- if (GetQuicReloadableFlag(quic_advance_ack_timeout_update)) {
- // Client sends CHLO in packet 1 and retransmitted in packet 2. Because of
- // the delay, server processes packet 2 and later drops packet 1. ACK is
- // bundled with SHLO, such that 1 can be detected loss by time threshold.
- EXPECT_LE(0u, client_stats.packets_lost);
- } else {
- EXPECT_EQ(0u, client_stats.packets_lost);
- }
+ // Client sends CHLO in packet 1 and retransmitted in packet 2. Because of
+ // the delay, server processes packet 2 and later drops packet 1. ACK is
+ // bundled with SHLO, such that 1 can be detected loss by time threshold.
+ EXPECT_LE(0u, client_stats.packets_lost);
EXPECT_TRUE(client_->client()->EarlyDataAccepted());
}
@@ -4010,7 +4012,7 @@ TEST_P(EndToEndTest, SimpleStopSendingTest) {
server_hostname_, "/test_url", std::move(response_headers), response_body,
kStopSendingTestCode);
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
client_->WaitForDelayedAcks();
QuicSession* session = GetClientSession();
@@ -4188,7 +4190,7 @@ TEST_P(EndToEndTest, TooBigStreamIdClosesConnection) {
// Only runs for IETF QUIC.
return;
}
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
std::string body(kMaxOutgoingPacketSize, 'a');
SpdyHeaderBlock headers;
@@ -4216,17 +4218,15 @@ TEST_P(EndToEndTest, TooBigStreamIdClosesConnection) {
}
TEST_P(EndToEndTest, TestMaxPushId) {
- if (version_.UsesTls() ||
- !VersionHasIetfQuicFrames(version_.transport_version)) {
- // TODO(b/155316241): Enable this test for TLS.
- // Only runs for IETF QUIC.
+ if (!version_.HasIetfQuicFrames()) {
+ // MaxPushId is only implemented for IETF QUIC.
Initialize();
return;
}
- // Has to be before version test, see EndToEndTest::TearDown()
+ SetQuicFlag(FLAGS_quic_enable_http3_server_push, true);
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
static_cast<QuicSpdySession*>(client_->client()->session())
->SetMaxPushId(kMaxQuicStreamId);
@@ -4239,18 +4239,135 @@ TEST_P(EndToEndTest, TestMaxPushId) {
->CanCreatePushStreamWithId(kMaxQuicStreamId));
}
-TEST_P(EndToEndTest, DISABLED_CustomTransportParameters) {
- // TODO(b/155316241): Enable this test.
+TEST_P(EndToEndTest, CustomTransportParameters) {
+ if (!version_.UsesTls()) {
+ // Custom transport parameters are only supported with TLS.
+ ASSERT_TRUE(Initialize());
+ return;
+ }
constexpr auto kCustomParameter =
static_cast<TransportParameters::TransportParameterId>(0xff34);
client_config_.custom_transport_parameters_to_send()[kCustomParameter] =
"test";
+ NiceMock<MockQuicConnectionDebugVisitor> visitor;
+ connection_debug_visitor_ = &visitor;
+ EXPECT_CALL(visitor, OnTransportParametersSent(_))
+ .WillOnce(Invoke([kCustomParameter](
+ const TransportParameters& transport_parameters) {
+ ASSERT_NE(transport_parameters.custom_parameters.find(kCustomParameter),
+ transport_parameters.custom_parameters.end());
+ EXPECT_EQ(transport_parameters.custom_parameters.at(kCustomParameter),
+ "test");
+ }));
+ EXPECT_CALL(visitor, OnTransportParametersReceived(_)).Times(1);
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
- EXPECT_EQ(server_config_.received_custom_transport_parameters().at(
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
+
+ server_thread_->Pause();
+ QuicConfig server_config = *GetServerSession()->config();
+ if (GetQuicReloadableFlag(quic_save_user_agent_in_quic_session)) {
+ EXPECT_EQ(GetServerSession()->user_agent_id().value_or("MissingUserAgent"),
+ kTestUserAgentId);
+ } else {
+ EXPECT_FALSE(GetServerSession()->user_agent_id().has_value());
+ }
+ server_thread_->Resume();
+ ASSERT_NE(server_config.received_custom_transport_parameters().find(
kCustomParameter),
- "test");
+ server_config.received_custom_transport_parameters().end());
+ EXPECT_EQ(
+ server_config.received_custom_transport_parameters().at(kCustomParameter),
+ "test");
+}
+
+TEST_P(EndToEndTest, LegacyVersionEncapsulation) {
+ if (!version_.HasLongHeaderLengths()) {
+ // Decapsulating Legacy Version Encapsulation packets from these versions
+ // is not currently supported in QuicDispatcher.
+ ASSERT_TRUE(Initialize());
+ return;
+ }
+ SetQuicReloadableFlag(quic_dont_pad_chlo, true);
+ SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true);
+ client_config_.SetClientConnectionOptions(QuicTagVector{kQLVE});
+ ASSERT_TRUE(Initialize());
+ EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
+ EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
+ EXPECT_GT(GetClientConnection()
+ ->GetStats()
+ .sent_legacy_version_encapsulated_packets,
+ 0u);
+}
+
+TEST_P(EndToEndTest, LegacyVersionEncapsulationWithMultiPacketChlo) {
+ if (!version_.HasLongHeaderLengths()) {
+ // Decapsulating Legacy Version Encapsulation packets from these versions
+ // is not currently supported in QuicDispatcher.
+ ASSERT_TRUE(Initialize());
+ return;
+ }
+ if (!version_.UsesTls()) {
+ // This test uses custom transport parameters to increase the size of the
+ // CHLO, and those are only supported with TLS.
+ ASSERT_TRUE(Initialize());
+ return;
+ }
+ SetQuicReloadableFlag(quic_dont_pad_chlo, true);
+ SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true);
+ client_config_.SetClientConnectionOptions(QuicTagVector{kQLVE});
+ constexpr auto kCustomParameter =
+ static_cast<TransportParameters::TransportParameterId>(0xff34);
+ client_config_.custom_transport_parameters_to_send()[kCustomParameter] =
+ std::string(2000, '?');
+ ASSERT_TRUE(Initialize());
+ EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
+ EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
+ EXPECT_GT(GetClientConnection()
+ ->GetStats()
+ .sent_legacy_version_encapsulated_packets,
+ 0u);
+}
+
+TEST_P(EndToEndTest, LegacyVersionEncapsulationWithVersionNegotiation) {
+ if (!version_.HasLongHeaderLengths()) {
+ // Decapsulating Legacy Version Encapsulation packets from these versions
+ // is not currently supported in QuicDispatcher.
+ ASSERT_TRUE(Initialize());
+ return;
+ }
+ client_supported_versions_.insert(client_supported_versions_.begin(),
+ QuicVersionReservedForNegotiation());
+ SetQuicReloadableFlag(quic_dont_pad_chlo, true);
+ SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true);
+ client_config_.SetClientConnectionOptions(QuicTagVector{kQLVE});
+ ASSERT_TRUE(Initialize());
+ EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
+ EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
+ EXPECT_GT(GetClientConnection()
+ ->GetStats()
+ .sent_legacy_version_encapsulated_packets,
+ 0u);
+}
+
+TEST_P(EndToEndTest, LegacyVersionEncapsulationWithLoss) {
+ if (!version_.HasLongHeaderLengths()) {
+ // Decapsulating Legacy Version Encapsulation packets from these versions
+ // is not currently supported in QuicDispatcher.
+ ASSERT_TRUE(Initialize());
+ return;
+ }
+ SetPacketLossPercentage(30);
+ SetQuicReloadableFlag(quic_dont_pad_chlo, true);
+ SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true);
+ client_config_.SetClientConnectionOptions(QuicTagVector{kQLVE});
+ ASSERT_TRUE(Initialize());
+ EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
+ EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
+ EXPECT_GT(GetClientConnection()
+ ->GetStats()
+ .sent_legacy_version_encapsulated_packets,
+ 0u);
}
} // namespace
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h b/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h
index 17afe1bea19..285d3792d7a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h
@@ -42,6 +42,7 @@ const QuicByteCount kDefaultQpackMaxDynamicTableCapacity = 64 * 1024; // 64 KB
// SETTINGS_QPACK_BLOCKED_STREAMS.
const uint64_t kDefaultMaximumBlockedStreams = 100;
+const char kUserAgentHeaderName[] = "user-agent";
} // namespace quic
#endif // QUICHE_QUIC_CORE_HTTP_HTTP_CONSTANTS_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc
index a5996260d23..0836f9a0d56 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc
@@ -227,9 +227,6 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseMismatch) {
EXPECT_CALL(*connection_, SendControlFrame(_));
EXPECT_CALL(*connection_,
OnStreamReset(promise_id_, QUIC_PROMISE_VARY_MISMATCH));
- if (!session_.break_close_loop()) {
- EXPECT_CALL(session_, CloseStream(promise_id_));
- }
promised->HandleClientRequest(client_request_, &delegate);
}
@@ -305,9 +302,6 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseWaitCancels) {
session_.GetOrCreateStream(promise_id_);
// Cancel the promised stream.
- if (!session_.break_close_loop()) {
- EXPECT_CALL(session_, CloseStream(promise_id_));
- }
EXPECT_CALL(*connection_, SendControlFrame(_));
EXPECT_CALL(*connection_, OnStreamReset(promise_id_, QUIC_STREAM_CANCELLED));
promised->Cancel();
@@ -331,17 +325,10 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseDataClosed) {
promise_stream->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
headers);
- if (!session_.break_close_loop()) {
- EXPECT_CALL(session_, CloseStream(promise_id_));
- }
EXPECT_CALL(*connection_, SendControlFrame(_));
EXPECT_CALL(*connection_,
OnStreamReset(promise_id_, QUIC_STREAM_PEER_GOING_AWAY));
- if (session_.break_close_loop()) {
- session_.ResetStream(promise_id_, QUIC_STREAM_PEER_GOING_AWAY, 0);
- } else {
- session_.SendRstStream(promise_id_, QUIC_STREAM_PEER_GOING_AWAY, 0);
- }
+ session_.ResetStream(promise_id_, QUIC_STREAM_PEER_GOING_AWAY, 0);
// Now initiate rendezvous.
TestPushPromiseDelegate delegate(/*match=*/true);
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc
index d24e3ddaa88..27de70d3fa4 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc
@@ -131,8 +131,7 @@ bool QuicReceiveControlStream::OnSettingsFrameStart(
bool QuicReceiveControlStream::OnSettingsFrame(const SettingsFrame& frame) {
QUIC_DVLOG(1) << "Control Stream " << id()
<< " received settings frame: " << frame;
- spdy_session_->OnSettingsFrame(frame);
- return true;
+ return spdy_session_->OnSettingsFrame(frame);
}
bool QuicReceiveControlStream::OnDataFrameStart(QuicByteCount /*header_length*/,
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc
index 64c306a4431..59574a146b9 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc
@@ -18,18 +18,12 @@
namespace quic {
-QuicSendControlStream::QuicSendControlStream(
- QuicStreamId id,
- QuicSpdySession* spdy_session,
- uint64_t qpack_maximum_dynamic_table_capacity,
- uint64_t qpack_maximum_blocked_streams,
- uint64_t max_inbound_header_list_size)
+QuicSendControlStream::QuicSendControlStream(QuicStreamId id,
+ QuicSpdySession* spdy_session,
+ const SettingsFrame& settings)
: QuicStream(id, spdy_session, /*is_static = */ true, WRITE_UNIDIRECTIONAL),
settings_sent_(false),
- qpack_maximum_dynamic_table_capacity_(
- qpack_maximum_dynamic_table_capacity),
- qpack_maximum_blocked_streams_(qpack_maximum_blocked_streams),
- max_inbound_header_list_size_(max_inbound_header_list_size),
+ settings_(settings),
spdy_session_(spdy_session) {}
void QuicSendControlStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
@@ -56,13 +50,7 @@ void QuicSendControlStream::MaybeSendSettingsFrame() {
WriteOrBufferData(quiche::QuicheStringPiece(writer.data(), writer.length()),
false, nullptr);
- SettingsFrame settings;
- settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] =
- qpack_maximum_dynamic_table_capacity_;
- settings.values[SETTINGS_QPACK_BLOCKED_STREAMS] =
- qpack_maximum_blocked_streams_;
- settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] =
- max_inbound_header_list_size_;
+ SettingsFrame settings = settings_;
// https://tools.ietf.org/html/draft-ietf-quic-http-25#section-7.2.4.1
// specifies that setting identifiers of 0x1f * N + 0x21 are reserved and
// greasing should be attempted.
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h
index 03bd1f747aa..c14254f4cb7 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h
@@ -23,9 +23,7 @@ class QUIC_EXPORT_PRIVATE QuicSendControlStream : public QuicStream {
// only be accessed through the session.
QuicSendControlStream(QuicStreamId id,
QuicSpdySession* session,
- uint64_t qpack_maximum_dynamic_table_capacity,
- uint64_t qpack_maximum_blocked_streams,
- uint64_t max_inbound_header_list_size);
+ const SettingsFrame& settings);
QuicSendControlStream(const QuicSendControlStream&) = delete;
QuicSendControlStream& operator=(const QuicSendControlStream&) = delete;
~QuicSendControlStream() override = default;
@@ -59,12 +57,8 @@ class QUIC_EXPORT_PRIVATE QuicSendControlStream : public QuicStream {
// Track if a settings frame is already sent.
bool settings_sent_;
- // SETTINGS_QPACK_MAX_TABLE_CAPACITY value to send.
- const uint64_t qpack_maximum_dynamic_table_capacity_;
- // SETTINGS_QPACK_BLOCKED_STREAMS value to send.
- const uint64_t qpack_maximum_blocked_streams_;
- // SETTINGS_MAX_HEADER_LIST_SIZE value to send.
- const uint64_t max_inbound_header_list_size_;
+ // SETTINGS values to send.
+ const SettingsFrame settings_;
QuicSpdySession* const spdy_session_;
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc
index 27db719fccd..ef367d98cb5 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc
@@ -39,6 +39,9 @@ void QuicServerSessionBase::Initialize() {
crypto_stream_ =
CreateQuicCryptoServerStream(crypto_config_, compressed_certs_cache_);
QuicSpdySession::Initialize();
+ if (GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls)) {
+ SendSettingsToCryptoStream();
+ }
}
void QuicServerSessionBase::OnConfigNegotiated() {
@@ -260,4 +263,19 @@ int32_t QuicServerSessionBase::BandwidthToCachedParameterBytesPerSecond(
bandwidth.ToBytesPerSecond(), std::numeric_limits<uint32_t>::max()));
}
+void QuicServerSessionBase::SendSettingsToCryptoStream() {
+ if (!version().UsesTls()) {
+ return;
+ }
+ std::unique_ptr<char[]> buffer;
+ QuicByteCount buffer_size =
+ HttpEncoder::SerializeSettingsFrame(settings(), &buffer);
+
+ std::unique_ptr<ApplicationState> serialized_settings =
+ std::make_unique<ApplicationState>(buffer.get(),
+ buffer.get() + buffer_size);
+ GetMutableCryptoStream()->SetServerApplicationStateForResumption(
+ std::move(serialized_settings));
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.h
index bf7a5bbb693..b4a467fedff 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.h
@@ -99,6 +99,11 @@ class QUIC_EXPORT_PRIVATE QuicServerSessionBase : public QuicSpdySession {
friend class test::QuicServerSessionBasePeer;
friend class test::QuicSimpleServerSessionPeer;
+ // Informs the QuicCryptoStream of the SETTINGS that will be used on this
+ // connection, so that the server crypto stream knows whether to accept 0-RTT
+ // data.
+ void SendSettingsToCryptoStream();
+
const QuicCryptoServerConfig* crypto_config_;
// The cache which contains most recently compressed certs.
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc
index c482856b61b..6af67a656f4 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc
@@ -157,6 +157,9 @@ class QuicServerSessionBaseTest : public QuicTestWithParam<ParsedQuicVersion> {
QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(
session_->config(), kMinimumFlowControlSendWindow);
session_->OnConfigNegotiated();
+ if (connection_->version().SupportsAntiAmplificationLimit()) {
+ QuicConnectionPeer::SetAddressValidated(connection_);
+ }
}
QuicStreamId GetNthClientInitiatedBidirectionalId(int n) {
@@ -349,6 +352,7 @@ TEST_P(QuicServerSessionBaseTest, MaxOpenStreams) {
// more than the negotiated stream limit to deal with rare cases where a
// client FIN/RST is lost.
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_->OnConfigNegotiated();
if (!VersionHasIetfQuicFrames(transport_version())) {
// The slightly increased stream limit is set during config negotiation. It
@@ -401,6 +405,7 @@ TEST_P(QuicServerSessionBaseTest, MaxAvailableBidirectionalStreams) {
// streams available. The server accepts slightly more than the negotiated
// stream limit to deal with rare cases where a client FIN/RST is lost.
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_->OnConfigNegotiated();
const size_t kAvailableStreamLimit =
session_->MaxAvailableBidirectionalStreams();
@@ -506,6 +511,7 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) {
QuicTagVector copt;
copt.push_back(kBWRE);
QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt);
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_->OnConfigNegotiated();
EXPECT_TRUE(
QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get()));
@@ -696,6 +702,7 @@ TEST_P(QuicServerSessionBaseTest, BandwidthMaxEnablesResumption) {
QuicTagVector copt;
copt.push_back(kBWMX);
QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt);
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_->OnConfigNegotiated();
EXPECT_TRUE(
QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get()));
@@ -704,6 +711,7 @@ TEST_P(QuicServerSessionBaseTest, BandwidthMaxEnablesResumption) {
TEST_P(QuicServerSessionBaseTest, NoBandwidthResumptionByDefault) {
EXPECT_FALSE(
QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get()));
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_->OnConfigNegotiated();
EXPECT_FALSE(
QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get()));
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc
index 6127e1b682e..066adb9f859 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc
@@ -39,6 +39,13 @@ QuicSpdyClientSession::~QuicSpdyClientSession() = default;
void QuicSpdyClientSession::Initialize() {
crypto_stream_ = CreateQuicCryptoStream();
+ if (config()->HasClientRequestedIndependentOption(kQLVE,
+ Perspective::IS_CLIENT)) {
+ connection()->EnableLegacyVersionEncapsulation(server_id_.host());
+ // Legacy Version Encapsulation needs CHLO padding to be disabled.
+ // TODO(dschinazi) remove this line once we deprecate quic_dont_pad_chlo.
+ crypto_config_->set_disable_chlo_padding(true);
+ }
QuicSpdyClientSessionBase::Initialize();
}
@@ -152,7 +159,7 @@ bool QuicSpdyClientSession::ShouldCreateIncomingStream(QuicStreamId id) {
}
if (VersionHasIetfQuicFrames(transport_version()) &&
- QuicUtils::IsBidirectionalStreamId(id)) {
+ QuicUtils::IsBidirectionalStreamId(id, version())) {
connection()->CloseConnection(
QUIC_HTTP_SERVER_INITIATED_BIDIRECTIONAL_STREAM,
"Server created bidirectional stream.",
@@ -186,7 +193,7 @@ QuicSpdyClientSession::CreateQuicCryptoStream() {
return std::make_unique<QuicCryptoClientStream>(
server_id_, this,
crypto_config_->proof_verifier()->CreateDefaultContext(), crypto_config_,
- this, /*has_application_state = */ true);
+ this, /*has_application_state = */ version().UsesHttp3());
}
bool QuicSpdyClientSession::IsAuthorized(const std::string& /*authority*/) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc
index 63de57c31bc..b433c56f687 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc
@@ -204,26 +204,20 @@ void QuicSpdyClientSessionBase::ResetPromised(
QuicStreamId id,
QuicRstStreamErrorCode error_code) {
DCHECK(QuicUtils::IsServerInitiatedStreamId(transport_version(), id));
- if (break_close_loop()) {
- ResetStream(id, error_code, 0);
- } else {
- SendRstStream(id, error_code, 0);
- }
+ ResetStream(id, error_code, 0);
if (!IsOpenStream(id) && !IsClosedStream(id)) {
MaybeIncreaseLargestPeerStreamId(id);
}
}
-void QuicSpdyClientSessionBase::CloseStreamInner(QuicStreamId stream_id,
- bool rst_sent) {
- QuicSpdySession::CloseStreamInner(stream_id, rst_sent);
+void QuicSpdyClientSessionBase::CloseStream(QuicStreamId stream_id) {
+ QuicSpdySession::CloseStream(stream_id);
if (!VersionUsesHttp3(transport_version())) {
headers_stream()->MaybeReleaseSequencerBuffer();
}
}
void QuicSpdyClientSessionBase::OnStreamClosed(QuicStreamId stream_id) {
- DCHECK(break_close_loop());
QuicSpdySession::OnStreamClosed(stream_id);
if (!VersionUsesHttp3(transport_version())) {
headers_stream()->MaybeReleaseSequencerBuffer();
@@ -234,15 +228,55 @@ bool QuicSpdyClientSessionBase::ShouldReleaseHeadersStreamSequencerBuffer() {
return !HasActiveRequestStreams() && promised_by_id_.empty();
}
-void QuicSpdyClientSessionBase::OnSettingsFrame(const SettingsFrame& frame) {
- QuicSpdySession::OnSettingsFrame(frame);
+bool QuicSpdyClientSessionBase::ShouldKeepConnectionAlive() const {
+ return QuicSpdySession::ShouldKeepConnectionAlive() ||
+ num_outgoing_draining_streams() > 0;
+}
+
+bool QuicSpdyClientSessionBase::OnSettingsFrame(const SettingsFrame& frame) {
+ if (!was_zero_rtt_rejected()) {
+ if (max_outbound_header_list_size() != std::numeric_limits<size_t>::max() &&
+ frame.values.find(SETTINGS_MAX_HEADER_LIST_SIZE) ==
+ frame.values.end()) {
+ CloseConnectionWithDetails(
+ QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH,
+ "Server accepted 0-RTT but omitted non-default "
+ "SETTINGS_MAX_HEADER_LIST_SIZE");
+ return false;
+ }
+
+ if (qpack_encoder()->maximum_blocked_streams() != 0 &&
+ frame.values.find(SETTINGS_QPACK_BLOCKED_STREAMS) ==
+ frame.values.end()) {
+ CloseConnectionWithDetails(
+ QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH,
+ "Server accepted 0-RTT but omitted non-default "
+ "SETTINGS_QPACK_BLOCKED_STREAMS");
+ return false;
+ }
+
+ if (qpack_encoder()->MaximumDynamicTableCapacity() != 0 &&
+ frame.values.find(SETTINGS_QPACK_MAX_TABLE_CAPACITY) ==
+ frame.values.end()) {
+ CloseConnectionWithDetails(
+ QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH,
+ "Server accepted 0-RTT but omitted non-default "
+ "SETTINGS_QPACK_MAX_TABLE_CAPACITY");
+ return false;
+ }
+ }
+
+ if (!QuicSpdySession::OnSettingsFrame(frame)) {
+ return false;
+ }
std::unique_ptr<char[]> buffer;
QuicByteCount frame_length =
HttpEncoder::SerializeSettingsFrame(frame, &buffer);
auto serialized_data = std::make_unique<ApplicationState>(
buffer.get(), buffer.get() + frame_length);
- static_cast<QuicCryptoClientStreamBase*>(GetMutableCryptoStream())
- ->OnApplicationState(std::move(serialized_data));
+ GetMutableCryptoStream()->SetServerApplicationStateForResumption(
+ std::move(serialized_data));
+ return true;
}
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h
index a109d185a46..31924793f6b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h
@@ -102,7 +102,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdyClientSessionBase
void ResetPromised(QuicStreamId id, QuicRstStreamErrorCode error_code);
// Release headers stream's sequencer buffer if it's empty.
- void CloseStreamInner(QuicStreamId stream_id, bool rst_sent) override;
+ void CloseStream(QuicStreamId stream_id) override;
// Release headers stream's sequencer buffer if it's empty.
void OnStreamClosed(QuicStreamId stream_id) override;
@@ -110,6 +110,9 @@ class QUIC_EXPORT_PRIVATE QuicSpdyClientSessionBase
// Returns true if there are no active requests and no promised streams.
bool ShouldReleaseHeadersStreamSequencerBuffer() override;
+ // Override to wait for all received responses to be consumed by application.
+ bool ShouldKeepConnectionAlive() const override;
+
size_t get_max_promises() const {
return max_open_incoming_unidirectional_streams() *
kMaxPromisedStreamsMultiplier;
@@ -120,7 +123,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdyClientSessionBase
}
// Override to serialize the settings and pass it down to the handshaker.
- void OnSettingsFrame(const SettingsFrame& frame) override;
+ bool OnSettingsFrame(const SettingsFrame& frame) override;
private:
// For QuicSpdyClientStream to detect that a response corresponds to a
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc
index 7d4ae810115..3464a7eda90 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc
@@ -16,10 +16,12 @@
#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h"
#include "net/third_party/quiche/src/quic/core/http/spdy_server_push_utils.h"
#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
@@ -38,12 +40,13 @@
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
using spdy::SpdyHeaderBlock;
-using testing::_;
-using testing::AnyNumber;
-using testing::AtLeast;
-using testing::AtMost;
-using testing::Invoke;
-using testing::Truly;
+using ::testing::_;
+using ::testing::AnyNumber;
+using ::testing::AtLeast;
+using ::testing::AtMost;
+using ::testing::Invoke;
+using ::testing::StrictMock;
+using ::testing::Truly;
namespace quic {
namespace test {
@@ -93,8 +96,12 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> {
QuicUtils::GetInvalidStreamId(GetParam().transport_version)) {
auto client_cache = std::make_unique<test::SimpleSessionCache>();
client_session_cache_ = client_cache.get();
- crypto_config_ = std::make_unique<QuicCryptoClientConfig>(
+ SetQuicReloadableFlag(quic_enable_tls_resumption, true);
+ SetQuicReloadableFlag(quic_enable_zero_rtt_for_tls, true);
+ SetQuicReloadableFlag(quic_fix_gquic_stream_type, true);
+ client_crypto_config_ = std::make_unique<QuicCryptoClientConfig>(
crypto_test_utils::ProofVerifierForTesting(), std::move(client_cache));
+ server_crypto_config_ = crypto_test_utils::CryptoServerConfigForTesting();
Initialize();
// Advance the time, because timers do not like uninitialized times.
connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
@@ -107,14 +114,16 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> {
void Initialize() {
session_.reset();
- connection_ = new PacketSavingConnection(&helper_, &alarm_factory_,
- Perspective::IS_CLIENT,
- SupportedVersions(GetParam()));
+ connection_ = new ::testing::NiceMock<PacketSavingConnection>(
+ &helper_, &alarm_factory_, Perspective::IS_CLIENT,
+ SupportedVersions(GetParam()));
session_ = std::make_unique<TestQuicSpdyClientSession>(
DefaultQuicConfig(), SupportedVersions(GetParam()), connection_,
- QuicServerId(kServerHostname, kPort, false), crypto_config_.get(),
- &push_promise_index_);
+ QuicServerId(kServerHostname, kPort, false),
+ client_crypto_config_.get(), &push_promise_index_);
session_->Initialize();
+ crypto_stream_ = static_cast<QuicCryptoClientStream*>(
+ session_->GetMutableCryptoStream());
push_promise_[":path"] = "/bar";
push_promise_[":authority"] = "www.google.com";
push_promise_[":method"] = "GET";
@@ -157,13 +166,11 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> {
void CompleteCryptoHandshake(uint32_t server_max_incoming_streams) {
if (VersionHasIetfQuicFrames(connection_->transport_version())) {
EXPECT_CALL(*connection_, SendControlFrame(_))
- .Times(testing::AnyNumber())
+ .Times(::testing::AnyNumber())
.WillRepeatedly(Invoke(
this, &QuicSpdyClientSessionTest::ClearMaxStreamsControlFrame));
}
session_->CryptoConnect();
- QuicCryptoClientStream* stream = static_cast<QuicCryptoClientStream*>(
- session_->GetMutableCryptoStream());
QuicConfig config = DefaultQuicConfig();
if (VersionHasIetfQuicFrames(connection_->transport_version())) {
config.SetMaxUnidirectionalStreamsToSend(server_max_incoming_streams);
@@ -171,32 +178,45 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> {
} else {
config.SetMaxBidirectionalStreamsToSend(server_max_incoming_streams);
}
- SetQuicReloadableFlag(quic_enable_tls_resumption, true);
- SetQuicReloadableFlag(quic_enable_zero_rtt_for_tls, true);
- std::unique_ptr<QuicCryptoServerConfig> crypto_config =
- crypto_test_utils::CryptoServerConfigForTesting();
crypto_test_utils::HandshakeWithFakeServer(
- &config, crypto_config.get(), &helper_, &alarm_factory_, connection_,
- stream, AlpnForVersion(connection_->version()));
+ &config, server_crypto_config_.get(), &helper_, &alarm_factory_,
+ connection_, crypto_stream_, AlpnForVersion(connection_->version()));
}
void CreateConnection() {
- connection_ = new PacketSavingConnection(&helper_, &alarm_factory_,
- Perspective::IS_CLIENT,
- SupportedVersions(GetParam()));
+ connection_ = new ::testing::NiceMock<PacketSavingConnection>(
+ &helper_, &alarm_factory_, Perspective::IS_CLIENT,
+ SupportedVersions(GetParam()));
// Advance the time, because timers do not like uninitialized times.
connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
session_ = std::make_unique<TestQuicSpdyClientSession>(
DefaultQuicConfig(), SupportedVersions(GetParam()), connection_,
- QuicServerId(kServerHostname, kPort, false), crypto_config_.get(),
- &push_promise_index_);
+ QuicServerId(kServerHostname, kPort, false),
+ client_crypto_config_.get(), &push_promise_index_);
session_->Initialize();
+ crypto_stream_ = static_cast<QuicCryptoClientStream*>(
+ session_->GetMutableCryptoStream());
}
- std::unique_ptr<QuicCryptoClientConfig> crypto_config_;
+ void CompleteFirstConnection() {
+ CompleteCryptoHandshake();
+ EXPECT_FALSE(session_->GetCryptoStream()->IsResumption());
+ if (session_->version().UsesHttp3()) {
+ SettingsFrame settings;
+ settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2;
+ settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
+ settings.values[256] = 4; // unknown setting
+ session_->OnSettingsFrame(settings);
+ }
+ }
+
+ // Owned by |session_|.
+ QuicCryptoClientStream* crypto_stream_;
+ std::unique_ptr<QuicCryptoServerConfig> server_crypto_config_;
+ std::unique_ptr<QuicCryptoClientConfig> client_crypto_config_;
MockQuicConnectionHelper helper_;
MockAlarmFactory alarm_factory_;
- PacketSavingConnection* connection_;
+ ::testing::NiceMock<PacketSavingConnection>* connection_;
std::unique_ptr<TestQuicSpdyClientSession> session_;
QuicClientPushPromiseIndex push_promise_index_;
SpdyHeaderBlock push_promise_;
@@ -219,8 +239,6 @@ TEST_P(QuicSpdyClientSessionTest, NoEncryptionAfterInitialEncryption) {
if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
// This test relies on resumption and is QUIC crypto specific, so it is
// disabled for TLS.
- // TODO(nharper): Add support for resumption to the TLS handshake, and fix
- // this test to not rely on QUIC crypto.
return;
}
// Complete a handshake in order to prime the crypto config for 0-RTT.
@@ -229,7 +247,6 @@ TEST_P(QuicSpdyClientSessionTest, NoEncryptionAfterInitialEncryption) {
// Now create a second session using the same crypto config.
Initialize();
- EXPECT_CALL(*connection_, OnCanWrite());
// Starting the handshake should move immediately to encryption
// established and will allow streams to be created.
session_->CryptoConnect();
@@ -257,7 +274,7 @@ TEST_P(QuicSpdyClientSessionTest, NoEncryptionAfterInitialEncryption) {
char data[] = "hello world";
EXPECT_QUIC_BUG(
session_->WritevData(stream->id(), QUICHE_ARRAYSIZE(data), 0, NO_FIN,
- NOT_RETRANSMISSION, QuicheNullOpt),
+ NOT_RETRANSMISSION, QUICHE_NULLOPT),
"Client: Try to send data of stream");
}
@@ -343,11 +360,7 @@ TEST_P(QuicSpdyClientSessionTest, ResetAndTrailers) {
.Times(AtLeast(1))
.WillRepeatedly(Invoke(&ClearControlFrame));
EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(1);
- if (session_->break_close_loop()) {
- session_->ResetStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0);
- } else {
- session_->SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0);
- }
+ session_->ResetStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0);
// A new stream cannot be created as the reset stream still counts as an open
// outgoing stream until closed by the server.
@@ -399,11 +412,7 @@ TEST_P(QuicSpdyClientSessionTest, ReceivedMalformedTrailersAfterSendingRst) {
.Times(AtLeast(1))
.WillRepeatedly(Invoke(&ClearControlFrame));
EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(1);
- if (session_->break_close_loop()) {
- session_->ResetStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0);
- } else {
- session_->SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0);
- }
+ session_->ResetStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0);
// The stream receives trailers with final byte offset, but the header value
// is non-numeric and should be treated as malformed.
@@ -853,12 +862,7 @@ TEST_P(QuicSpdyClientSessionTest, ResetPromised) {
EXPECT_CALL(*connection_, SendControlFrame(_));
EXPECT_CALL(*connection_,
OnStreamReset(promised_stream_id_, QUIC_STREAM_PEER_GOING_AWAY));
- if (session_->break_close_loop()) {
- session_->ResetStream(promised_stream_id_, QUIC_STREAM_PEER_GOING_AWAY, 0);
- } else {
- session_->SendRstStream(promised_stream_id_, QUIC_STREAM_PEER_GOING_AWAY,
- 0);
- }
+ session_->ResetStream(promised_stream_id_, QUIC_STREAM_PEER_GOING_AWAY, 0);
QuicClientPromisedInfo* promised =
session_->GetPromisedById(promised_stream_id_);
EXPECT_NE(promised, nullptr);
@@ -983,44 +987,50 @@ TEST_P(QuicSpdyClientSessionTest, OnSettingsFrame) {
}
TEST_P(QuicSpdyClientSessionTest, IetfZeroRttSetup) {
- // This feature is HTTP/3 only
- if (!VersionUsesHttp3(session_->transport_version())) {
+ // This feature is TLS-only.
+ if (session_->version().UsesQuicCrypto()) {
return;
}
- CompleteCryptoHandshake();
- EXPECT_FALSE(session_->GetCryptoStream()->IsResumption());
- SettingsFrame settings;
- settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2;
- settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
- settings.values[256] = 4; // unknown setting
- session_->OnSettingsFrame(settings);
+
+ CompleteFirstConnection();
CreateConnection();
// Session configs should be in initial state.
- EXPECT_EQ(0u, session_->flow_controller()->send_window_offset());
- EXPECT_EQ(std::numeric_limits<size_t>::max(),
- session_->max_outbound_header_list_size());
+ if (session_->version().UsesHttp3()) {
+ EXPECT_EQ(0u, session_->flow_controller()->send_window_offset());
+ EXPECT_EQ(std::numeric_limits<size_t>::max(),
+ session_->max_outbound_header_list_size());
+ } else {
+ EXPECT_EQ(kMinimumFlowControlSendWindow,
+ session_->flow_controller()->send_window_offset());
+ }
session_->CryptoConnect();
+ EXPECT_TRUE(session_->IsEncryptionEstablished());
+ EXPECT_EQ(ENCRYPTION_ZERO_RTT, session_->connection()->encryption_level());
// The client session should have a basic setup ready before the handshake
// succeeds.
EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
session_->flow_controller()->send_window_offset());
- auto* id_manager = QuicSessionPeer::v99_streamid_manager(session_.get());
- EXPECT_EQ(kDefaultMaxStreamsPerConnection,
- id_manager->max_outgoing_bidirectional_streams());
- EXPECT_EQ(
- kDefaultMaxStreamsPerConnection + kHttp3StaticUnidirectionalStreamCount,
- id_manager->max_outgoing_unidirectional_streams());
- auto* control_stream =
- QuicSpdySessionPeer::GetSendControlStream(session_.get());
- EXPECT_EQ(kInitialStreamFlowControlWindowForTest,
- control_stream->flow_controller()->send_window_offset());
- EXPECT_EQ(5u, session_->max_outbound_header_list_size());
+ if (session_->version().UsesHttp3()) {
+ auto* id_manager = QuicSessionPeer::v99_streamid_manager(session_.get());
+ EXPECT_EQ(kDefaultMaxStreamsPerConnection,
+ id_manager->max_outgoing_bidirectional_streams());
+ EXPECT_EQ(
+ kDefaultMaxStreamsPerConnection + kHttp3StaticUnidirectionalStreamCount,
+ id_manager->max_outgoing_unidirectional_streams());
+ auto* control_stream =
+ QuicSpdySessionPeer::GetSendControlStream(session_.get());
+ EXPECT_EQ(kInitialStreamFlowControlWindowForTest,
+ control_stream->flow_controller()->send_window_offset());
+ EXPECT_EQ(5u, session_->max_outbound_header_list_size());
+ } else {
+ auto* id_manager = QuicSessionPeer::GetStreamIdManager(session_.get());
+ EXPECT_EQ(kDefaultMaxStreamsPerConnection,
+ id_manager->max_open_outgoing_streams());
+ }
// Complete the handshake with a different config.
- QuicCryptoClientStream* stream =
- static_cast<QuicCryptoClientStream*>(session_->GetMutableCryptoStream());
QuicConfig config = DefaultQuicConfig();
config.SetInitialMaxStreamDataBytesUnidirectionalToSend(
kInitialStreamFlowControlWindowForTest + 1);
@@ -1028,23 +1038,415 @@ TEST_P(QuicSpdyClientSessionTest, IetfZeroRttSetup) {
kInitialSessionFlowControlWindowForTest + 1);
config.SetMaxBidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection + 1);
config.SetMaxUnidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection + 1);
- SetQuicReloadableFlag(quic_enable_tls_resumption, true);
- std::unique_ptr<QuicCryptoServerConfig> crypto_config =
- crypto_test_utils::CryptoServerConfigForTesting();
crypto_test_utils::HandshakeWithFakeServer(
- &config, crypto_config.get(), &helper_, &alarm_factory_, connection_,
- stream, AlpnForVersion(connection_->version()));
+ &config, server_crypto_config_.get(), &helper_, &alarm_factory_,
+ connection_, crypto_stream_, AlpnForVersion(connection_->version()));
EXPECT_TRUE(session_->GetCryptoStream()->IsResumption());
EXPECT_EQ(kInitialSessionFlowControlWindowForTest + 1,
session_->flow_controller()->send_window_offset());
- EXPECT_EQ(kDefaultMaxStreamsPerConnection + 1,
- id_manager->max_outgoing_bidirectional_streams());
- EXPECT_EQ(kDefaultMaxStreamsPerConnection +
- kHttp3StaticUnidirectionalStreamCount + 1,
- id_manager->max_outgoing_unidirectional_streams());
- EXPECT_EQ(kInitialStreamFlowControlWindowForTest + 1,
- control_stream->flow_controller()->send_window_offset());
+ if (session_->version().UsesHttp3()) {
+ auto* id_manager = QuicSessionPeer::v99_streamid_manager(session_.get());
+ auto* control_stream =
+ QuicSpdySessionPeer::GetSendControlStream(session_.get());
+ EXPECT_EQ(kDefaultMaxStreamsPerConnection + 1,
+ id_manager->max_outgoing_bidirectional_streams());
+ EXPECT_EQ(kDefaultMaxStreamsPerConnection +
+ kHttp3StaticUnidirectionalStreamCount + 1,
+ id_manager->max_outgoing_unidirectional_streams());
+ EXPECT_EQ(kInitialStreamFlowControlWindowForTest + 1,
+ control_stream->flow_controller()->send_window_offset());
+ } else {
+ auto* id_manager = QuicSessionPeer::GetStreamIdManager(session_.get());
+ EXPECT_EQ(kDefaultMaxStreamsPerConnection + 1,
+ id_manager->max_open_outgoing_streams());
+ }
+
+ EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
+ // Let the session receive a new SETTINGS frame to complete the second
+ // connection.
+ if (session_->version().UsesHttp3()) {
+ SettingsFrame settings;
+ settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2;
+ settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
+ settings.values[256] = 4; // unknown setting
+ session_->OnSettingsFrame(settings);
+ }
+}
+
+// Regression test for b/159168475
+TEST_P(QuicSpdyClientSessionTest, RetransmitDataOnZeroRttReject) {
+ SetQuicReloadableFlag(quic_do_not_retransmit_immediately_on_zero_rtt_reject,
+ true);
+ // This feature is TLS-only.
+ if (session_->version().UsesQuicCrypto()) {
+ return;
+ }
+
+ CompleteFirstConnection();
+
+ // Create a second connection, but disable 0-RTT on the server.
+ CreateConnection();
+ ON_CALL(*connection_, OnCanWrite())
+ .WillByDefault(
+ testing::Invoke(connection_, &MockQuicConnection::ReallyOnCanWrite));
+ EXPECT_CALL(*connection_, OnCanWrite()).Times(0);
+
+ QuicConfig config = DefaultQuicConfig();
+ config.SetMaxUnidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection);
+ config.SetMaxBidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection);
+ SSL_CTX_set_early_data_enabled(server_crypto_config_->ssl_ctx(), false);
+
+ // Packets will be written: CHLO, HTTP/3 SETTINGS (H/3 only), and request
+ // data.
+ EXPECT_CALL(*connection_,
+ OnPacketSent(ENCRYPTION_INITIAL, NOT_RETRANSMISSION));
+ EXPECT_CALL(*connection_,
+ OnPacketSent(ENCRYPTION_ZERO_RTT, NOT_RETRANSMISSION))
+ .Times(session_->version().UsesHttp3() ? 2 : 1);
+ session_->CryptoConnect();
+ EXPECT_TRUE(session_->IsEncryptionEstablished());
+ EXPECT_EQ(ENCRYPTION_ZERO_RTT, session_->connection()->encryption_level());
+ QuicSpdyClientStream* stream = session_->CreateOutgoingBidirectionalStream();
+ ASSERT_TRUE(stream);
+ stream->WriteOrBufferData("hello", true, nullptr);
+
+ // When handshake is done, the client sends 2 packet: HANDSHAKE FINISHED, and
+ // coalesced retransmission of HTTP/3 SETTINGS and request data.
+ EXPECT_CALL(*connection_,
+ OnPacketSent(ENCRYPTION_HANDSHAKE, NOT_RETRANSMISSION));
+ // TODO(b/158027651): change transmission type to ALL_ZERO_RTT_RETRANSMISSION.
+ EXPECT_CALL(*connection_,
+ OnPacketSent(ENCRYPTION_FORWARD_SECURE, LOSS_RETRANSMISSION));
+ crypto_test_utils::HandshakeWithFakeServer(
+ &config, server_crypto_config_.get(), &helper_, &alarm_factory_,
+ connection_, crypto_stream_, AlpnForVersion(connection_->version()));
+ EXPECT_TRUE(session_->GetCryptoStream()->IsResumption());
+}
+
+// When IETF QUIC 0-RTT is rejected, a server-sent fresh transport params is
+// available. If the new transport params reduces stream/flow control limit to
+// lower than what the client has already used, connection will be closed.
+TEST_P(QuicSpdyClientSessionTest, ZeroRttRejectReducesStreamLimitTooMuch) {
+ // This feature is TLS-only.
+ if (session_->version().UsesQuicCrypto()) {
+ return;
+ }
+
+ CompleteFirstConnection();
+
+ // Create a second connection, but disable 0-RTT on the server.
+ CreateConnection();
+ QuicConfig config = DefaultQuicConfig();
+ // Server doesn't allow any bidirectional streams.
+ config.SetMaxBidirectionalStreamsToSend(0);
+ SSL_CTX_set_early_data_enabled(server_crypto_config_->ssl_ctx(), false);
+ session_->CryptoConnect();
+ EXPECT_TRUE(session_->IsEncryptionEstablished());
+ QuicSpdyClientStream* stream = session_->CreateOutgoingBidirectionalStream();
+ ASSERT_TRUE(stream);
+
+ if (session_->version().UsesHttp3()) {
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(
+ QUIC_ZERO_RTT_UNRETRANSMITTABLE,
+ "Server rejected 0-RTT, aborting because new bidirectional initial "
+ "stream limit 0 is less than current open streams: 1",
+ _))
+ .WillOnce(testing::Invoke(connection_,
+ &MockQuicConnection::ReallyCloseConnection));
+ } else {
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(QUIC_INTERNAL_ERROR,
+ "Server rejected 0-RTT, aborting because new stream "
+ "limit 0 is less than current open streams: 1",
+ _))
+ .WillOnce(testing::Invoke(connection_,
+ &MockQuicConnection::ReallyCloseConnection));
+ }
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _));
+
+ crypto_test_utils::HandshakeWithFakeServer(
+ &config, server_crypto_config_.get(), &helper_, &alarm_factory_,
+ connection_, crypto_stream_, AlpnForVersion(connection_->version()));
+}
+
+TEST_P(QuicSpdyClientSessionTest,
+ ZeroRttRejectReducesStreamFlowControlTooMuch) {
+ // This feature is TLS-only.
+ if (session_->version().UsesQuicCrypto()) {
+ return;
+ }
+
+ CompleteFirstConnection();
+
+ // Create a second connection, but disable 0-RTT on the server.
+ CreateConnection();
+ QuicConfig config = DefaultQuicConfig();
+ // Server doesn't allow any outgoing streams.
+ config.SetInitialMaxStreamDataBytesIncomingBidirectionalToSend(2);
+ config.SetInitialMaxStreamDataBytesUnidirectionalToSend(1);
+ SSL_CTX_set_early_data_enabled(server_crypto_config_->ssl_ctx(), false);
+ session_->CryptoConnect();
+ EXPECT_TRUE(session_->IsEncryptionEstablished());
+ QuicSpdyClientStream* stream = session_->CreateOutgoingBidirectionalStream();
+ ASSERT_TRUE(stream);
+ // Let the stream write more than 1 byte of data.
+ stream->WriteOrBufferData("hello", true, nullptr);
+
+ if (session_->version().UsesHttp3()) {
+ // Both control stream and the request stream will report errors.
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_ZERO_RTT_UNRETRANSMITTABLE, _, _))
+ .Times(2)
+ .WillOnce(testing::Invoke(connection_,
+ &MockQuicConnection::ReallyCloseConnection));
+ } else {
+ EXPECT_CALL(*connection_,
+ CloseConnection(
+ QUIC_ZERO_RTT_UNRETRANSMITTABLE,
+ "Server rejected 0-RTT, aborting because new stream max "
+ "data 2 for stream 3 is less than currently used: 5",
+ _))
+ .Times(1)
+ .WillOnce(testing::Invoke(connection_,
+ &MockQuicConnection::ReallyCloseConnection));
+ }
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _));
+
+ crypto_test_utils::HandshakeWithFakeServer(
+ &config, server_crypto_config_.get(), &helper_, &alarm_factory_,
+ connection_, crypto_stream_, AlpnForVersion(connection_->version()));
+}
+
+TEST_P(QuicSpdyClientSessionTest,
+ ZeroRttRejectReducesSessionFlowControlTooMuch) {
+ // This feature is TLS-only.
+ if (session_->version().UsesQuicCrypto()) {
+ return;
+ }
+
+ CompleteFirstConnection();
+
+ // Create a second connection, but disable 0-RTT on the server.
+ CreateConnection();
+ QuicConfig config = DefaultQuicConfig();
+ // Server doesn't allow minimum data in session.
+ config.SetInitialSessionFlowControlWindowToSend(
+ kMinimumFlowControlSendWindow);
+ SSL_CTX_set_early_data_enabled(server_crypto_config_->ssl_ctx(), false);
+ session_->CryptoConnect();
+ EXPECT_TRUE(session_->IsEncryptionEstablished());
+ QuicSpdyClientStream* stream = session_->CreateOutgoingBidirectionalStream();
+ ASSERT_TRUE(stream);
+ std::string data_to_send(kMinimumFlowControlSendWindow + 1, 'x');
+ // Let the stream write some data.
+ stream->WriteOrBufferData(data_to_send, true, nullptr);
+
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_ZERO_RTT_UNRETRANSMITTABLE, _, _))
+ .WillOnce(testing::Invoke(connection_,
+ &MockQuicConnection::ReallyCloseConnection));
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _));
+
+ crypto_test_utils::HandshakeWithFakeServer(
+ &config, server_crypto_config_.get(), &helper_, &alarm_factory_,
+ connection_, crypto_stream_, AlpnForVersion(connection_->version()));
+}
+
+TEST_P(QuicSpdyClientSessionTest, SetMaxPushIdBeforeEncryptionEstablished) {
+ // 0-RTT is TLS-only, MAX_PUSH_ID frame is HTTP/3-only.
+ if (!session_->version().UsesTls() || !session_->version().UsesHttp3()) {
+ return;
+ }
+
+ CompleteFirstConnection();
+
+ CreateConnection();
+ StrictMock<MockHttp3DebugVisitor> debug_visitor;
+ session_->set_debug_visitor(&debug_visitor);
+
+ // No MAX_PUSH_ID frame is sent before encryption is established.
+ session_->SetMaxPushId(5);
+
+ EXPECT_FALSE(session_->IsEncryptionEstablished());
+ EXPECT_FALSE(session_->OneRttKeysAvailable());
+ EXPECT_EQ(ENCRYPTION_INITIAL, session_->connection()->encryption_level());
+
+ // MAX_PUSH_ID frame is sent upon encryption establishment with the value set
+ // by the earlier SetMaxPushId() call.
+ EXPECT_CALL(debug_visitor, OnSettingsFrameSent(_));
+ EXPECT_CALL(debug_visitor, OnMaxPushIdFrameSent(_))
+ .WillOnce(Invoke(
+ [](const MaxPushIdFrame& frame) { EXPECT_EQ(5u, frame.push_id); }));
+ session_->CryptoConnect();
+ testing::Mock::VerifyAndClearExpectations(&debug_visitor);
+
+ EXPECT_TRUE(session_->IsEncryptionEstablished());
+ EXPECT_FALSE(session_->OneRttKeysAvailable());
+ EXPECT_EQ(ENCRYPTION_ZERO_RTT, session_->connection()->encryption_level());
+
+ // Another SetMaxPushId() call with the same value does not trigger sending
+ // another MAX_PUSH_ID frame.
+ session_->SetMaxPushId(5);
+
+ // Calling SetMaxPushId() with a different value results in sending another
+ // MAX_PUSH_ID frame.
+ EXPECT_CALL(debug_visitor, OnMaxPushIdFrameSent(_))
+ .WillOnce(Invoke(
+ [](const MaxPushIdFrame& frame) { EXPECT_EQ(10u, frame.push_id); }));
+ session_->SetMaxPushId(10);
+ testing::Mock::VerifyAndClearExpectations(&debug_visitor);
+
+ QuicConfig config = DefaultQuicConfig();
+ crypto_test_utils::HandshakeWithFakeServer(
+ &config, server_crypto_config_.get(), &helper_, &alarm_factory_,
+ connection_, crypto_stream_, AlpnForVersion(connection_->version()));
+
+ EXPECT_TRUE(session_->IsEncryptionEstablished());
+ EXPECT_TRUE(session_->OneRttKeysAvailable());
+ EXPECT_EQ(ENCRYPTION_FORWARD_SECURE,
+ session_->connection()->encryption_level());
+ EXPECT_TRUE(session_->GetCryptoStream()->IsResumption());
+}
+
+TEST_P(QuicSpdyClientSessionTest, SetMaxPushIdAfterEncryptionEstablished) {
+ // 0-RTT is TLS-only, MAX_PUSH_ID frame is HTTP/3-only.
+ if (!session_->version().UsesTls() || !session_->version().UsesHttp3()) {
+ return;
+ }
+
+ CompleteFirstConnection();
+
+ CreateConnection();
+ StrictMock<MockHttp3DebugVisitor> debug_visitor;
+ session_->set_debug_visitor(&debug_visitor);
+
+ EXPECT_FALSE(session_->IsEncryptionEstablished());
+ EXPECT_FALSE(session_->OneRttKeysAvailable());
+ EXPECT_EQ(ENCRYPTION_INITIAL, session_->connection()->encryption_level());
+
+ // No MAX_PUSH_ID frame is sent if SetMaxPushId() has not been called.
+ EXPECT_CALL(debug_visitor, OnSettingsFrameSent(_));
+ session_->CryptoConnect();
+ testing::Mock::VerifyAndClearExpectations(&debug_visitor);
+
+ EXPECT_TRUE(session_->IsEncryptionEstablished());
+ EXPECT_FALSE(session_->OneRttKeysAvailable());
+ EXPECT_EQ(ENCRYPTION_ZERO_RTT, session_->connection()->encryption_level());
+
+ // Calling SetMaxPushId() for the first time after encryption is established
+ // results in sending a MAX_PUSH_ID frame.
+ EXPECT_CALL(debug_visitor, OnMaxPushIdFrameSent(_))
+ .WillOnce(Invoke(
+ [](const MaxPushIdFrame& frame) { EXPECT_EQ(5u, frame.push_id); }));
+ session_->SetMaxPushId(5);
+ testing::Mock::VerifyAndClearExpectations(&debug_visitor);
+
+ // Another SetMaxPushId() call with the same value does not trigger sending
+ // another MAX_PUSH_ID frame.
+ session_->SetMaxPushId(5);
+
+ // Calling SetMaxPushId() with a different value results in sending another
+ // MAX_PUSH_ID frame.
+ EXPECT_CALL(debug_visitor, OnMaxPushIdFrameSent(_))
+ .WillOnce(Invoke(
+ [](const MaxPushIdFrame& frame) { EXPECT_EQ(10u, frame.push_id); }));
+ session_->SetMaxPushId(10);
+ testing::Mock::VerifyAndClearExpectations(&debug_visitor);
+
+ QuicConfig config = DefaultQuicConfig();
+ crypto_test_utils::HandshakeWithFakeServer(
+ &config, server_crypto_config_.get(), &helper_, &alarm_factory_,
+ connection_, crypto_stream_, AlpnForVersion(connection_->version()));
+
+ EXPECT_TRUE(session_->IsEncryptionEstablished());
+ EXPECT_TRUE(session_->OneRttKeysAvailable());
+ EXPECT_EQ(ENCRYPTION_FORWARD_SECURE,
+ session_->connection()->encryption_level());
+ EXPECT_TRUE(session_->GetCryptoStream()->IsResumption());
+}
+
+TEST_P(QuicSpdyClientSessionTest, BadSettingsInZeroRttResumption) {
+ if (!session_->version().UsesHttp3()) {
+ return;
+ }
+
+ CompleteFirstConnection();
+
+ CreateConnection();
+ CompleteCryptoHandshake();
+ EXPECT_TRUE(session_->GetCryptoStream()->EarlyDataAccepted());
+
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH, _, _))
+ .WillOnce(testing::Invoke(connection_,
+ &MockQuicConnection::ReallyCloseConnection));
+ // Let the session receive a different SETTINGS frame.
+ SettingsFrame settings;
+ settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 1;
+ settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
+ settings.values[256] = 4; // unknown setting
+ session_->OnSettingsFrame(settings);
+}
+
+TEST_P(QuicSpdyClientSessionTest, BadSettingsInZeroRttRejection) {
+ if (!session_->version().UsesHttp3()) {
+ return;
+ }
+
+ CompleteFirstConnection();
+
+ CreateConnection();
+ SSL_CTX_set_early_data_enabled(server_crypto_config_->ssl_ctx(), false);
+ session_->CryptoConnect();
+ EXPECT_TRUE(session_->IsEncryptionEstablished());
+ QuicConfig config = DefaultQuicConfig();
+ crypto_test_utils::HandshakeWithFakeServer(
+ &config, server_crypto_config_.get(), &helper_, &alarm_factory_,
+ connection_, crypto_stream_, AlpnForVersion(connection_->version()));
+ EXPECT_FALSE(session_->GetCryptoStream()->EarlyDataAccepted());
+
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH, _, _))
+ .WillOnce(testing::Invoke(connection_,
+ &MockQuicConnection::ReallyCloseConnection));
+ // Let the session receive a different SETTINGS frame.
+ SettingsFrame settings;
+ settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2;
+ // setting on SETTINGS_MAX_HEADER_LIST_SIZE is reduced.
+ settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 4;
+ settings.values[256] = 4; // unknown setting
+ session_->OnSettingsFrame(settings);
+}
+
+TEST_P(QuicSpdyClientSessionTest, ServerAcceptsZeroRttButOmitSetting) {
+ if (!session_->version().UsesHttp3()) {
+ return;
+ }
+
+ CompleteFirstConnection();
+
+ CreateConnection();
+ CompleteCryptoHandshake();
+ EXPECT_TRUE(session_->GetMutableCryptoStream()->EarlyDataAccepted());
+
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH, _, _))
+ .WillOnce(testing::Invoke(connection_,
+ &MockQuicConnection::ReallyCloseConnection));
+ // Let the session receive a different SETTINGS frame.
+ SettingsFrame settings;
+ settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 1;
+ // Intentionally omit SETTINGS_MAX_HEADER_LIST_SIZE which was previously sent
+ // with a non-zero value.
+ settings.values[256] = 4; // unknown setting
+ session_->OnSettingsFrame(settings);
}
} // namespace
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.cc
index 7232f76c755..f50e756d1b3 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.cc
@@ -53,24 +53,41 @@ void QuicSpdyClientStream::OnInitialHeadersComplete(
if (!SpdyUtils::CopyAndValidateHeaders(header_list, &content_length_,
&response_headers_)) {
QUIC_DLOG(ERROR) << "Failed to parse header list: "
- << header_list.DebugString();
+ << header_list.DebugString() << " on stream " << id();
Reset(QUIC_BAD_APPLICATION_PAYLOAD);
return;
}
if (!ParseHeaderStatusCode(response_headers_, &response_code_)) {
QUIC_DLOG(ERROR) << "Received invalid response code: "
- << response_headers_[":status"].as_string();
+ << response_headers_[":status"].as_string()
+ << " on stream " << id();
+ Reset(QUIC_BAD_APPLICATION_PAYLOAD);
+ return;
+ }
+
+ if (response_code_ == 101) {
+ // 101 "Switching Protocols" is forbidden in HTTP/3 as per the
+ // "HTTP Upgrade" section of draft-ietf-quic-http.
+ QUIC_DLOG(ERROR) << "Received forbidden 101 response code"
+ << " on stream " << id();
Reset(QUIC_BAD_APPLICATION_PAYLOAD);
return;
}
- if (response_code_ == 100 && !has_preliminary_headers_) {
- // These are preliminary 100 Continue headers, not the actual response
- // headers.
+ if (response_code_ >= 100 && response_code_ < 200) {
+ // These are Informational 1xx headers, not the actual response headers.
+ QUIC_DLOG(INFO) << "Received informational response code: "
+ << response_headers_[":status"].as_string() << " on stream "
+ << id();
set_headers_decompressed(false);
- has_preliminary_headers_ = true;
- preliminary_headers_ = std::move(response_headers_);
+ if (response_code_ == 100 && !has_preliminary_headers_) {
+ // This is 100 Continue, save it to enable "Expect: 100-continue".
+ has_preliminary_headers_ = true;
+ preliminary_headers_ = std::move(response_headers_);
+ } else {
+ response_headers_.clear();
+ }
}
ConsumeHeaderList();
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc
index fdc0e298371..1aba0005981 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc
@@ -133,17 +133,77 @@ TEST_P(QuicSpdyClientStreamTest, TestFraming) {
EXPECT_EQ(body_, stream_->data());
}
-TEST_P(QuicSpdyClientStreamTest, TestFraming100Continue) {
+TEST_P(QuicSpdyClientStreamTest, Test100ContinueBeforeSuccessful) {
+ // First send 100 Continue.
headers_[":status"] = "100";
auto headers = AsHeaderList(headers_);
stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
headers);
- stream_->OnStreamFrame(
- QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, body_));
EXPECT_EQ("100", stream_->preliminary_headers().find(":status")->second);
EXPECT_EQ(0u, stream_->response_headers().size());
EXPECT_EQ(100, stream_->response_code());
EXPECT_EQ("", stream_->data());
+ // Then send 200 OK.
+ headers_[":status"] = "200";
+ headers = AsHeaderList(headers_);
+ stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
+ headers);
+ std::unique_ptr<char[]> buffer;
+ QuicByteCount header_length =
+ HttpEncoder::SerializeDataFrameHeader(body_.length(), &buffer);
+ std::string header = std::string(buffer.get(), header_length);
+ std::string data =
+ connection_->version().UsesHttp3() ? header + body_ : body_;
+ stream_->OnStreamFrame(
+ QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
+ // Make sure the 200 response got parsed correctly.
+ EXPECT_EQ("200", stream_->response_headers().find(":status")->second);
+ EXPECT_EQ(200, stream_->response_code());
+ EXPECT_EQ(body_, stream_->data());
+ // Make sure the 100 response is still available.
+ EXPECT_EQ("100", stream_->preliminary_headers().find(":status")->second);
+}
+
+TEST_P(QuicSpdyClientStreamTest, TestUnknownInformationalBeforeSuccessful) {
+ // First send 199, an unknown Informational (1XX).
+ headers_[":status"] = "199";
+ auto headers = AsHeaderList(headers_);
+ stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
+ headers);
+ EXPECT_EQ(0u, stream_->response_headers().size());
+ EXPECT_EQ(199, stream_->response_code());
+ EXPECT_EQ("", stream_->data());
+ // Then send 200 OK.
+ headers_[":status"] = "200";
+ headers = AsHeaderList(headers_);
+ stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
+ headers);
+ std::unique_ptr<char[]> buffer;
+ QuicByteCount header_length =
+ HttpEncoder::SerializeDataFrameHeader(body_.length(), &buffer);
+ std::string header = std::string(buffer.get(), header_length);
+ std::string data =
+ connection_->version().UsesHttp3() ? header + body_ : body_;
+ stream_->OnStreamFrame(
+ QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
+ // Make sure the 200 response got parsed correctly.
+ EXPECT_EQ("200", stream_->response_headers().find(":status")->second);
+ EXPECT_EQ(200, stream_->response_code());
+ EXPECT_EQ(body_, stream_->data());
+}
+
+TEST_P(QuicSpdyClientStreamTest, TestReceiving101) {
+ // 101 "Switching Protocols" is forbidden in HTTP/3 as per the
+ // "HTTP Upgrade" section of draft-ietf-quic-http.
+ headers_[":status"] = "101";
+ EXPECT_CALL(*connection_, SendControlFrame(_));
+ EXPECT_CALL(*connection_,
+ OnStreamReset(stream_->id(), QUIC_BAD_APPLICATION_PAYLOAD));
+ auto headers = AsHeaderList(headers_);
+ stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
+ headers);
+ EXPECT_THAT(stream_->stream_error(),
+ IsStreamError(QUIC_BAD_APPLICATION_PAYLOAD));
}
TEST_P(QuicSpdyClientStreamTest, TestFramingOnePacket) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc
index 27643c87294..d6b5a0e7629 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc
@@ -434,6 +434,7 @@ QuicSpdySession::~QuicSpdySession() {
void QuicSpdySession::Initialize() {
QuicSession::Initialize();
+ FillSettingsFrame();
if (!VersionUsesHttp3(transport_version())) {
if (perspective() == Perspective::IS_SERVER) {
set_largest_peer_created_stream_id(
@@ -464,6 +465,15 @@ void QuicSpdySession::Initialize() {
2 * max_inbound_header_list_size_);
}
+void QuicSpdySession::FillSettingsFrame() {
+ settings_.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] =
+ qpack_maximum_dynamic_table_capacity_;
+ settings_.values[SETTINGS_QPACK_BLOCKED_STREAMS] =
+ qpack_maximum_blocked_streams_;
+ settings_.values[SETTINGS_MAX_HEADER_LIST_SIZE] =
+ max_inbound_header_list_size_;
+}
+
void QuicSpdySession::OnDecoderStreamError(
quiche::QuicheStringPiece error_message) {
DCHECK(VersionUsesHttp3(transport_version()));
@@ -548,7 +558,7 @@ void QuicSpdySession::OnPriorityFrame(
bool QuicSpdySession::OnPriorityUpdateForRequestStream(QuicStreamId stream_id,
int urgency) {
if (perspective() == Perspective::IS_CLIENT ||
- !QuicUtils::IsBidirectionalStreamId(stream_id) ||
+ !QuicUtils::IsBidirectionalStreamId(stream_id, version()) ||
!QuicUtils::IsClientInitiatedStreamId(transport_version(), stream_id)) {
return true;
}
@@ -647,7 +657,7 @@ void QuicSpdySession::WriteHttp3PriorityUpdate(
void QuicSpdySession::OnHttp3GoAway(QuicStreamId stream_id) {
DCHECK_EQ(perspective(), Perspective::IS_CLIENT);
- if (!QuicUtils::IsBidirectionalStreamId(stream_id) ||
+ if (!QuicUtils::IsBidirectionalStreamId(stream_id, version()) ||
IsIncomingStream(stream_id)) {
CloseConnectionWithDetails(
QUIC_INVALID_STREAM_ID,
@@ -736,9 +746,9 @@ void QuicSpdySession::SendInitialData() {
}
QuicConnection::ScopedPacketFlusher flusher(connection());
send_control_stream_->MaybeSendSettingsFrame();
- if (perspective() == Perspective::IS_CLIENT && !http3_max_push_id_sent_) {
+ if (perspective() == Perspective::IS_CLIENT && max_push_id_.has_value() &&
+ !http3_max_push_id_sent_) {
SendMaxPushId();
- http3_max_push_id_sent_ = true;
}
}
@@ -856,7 +866,7 @@ void QuicSpdySession::OnPromiseHeaderList(
ConnectionCloseBehavior::SILENT_CLOSE);
}
-bool QuicSpdySession::SetApplicationState(ApplicationState* cached_state) {
+bool QuicSpdySession::ResumeApplicationState(ApplicationState* cached_state) {
DCHECK_EQ(perspective(), Perspective::IS_CLIENT);
DCHECK(VersionUsesHttp3(transport_version()));
@@ -874,52 +884,102 @@ bool QuicSpdySession::SetApplicationState(ApplicationState* cached_state) {
return true;
}
-void QuicSpdySession::OnSettingsFrame(const SettingsFrame& frame) {
+bool QuicSpdySession::OnSettingsFrame(const SettingsFrame& frame) {
DCHECK(VersionUsesHttp3(transport_version()));
if (debug_visitor_ != nullptr) {
debug_visitor_->OnSettingsFrameReceived(frame);
}
for (const auto& setting : frame.values) {
- OnSetting(setting.first, setting.second);
+ if (!OnSetting(setting.first, setting.second)) {
+ return false;
+ }
}
+ return true;
}
-void QuicSpdySession::OnSetting(uint64_t id, uint64_t value) {
+bool QuicSpdySession::OnSetting(uint64_t id, uint64_t value) {
if (VersionUsesHttp3(transport_version())) {
// SETTINGS frame received on the control stream.
switch (id) {
- case SETTINGS_QPACK_MAX_TABLE_CAPACITY:
+ case SETTINGS_QPACK_MAX_TABLE_CAPACITY: {
QUIC_DVLOG(1)
<< ENDPOINT
<< "SETTINGS_QPACK_MAX_TABLE_CAPACITY received with value "
<< value;
// Communicate |value| to encoder, because it is used for encoding
// Required Insert Count.
- qpack_encoder_->SetMaximumDynamicTableCapacity(value);
+ bool success = qpack_encoder_->SetMaximumDynamicTableCapacity(value);
+ if (GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls) && !success) {
+ CloseConnectionWithDetails(
+ was_zero_rtt_rejected()
+ ? QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH
+ : QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH,
+ quiche::QuicheStrCat(
+ was_zero_rtt_rejected()
+ ? "Server rejected 0-RTT, aborting because "
+ : "",
+ "Server sent an SETTINGS_QPACK_MAX_TABLE_CAPACITY: ", value,
+ "while current value is: ",
+ qpack_encoder_->MaximumDynamicTableCapacity()));
+ return false;
+ }
// However, limit the dynamic table capacity to
// |qpack_maximum_dynamic_table_capacity_|.
qpack_encoder_->SetDynamicTableCapacity(
std::min(value, qpack_maximum_dynamic_table_capacity_));
break;
+ }
case SETTINGS_MAX_HEADER_LIST_SIZE:
QUIC_DVLOG(1) << ENDPOINT
<< "SETTINGS_MAX_HEADER_LIST_SIZE received with value "
<< value;
+ if (GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls) &&
+ max_outbound_header_list_size_ !=
+ std::numeric_limits<size_t>::max() &&
+ max_outbound_header_list_size_ > value) {
+ CloseConnectionWithDetails(
+ was_zero_rtt_rejected()
+ ? QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH
+ : QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH,
+ quiche::QuicheStrCat(
+ was_zero_rtt_rejected()
+ ? "Server rejected 0-RTT, aborting because "
+ : "",
+ "Server sent an SETTINGS_MAX_HEADER_LIST_SIZE: ", value,
+ "which reduces current value: ",
+ max_outbound_header_list_size_));
+ return false;
+ }
max_outbound_header_list_size_ = value;
break;
- case SETTINGS_QPACK_BLOCKED_STREAMS:
+ case SETTINGS_QPACK_BLOCKED_STREAMS: {
QUIC_DVLOG(1) << ENDPOINT
<< "SETTINGS_QPACK_BLOCKED_STREAMS received with value "
<< value;
- qpack_encoder_->SetMaximumBlockedStreams(value);
+ bool success = qpack_encoder_->SetMaximumBlockedStreams(value);
+ if (GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls) && !success) {
+ CloseConnectionWithDetails(
+ was_zero_rtt_rejected()
+ ? QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH
+ : QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH,
+ quiche::QuicheStrCat(
+ was_zero_rtt_rejected()
+ ? "Server rejected 0-RTT, aborting because "
+ : "",
+ "Server sent an SETTINGS_QPACK_BLOCKED_STREAMS: ", value,
+ "which reduces current value: ",
+ qpack_encoder_->maximum_blocked_streams()));
+ return false;
+ }
break;
+ }
default:
QUIC_DVLOG(1) << ENDPOINT << "Unknown setting identifier " << id
<< " received with value " << value;
// Ignore unknown settings.
break;
}
- return;
+ return true;
}
// SETTINGS frame received on the headers stream.
@@ -942,7 +1002,7 @@ void QuicSpdySession::OnSetting(uint64_t id, uint64_t value) {
quiche::QuicheStrCat("Invalid value for SETTINGS_ENABLE_PUSH: ",
value));
}
- return;
+ return true;
}
QUIC_DVLOG(1) << ENDPOINT << "SETTINGS_ENABLE_PUSH received with value "
<< value;
@@ -977,6 +1037,7 @@ void QuicSpdySession::OnSetting(uint64_t id, uint64_t value) {
id));
}
}
+ return true;
}
bool QuicSpdySession::ShouldReleaseHeadersStreamSequencerBuffer() {
@@ -1076,11 +1137,8 @@ void QuicSpdySession::CloseConnectionWithDetails(QuicErrorCode error,
}
bool QuicSpdySession::HasActiveRequestStreams() const {
- DCHECK_GE(static_cast<size_t>(stream_map().size()),
- num_incoming_static_streams() + num_outgoing_static_streams());
- return stream_map().size() - num_incoming_static_streams() -
- num_outgoing_static_streams() >
- 0;
+ DCHECK_GE(static_cast<size_t>(stream_map().size()), num_static_streams());
+ return stream_map().size() - num_static_streams() > 0;
}
bool QuicSpdySession::ProcessPendingStream(PendingStream* pending) {
@@ -1176,9 +1234,7 @@ void QuicSpdySession::MaybeInitializeHttp3UnidirectionalStreams() {
DCHECK(VersionUsesHttp3(transport_version()));
if (!send_control_stream_ && CanOpenNextOutgoingUnidirectionalStream()) {
auto send_control = std::make_unique<QuicSendControlStream>(
- GetNextOutgoingUnidirectionalStreamId(), this,
- qpack_maximum_dynamic_table_capacity_, qpack_maximum_blocked_streams_,
- max_inbound_header_list_size_);
+ GetNextOutgoingUnidirectionalStreamId(), this, settings_);
send_control_stream_ = send_control.get();
ActivateStream(std::move(send_control));
if (debug_visitor_) {
@@ -1231,15 +1287,19 @@ void QuicSpdySession::SetMaxPushId(PushId max_push_id) {
ietf_server_push_enabled_ = true;
if (max_push_id_.has_value()) {
- QUIC_DVLOG(1) << "Setting max_push_id to: " << max_push_id
+ if (max_push_id == max_push_id_.value()) {
+ QUIC_DVLOG(1) << "Not changing max_push_id: " << max_push_id;
+ return;
+ }
+
+ QUIC_DVLOG(1) << "Setting max_push_id to: " << max_push_id
<< " from: " << max_push_id_.value();
} else {
- QUIC_DVLOG(1) << "Setting max_push_id to: " << max_push_id
- << " from unset";
+ QUIC_DVLOG(1) << "Setting max_push_id to: " << max_push_id << " from unset";
}
max_push_id_ = max_push_id;
- if (OneRttKeysAvailable()) {
+ if (IsEncryptionEstablished()) {
SendMaxPushId();
}
}
@@ -1281,9 +1341,8 @@ void QuicSpdySession::SendMaxPushId() {
DCHECK(VersionUsesHttp3(transport_version()));
DCHECK_EQ(Perspective::IS_CLIENT, perspective());
- if (max_push_id_.has_value()) {
- send_control_stream_->SendMaxPushIdFrame(max_push_id_.value());
- }
+ send_control_stream_->SendMaxPushIdFrame(max_push_id_.value());
+ http3_max_push_id_sent_ = true;
}
void QuicSpdySession::EnableServerPush() {
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h
index 703dffaf41e..4d6ee6370e3 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h
@@ -247,10 +247,14 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
bool server_push_enabled() const;
// Called when the control stream receives HTTP/3 SETTINGS.
- virtual void OnSettingsFrame(const SettingsFrame& frame);
+ // Returns false in case of 0-RTT if received settings are incompatible with
+ // cached values, true otherwise.
+ virtual bool OnSettingsFrame(const SettingsFrame& frame);
- // Called when a setting is parsed from an incoming SETTINGS frame.
- void OnSetting(uint64_t id, uint64_t value);
+ // Called when a SETTINGS is parsed from an incoming SETTINGS frame.
+ // Returns false in case of 0-RTT if received SETTINGS is incompatible with
+ // cached value, true otherwise.
+ bool OnSetting(uint64_t id, uint64_t value);
// Return true if this session wants to release headers stream's buffer
// aggressively.
@@ -378,7 +382,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
void OnStreamCreated(QuicSpdyStream* stream);
// Decode SETTINGS from |cached_state| and apply it to the session.
- bool SetApplicationState(ApplicationState* cached_state) override;
+ bool ResumeApplicationState(ApplicationState* cached_state) override;
protected:
// Override CreateIncomingStream(), CreateOutgoingBidirectionalStream() and
@@ -443,11 +447,11 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
return receive_control_stream_;
}
+ const SettingsFrame& settings() const { return settings_; }
+
// Initializes HTTP/3 unidirectional streams if not yet initialzed.
virtual void MaybeInitializeHttp3UnidirectionalStreams();
- void SendMaxPushId();
-
private:
friend class test::QuicSpdySessionPeer;
@@ -468,10 +472,18 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
void CloseConnectionOnDuplicateHttp3UnidirectionalStreams(
quiche::QuicheStringPiece type);
- // Sends any data which should be sent at the start of a connection,
- // including the initial SETTINGS frame, etc.
+ // Sends any data which should be sent at the start of a connection, including
+ // the initial SETTINGS frame, and (when IETF QUIC is used) also a MAX_PUSH_ID
+ // frame if SetMaxPushId() had been called before encryption was established.
+ // When using 0-RTT, this method is called twice: once when encryption is
+ // established, and again when 1-RTT keys are available.
void SendInitialData();
+ // Send a MAX_PUSH_ID frame. Used in IETF QUIC only.
+ void SendMaxPushId();
+
+ void FillSettingsFrame();
+
std::unique_ptr<QpackEncoder> qpack_encoder_;
std::unique_ptr<QpackDecoder> qpack_decoder_;
@@ -489,6 +501,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
QpackSendStream* qpack_encoder_send_stream_;
QpackSendStream* qpack_decoder_send_stream_;
+ SettingsFrame settings_;
+
// Maximum dynamic table capacity as defined at
// https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#maximum-dynamic-table-capacity
// for the decoding context. Value will be sent via
@@ -533,12 +547,17 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// Server push is enabled for a client by calling SetMaxPushId().
bool ietf_server_push_enabled_;
- // Used in IETF QUIC only. Unset until a MAX_PUSH_ID frame is received/sent.
- // For a server, the push ID in the most recently received MAX_PUSH_ID frame.
- // For a client before 1-RTT keys are available, the push ID to be sent in the
- // initial MAX_PUSH_ID frame.
- // For a client after 1-RTT keys are available, the push ID in the most
- // recently sent MAX_PUSH_ID frame.
+ // Used in IETF QUIC only.
+ // For a server:
+ // the push ID in the most recently received MAX_PUSH_ID frame,
+ // or unset if no MAX_PUSH_ID frame has been received.
+ // For a client:
+ // unset until SetMaxPushId() is called;
+ // before encryption is established, the push ID to be sent in the initial
+ // MAX_PUSH_ID frame;
+ // after encryption is established, the push ID in the most recently sent
+ // MAX_PUSH_ID frame.
+ // Once set, never goes back to unset.
quiche::QuicheOptional<PushId> max_push_id_;
// An integer used for live check. The indicator is assigned a value in
@@ -554,14 +573,14 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// If the endpoint has sent HTTP/3 GOAWAY frame.
bool http3_goaway_sent_;
- // If SendMaxPushId() has been called from SendInitialData(). Note that a
- // MAX_PUSH_ID frame is only sent if SetMaxPushId() had been called
- // beforehand.
+ // Only used by a client, only with IETF QUIC. True if a MAX_PUSH_ID frame
+ // has been sent, in which case |max_push_id_| has the value sent in the most
+ // recent MAX_PUSH_ID frame. Once true, never goes back to false.
bool http3_max_push_id_sent_;
// Priority values received in PRIORITY_UPDATE frames for streams that are not
// open yet.
- QuicUnorderedMap<QuicStreamId, int> buffered_stream_priorities_;
+ QuicHashMap<QuicStreamId, int> buffered_stream_priorities_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc
index 8b78d7f0883..b2bcaa3bf28 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc
@@ -91,6 +91,17 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
kInitialStreamFlowControlWindowForTest);
session()->config()->SetInitialSessionFlowControlWindowToSend(
kInitialSessionFlowControlWindowForTest);
+ if (session()->version().AuthenticatesHandshakeConnectionIds()) {
+ if (session()->perspective() == Perspective::IS_CLIENT) {
+ session()->config()->SetOriginalConnectionIdToSend(
+ session()->connection()->connection_id());
+ session()->config()->SetInitialSourceConnectionIdToSend(
+ session()->connection()->connection_id());
+ } else {
+ session()->config()->SetInitialSourceConnectionIdToSend(
+ session()->connection()->client_connection_id());
+ }
+ }
if (session()->connection()->version().handshake_protocol ==
PROTOCOL_TLS1_3) {
TransportParameters transport_parameters;
@@ -129,6 +140,8 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
HandshakeState GetHandshakeState() const override {
return one_rtt_keys_available() ? HANDSHAKE_COMPLETE : HANDSHAKE_START;
}
+ void SetServerApplicationStateForResumption(
+ std::unique_ptr<ApplicationState> /*application_state*/) override {}
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const override {
return *params_;
@@ -197,6 +210,9 @@ class TestSession : public QuicSpdySession {
this->connection()->SetEncrypter(
ENCRYPTION_FORWARD_SECURE,
std::make_unique<NullEncrypter>(connection->perspective()));
+ if (this->connection()->version().SupportsAntiAmplificationLimit()) {
+ QuicConnectionPeer::SetAddressValidated(this->connection());
+ }
}
~TestSession() override { DeleteConnection(); }
@@ -226,7 +242,7 @@ class TestSession : public QuicSpdySession {
TestStream* CreateIncomingStream(QuicStreamId id) override {
// Enforce the limit on the number of open streams.
if (!VersionHasIetfQuicFrames(connection()->transport_version()) &&
- GetNumOpenIncomingStreams() + 1 >
+ stream_id_manager().num_open_incoming_streams() + 1 >
max_open_incoming_bidirectional_streams()) {
connection()->CloseConnection(
QUIC_TOO_MANY_OPEN_STREAMS, "Too many streams!",
@@ -235,9 +251,8 @@ class TestSession : public QuicSpdySession {
} else {
TestStream* stream = new TestStream(
id, this,
- DetermineStreamType(id, connection()->transport_version(),
- perspective(), /*is_incoming=*/true,
- BIDIRECTIONAL));
+ DetermineStreamType(id, connection()->version(), perspective(),
+ /*is_incoming=*/true, BIDIRECTIONAL));
ActivateStream(QuicWrapUnique(stream));
return stream;
}
@@ -245,11 +260,10 @@ class TestSession : public QuicSpdySession {
TestStream* CreateIncomingStream(PendingStream* pending) override {
QuicStreamId id = pending->id();
- TestStream* stream =
- new TestStream(pending, this,
- DetermineStreamType(
- id, connection()->transport_version(), perspective(),
- /*is_incoming=*/true, BIDIRECTIONAL));
+ TestStream* stream = new TestStream(
+ pending, this,
+ DetermineStreamType(id, connection()->version(), perspective(),
+ /*is_incoming=*/true, BIDIRECTIONAL));
ActivateStream(QuicWrapUnique(stream));
return stream;
}
@@ -299,7 +313,7 @@ class TestSession : public QuicSpdySession {
MakeIOVector("not empty", &iov);
QuicStreamPeer::SendBuffer(stream).SaveStreamData(&iov, 1, 0, 9);
QuicConsumedData consumed =
- WritevData(stream->id(), 9, 0, FIN, NOT_RETRANSMISSION, QuicheNullOpt);
+ WritevData(stream->id(), 9, 0, FIN, NOT_RETRANSMISSION, QUICHE_NULLOPT);
QuicStreamPeer::SendBuffer(stream).OnStreamDataConsumed(
consumed.bytes_consumed);
return consumed;
@@ -308,7 +322,7 @@ class TestSession : public QuicSpdySession {
QuicConsumedData SendLargeFakeData(QuicStream* stream, int bytes) {
DCHECK(writev_consumes_all_data_);
return WritevData(stream->id(), bytes, 0, FIN, NOT_RETRANSMISSION,
- QuicheNullOpt);
+ QUICHE_NULLOPT);
}
using QuicSession::closed_streams;
@@ -1599,6 +1613,7 @@ TEST_P(QuicSpdySessionTestServer, TooLowUnidirectionalStreamLimitHttp3) {
return;
}
QuicConfigPeer::SetReceivedMaxUnidirectionalStreams(session_.config(), 2u);
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
EXPECT_CALL(
*connection_,
@@ -1613,6 +1628,7 @@ TEST_P(QuicSpdySessionTestServer, CustomFlowControlWindow) {
copt.push_back(kIFW7);
QuicConfigPeer::SetReceivedConnectionOptions(session_.config(), copt);
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_.OnConfigNegotiated();
EXPECT_EQ(192 * 1024u, QuicFlowControllerPeer::ReceiveWindowSize(
session_.flow_controller()));
@@ -2985,6 +3001,26 @@ TEST_P(QuicSpdySessionTestServer, PeerClosesCriticalReceiveStream) {
}
}
+TEST_P(QuicSpdySessionTestServer,
+ H3ControlStreamsLimitedByConnectionFlowControl) {
+ if (!VersionUsesHttp3(transport_version())) {
+ return;
+ }
+ // Ensure connection level flow control blockage.
+ QuicFlowControllerPeer::SetSendWindowOffset(session_.flow_controller(), 0);
+ EXPECT_TRUE(session_.IsConnectionFlowControlBlocked());
+
+ QuicSendControlStream* send_control_stream =
+ QuicSpdySessionPeer::GetSendControlStream(&session_);
+ // Mark send_control stream write blocked.
+ session_.MarkConnectionLevelWriteBlocked(send_control_stream->id());
+ if (GetQuicReloadableFlag(quic_fix_willing_and_able_to_write)) {
+ EXPECT_FALSE(session_.WillingAndAbleToWrite());
+ } else {
+ EXPECT_TRUE(session_.WillingAndAbleToWrite());
+ }
+}
+
TEST_P(QuicSpdySessionTestServer, PeerClosesCriticalSendStream) {
if (!VersionUsesHttp3(transport_version())) {
return;
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc
index 51f7c5c9525..4c979c1784f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc
@@ -529,6 +529,21 @@ void QuicSpdyStream::OnStreamHeadersPriority(
void QuicSpdyStream::OnStreamHeaderList(bool fin,
size_t frame_len,
const QuicHeaderList& header_list) {
+ if (GetQuicReloadableFlag(quic_save_user_agent_in_quic_session)) {
+ if (!spdy_session()->user_agent_id().has_value()) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_save_user_agent_in_quic_session, 3, 3);
+ std::string uaid;
+ for (const auto& kv : header_list) {
+ if (quiche::QuicheTextUtils::ToLower(kv.first) ==
+ kUserAgentHeaderName) {
+ uaid = kv.second;
+ break;
+ }
+ }
+ spdy_session()->SetUserAgentId(std::move(uaid));
+ }
+ }
+
// TODO(b/134706391): remove |fin| argument.
// When using Google QUIC, an empty header list indicates that the size limit
// has been exceeded.
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc
index bafb0f282f0..e769a9d6027 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc
@@ -78,6 +78,17 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
kInitialStreamFlowControlWindowForTest);
session()->config()->SetInitialSessionFlowControlWindowToSend(
kInitialSessionFlowControlWindowForTest);
+ if (session()->version().AuthenticatesHandshakeConnectionIds()) {
+ if (session()->perspective() == Perspective::IS_CLIENT) {
+ session()->config()->SetOriginalConnectionIdToSend(
+ session()->connection()->connection_id());
+ session()->config()->SetInitialSourceConnectionIdToSend(
+ session()->connection()->connection_id());
+ } else {
+ session()->config()->SetInitialSourceConnectionIdToSend(
+ session()->connection()->client_connection_id());
+ }
+ }
if (session()->connection()->version().handshake_protocol ==
PROTOCOL_TLS1_3) {
TransportParameters transport_parameters;
@@ -116,6 +127,8 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
HandshakeState GetHandshakeState() const override {
return one_rtt_keys_available() ? HANDSHAKE_COMPLETE : HANDSHAKE_START;
}
+ void SetServerApplicationStateForResumption(
+ std::unique_ptr<ApplicationState> /*application_state*/) override {}
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const override {
return *params_;
@@ -324,6 +337,9 @@ class QuicSpdyStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
&helper_, &alarm_factory_, perspective, SupportedVersions(GetParam()));
session_ = std::make_unique<StrictMock<TestSession>>(connection_);
session_->Initialize();
+ if (connection_->version().SupportsAntiAmplificationLimit()) {
+ QuicConnectionPeer::SetAddressValidated(connection_);
+ }
connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
ON_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillByDefault(
diff --git a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc
index 6120f850bbc..af4de8b1c8c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc
@@ -31,42 +31,20 @@ LegacyQuicStreamIdManager::LegacyQuicStreamIdManager(
: QuicUtils::GetCryptoStreamId(transport_version_))
: QuicUtils::GetInvalidStreamId(transport_version_)),
num_open_incoming_streams_(0),
- num_open_outgoing_streams_(0),
- handles_accounting_(
- GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) {
- if (handles_accounting_) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_stream_id_manager_handles_accounting);
- }
-}
+ num_open_outgoing_streams_(0) {}
LegacyQuicStreamIdManager::~LegacyQuicStreamIdManager() {}
-bool LegacyQuicStreamIdManager::CanOpenNextOutgoingStream(
- size_t current_num_open_outgoing_streams) const {
- if (handles_accounting_) {
- DCHECK_LE(num_open_outgoing_streams_, max_open_outgoing_streams_);
- QUIC_DLOG_IF(INFO, num_open_outgoing_streams_ == max_open_outgoing_streams_)
- << "Failed to create a new outgoing stream. "
- << "Already " << num_open_outgoing_streams_ << " open.";
- return num_open_outgoing_streams_ < max_open_outgoing_streams_;
- }
- if (current_num_open_outgoing_streams >= max_open_outgoing_streams_) {
- QUIC_DLOG(INFO) << "Failed to create a new outgoing stream. "
- << "Already " << current_num_open_outgoing_streams
- << " open.";
- return false;
- }
- return true;
+bool LegacyQuicStreamIdManager::CanOpenNextOutgoingStream() const {
+ DCHECK_LE(num_open_outgoing_streams_, max_open_outgoing_streams_);
+ QUIC_DLOG_IF(INFO, num_open_outgoing_streams_ == max_open_outgoing_streams_)
+ << "Failed to create a new outgoing stream. "
+ << "Already " << num_open_outgoing_streams_ << " open.";
+ return num_open_outgoing_streams_ < max_open_outgoing_streams_;
}
-bool LegacyQuicStreamIdManager::CanOpenIncomingStream(
- size_t current_num_open_incoming_streams) const {
- if (handles_accounting_) {
- return num_open_incoming_streams_ < max_open_incoming_streams_;
- }
- // Check if the new number of open streams would cause the number of
- // open streams to exceed the limit.
- return current_num_open_incoming_streams < max_open_incoming_streams_;
+bool LegacyQuicStreamIdManager::CanOpenIncomingStream() const {
+ return num_open_incoming_streams_ < max_open_incoming_streams_;
}
bool LegacyQuicStreamIdManager::MaybeIncreaseLargestPeerStreamId(
@@ -121,7 +99,6 @@ QuicStreamId LegacyQuicStreamIdManager::GetNextOutgoingStreamId() {
}
void LegacyQuicStreamIdManager::ActivateStream(bool is_incoming) {
- DCHECK(handles_accounting_);
if (is_incoming) {
++num_open_incoming_streams_;
return;
@@ -130,7 +107,6 @@ void LegacyQuicStreamIdManager::ActivateStream(bool is_incoming) {
}
void LegacyQuicStreamIdManager::OnStreamClosed(bool is_incoming) {
- DCHECK(handles_accounting_);
if (is_incoming) {
QUIC_BUG_IF(num_open_incoming_streams_ == 0);
--num_open_incoming_streams_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h
index 6c1309ebbc9..01315872fb8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h
@@ -29,11 +29,10 @@ class QUIC_EXPORT_PRIVATE LegacyQuicStreamIdManager {
~LegacyQuicStreamIdManager();
// Returns true if the next outgoing stream ID can be allocated.
- bool CanOpenNextOutgoingStream(
- size_t current_num_open_outgoing_streams) const;
+ bool CanOpenNextOutgoingStream() const;
// Returns true if a new incoming stream can be opened.
- bool CanOpenIncomingStream(size_t current_num_open_incoming_streams) const;
+ bool CanOpenIncomingStream() const;
// Returns false when increasing the largest created stream id to |id| would
// violate the limit, so the connection should be closed.
@@ -95,8 +94,6 @@ class QUIC_EXPORT_PRIVATE LegacyQuicStreamIdManager {
return num_open_outgoing_streams_;
}
- bool handles_accounting() const { return handles_accounting_; }
-
private:
friend class test::QuicSessionPeer;
@@ -118,16 +115,11 @@ class QUIC_EXPORT_PRIVATE LegacyQuicStreamIdManager {
QuicStreamId largest_peer_created_stream_id_;
- // A counter for peer initiated open streams. Used when handles_accounting_ is
- // true.
+ // A counter for peer initiated open streams.
size_t num_open_incoming_streams_;
- // A counter for self initiated open streams. Used when handles_accounting_ is
- // true.
+ // A counter for self initiated open streams.
size_t num_open_outgoing_streams_;
-
- // Latched value of quic_stream_id_manager_handles_accounting.
- const bool handles_accounting_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager_test.cc
index 00654b48c45..b7ba1d27035 100644
--- a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager_test.cc
@@ -78,33 +78,21 @@ INSTANTIATE_TEST_SUITE_P(Tests,
::testing::PrintToStringParamName());
TEST_P(LegacyQuicStreamIdManagerTest, CanOpenNextOutgoingStream) {
- if (GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) {
- for (size_t i = 0; i < manager_.max_open_outgoing_streams() - 1; ++i) {
- manager_.ActivateStream(/*is_incoming=*/false);
- }
- }
- EXPECT_TRUE(manager_.CanOpenNextOutgoingStream(
- manager_.max_open_outgoing_streams() - 1));
- if (GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) {
+ for (size_t i = 0; i < manager_.max_open_outgoing_streams() - 1; ++i) {
manager_.ActivateStream(/*is_incoming=*/false);
}
- EXPECT_FALSE(
- manager_.CanOpenNextOutgoingStream(manager_.max_open_outgoing_streams()));
+ EXPECT_TRUE(manager_.CanOpenNextOutgoingStream());
+ manager_.ActivateStream(/*is_incoming=*/false);
+ EXPECT_FALSE(manager_.CanOpenNextOutgoingStream());
}
TEST_P(LegacyQuicStreamIdManagerTest, CanOpenIncomingStream) {
- if (GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) {
- for (size_t i = 0; i < manager_.max_open_incoming_streams() - 1; ++i) {
- manager_.ActivateStream(/*is_incoming=*/true);
- }
- }
- EXPECT_TRUE(
- manager_.CanOpenIncomingStream(manager_.max_open_incoming_streams() - 1));
- if (GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) {
+ for (size_t i = 0; i < manager_.max_open_incoming_streams() - 1; ++i) {
manager_.ActivateStream(/*is_incoming=*/true);
}
- EXPECT_FALSE(
- manager_.CanOpenIncomingStream(manager_.max_open_incoming_streams()));
+ EXPECT_TRUE(manager_.CanOpenIncomingStream());
+ manager_.ActivateStream(/*is_incoming=*/true);
+ EXPECT_FALSE(manager_.CanOpenIncomingStream());
}
TEST_P(LegacyQuicStreamIdManagerTest, AvailableStreams) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h
index f1659a64fc9..ecb56993381 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h
@@ -77,7 +77,7 @@ class QUIC_EXPORT_PRIVATE QpackBlockingManager {
// same time. Use std::list instead of QuicCircularDeque because it has lower
// memory footprint when holding few elements.
using HeaderBlocksForStream = std::list<IndexSet>;
- using HeaderBlocks = QuicUnorderedMap<QuicStreamId, HeaderBlocksForStream>;
+ using HeaderBlocks = QuicHashMap<QuicStreamId, HeaderBlocksForStream>;
// Increase or decrease the reference count for each index in |indices|.
void IncreaseReferenceCounts(const IndexSet& indices);
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc
index db7ec794268..67adf1268eb 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc
@@ -378,9 +378,10 @@ std::string QpackEncoder::EncodeHeaderList(
return SecondPassEncode(std::move(instructions), required_insert_count);
}
-void QpackEncoder::SetMaximumDynamicTableCapacity(
+bool QpackEncoder::SetMaximumDynamicTableCapacity(
uint64_t maximum_dynamic_table_capacity) {
- header_table_.SetMaximumDynamicTableCapacity(maximum_dynamic_table_capacity);
+ return header_table_.SetMaximumDynamicTableCapacity(
+ maximum_dynamic_table_capacity);
}
void QpackEncoder::SetDynamicTableCapacity(uint64_t dynamic_table_capacity) {
@@ -392,8 +393,12 @@ void QpackEncoder::SetDynamicTableCapacity(uint64_t dynamic_table_capacity) {
DCHECK(success);
}
-void QpackEncoder::SetMaximumBlockedStreams(uint64_t maximum_blocked_streams) {
+bool QpackEncoder::SetMaximumBlockedStreams(uint64_t maximum_blocked_streams) {
+ if (maximum_blocked_streams < maximum_blocked_streams_) {
+ return false;
+ }
maximum_blocked_streams_ = maximum_blocked_streams;
+ return true;
}
void QpackEncoder::OnInsertCountIncrement(uint64_t increment) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h
index 0f1d14ca539..202fc6d8ef1 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h
@@ -63,7 +63,10 @@ class QUIC_EXPORT_PRIVATE QpackEncoder
// measured in bytes. Called when SETTINGS_QPACK_MAX_TABLE_CAPACITY is
// received. Encoder needs to know this value so that it can calculate
// MaxEntries, used as a modulus to encode Required Insert Count.
- void SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity);
+ // Returns true if |maximum_dynamic_table_capacity| is set for the first time
+ // or if it doesn't change current value. The setting is not changed when
+ // returning false.
+ bool SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity);
// Set dynamic table capacity to |dynamic_table_capacity|.
// |dynamic_table_capacity| must not exceed maximum dynamic table capacity.
@@ -72,7 +75,9 @@ class QUIC_EXPORT_PRIVATE QpackEncoder
// Set maximum number of blocked streams.
// Called when SETTINGS_QPACK_BLOCKED_STREAMS is received.
- void SetMaximumBlockedStreams(uint64_t maximum_blocked_streams);
+ // Returns true if |maximum_blocked_streams| doesn't decrease current value.
+ // The setting is not changed when returning false.
+ bool SetMaximumBlockedStreams(uint64_t maximum_blocked_streams);
// QpackDecoderStreamReceiver::Delegate implementation
void OnInsertCountIncrement(uint64_t increment) override;
@@ -94,6 +99,12 @@ class QUIC_EXPORT_PRIVATE QpackEncoder
return header_table_.dynamic_table_entry_referenced();
}
+ uint64_t maximum_blocked_streams() const { return maximum_blocked_streams_; }
+
+ uint64_t MaximumDynamicTableCapacity() const {
+ return header_table_.maximum_dynamic_table_capacity();
+ }
+
private:
friend class test::QpackEncoderPeer;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc
index 472db893540..29e71488bda 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc
@@ -186,16 +186,15 @@ bool QpackHeaderTable::SetDynamicTableCapacity(uint64_t capacity) {
return true;
}
-void QpackHeaderTable::SetMaximumDynamicTableCapacity(
+bool QpackHeaderTable::SetMaximumDynamicTableCapacity(
uint64_t maximum_dynamic_table_capacity) {
- // This method can only be called once: in the decoding context, shortly after
- // construction; in the encoding context, upon receiving the SETTINGS frame.
- DCHECK_EQ(0u, dynamic_table_capacity_);
- DCHECK_EQ(0u, maximum_dynamic_table_capacity_);
- DCHECK_EQ(0u, max_entries_);
-
- maximum_dynamic_table_capacity_ = maximum_dynamic_table_capacity;
- max_entries_ = maximum_dynamic_table_capacity / 32;
+ if (maximum_dynamic_table_capacity_ == 0) {
+ maximum_dynamic_table_capacity_ = maximum_dynamic_table_capacity;
+ max_entries_ = maximum_dynamic_table_capacity / 32;
+ return true;
+ }
+ // If the value is already set, it should not be changed.
+ return maximum_dynamic_table_capacity == maximum_dynamic_table_capacity_;
}
void QpackHeaderTable::RegisterObserver(uint64_t required_insert_count,
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h
index e3fb97504b3..bed1cc84afa 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h
@@ -97,7 +97,10 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable {
// value can be set upon connection establishment, whereas in the encoding
// context it can be set when the SETTINGS frame is received.
// This method must only be called at most once.
- void SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity);
+ // Returns true if |maximum_dynamic_table_capacity| is set for the first time
+ // or if it doesn't change current value. The setting is not changed when
+ // returning false.
+ bool SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity);
// Get |maximum_dynamic_table_capacity_|.
uint64_t maximum_dynamic_table_capacity() const {
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream_test.cc
index c77a6218bca..63e0f12e3cc 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream_test.cc
@@ -7,6 +7,7 @@
#include "net/third_party/quiche/src/quic/core/http/http_constants.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
@@ -66,6 +67,9 @@ class QpackSendStreamTest : public QuicTestWithParam<TestParams> {
SupportedVersions(GetParam().version))),
session_(connection_) {
session_.Initialize();
+ if (connection_->version().SupportsAntiAmplificationLimit()) {
+ QuicConnectionPeer::SetAddressValidated(connection_);
+ }
QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(
session_.config(), kMinimumFlowControlSendWindow);
QuicConfigPeer::SetReceivedInitialMaxStreamDataBytesUnidirectional(
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.cc b/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.cc
index c18369eac9b..3b22180750d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.cc
@@ -61,7 +61,7 @@ bool QuicCoalescedPacket::MaybeCoalescePacket(
return false;
}
QUIC_DVLOG(1) << "Successfully coalesced packet: encryption_level: "
- << EncryptionLevelToString(packet.encryption_level)
+ << packet.encryption_level
<< ", encrypted_length: " << packet.encrypted_length
<< ", current length: " << length_
<< ", max_packet_length: " << max_packet_length_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_config.cc b/chromium/net/third_party/quiche/src/quic/core/quic_config.cc
index 7c781f4def0..30a5e2ba568 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_config.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_config.cc
@@ -434,7 +434,7 @@ QuicConfig::QuicConfig()
max_undecryptable_packets_(0),
connection_options_(kCOPT, PRESENCE_OPTIONAL),
client_connection_options_(kCLOP, PRESENCE_OPTIONAL),
- idle_timeout_to_send_(QuicTime::Delta::Infinite()),
+ max_idle_timeout_to_send_(QuicTime::Delta::Infinite()),
max_bidirectional_streams_(kMIBS, PRESENCE_REQUIRED),
max_unidirectional_streams_(kMIUS, PRESENCE_OPTIONAL),
bytes_for_connection_id_(kTCID, PRESENCE_OPTIONAL),
@@ -447,12 +447,13 @@ QuicConfig::QuicConfig()
initial_stream_flow_control_window_bytes_(kSFCW, PRESENCE_OPTIONAL),
initial_session_flow_control_window_bytes_(kCFCW, PRESENCE_OPTIONAL),
connection_migration_disabled_(kNCMR, PRESENCE_OPTIONAL),
+ support_handshake_done_(0, PRESENCE_OPTIONAL),
alternate_server_address_ipv6_(kASAD, PRESENCE_OPTIONAL),
alternate_server_address_ipv4_(kASAD, PRESENCE_OPTIONAL),
stateless_reset_token_(kSRST, PRESENCE_OPTIONAL),
max_ack_delay_ms_(kMAD, PRESENCE_OPTIONAL),
ack_delay_exponent_(kADE, PRESENCE_OPTIONAL),
- max_packet_size_(0, PRESENCE_OPTIONAL),
+ max_udp_payload_size_(0, PRESENCE_OPTIONAL),
max_datagram_frame_size_(0, PRESENCE_OPTIONAL),
active_connection_id_limit_(0, PRESENCE_OPTIONAL) {
SetDefaults();
@@ -543,17 +544,17 @@ void QuicConfig::SetIdleNetworkTimeout(QuicTime::Delta idle_network_timeout) {
QUIC_BUG << "Invalid idle network timeout " << idle_network_timeout;
return;
}
- idle_timeout_to_send_ = idle_network_timeout;
+ max_idle_timeout_to_send_ = idle_network_timeout;
}
QuicTime::Delta QuicConfig::IdleNetworkTimeout() const {
// TODO(b/152032210) add a QUIC_BUG to ensure that is not called before we've
// received the peer's values. This is true in production code but not in all
// of our tests that use a fake QuicConfig.
- if (!received_idle_timeout_.has_value()) {
- return idle_timeout_to_send_;
+ if (!received_max_idle_timeout_.has_value()) {
+ return max_idle_timeout_to_send_;
}
- return received_idle_timeout_.value();
+ return received_max_idle_timeout_.value();
}
void QuicConfig::SetMaxBidirectionalStreamsToSend(uint32_t max_streams) {
@@ -592,7 +593,7 @@ void QuicConfig::SetMaxAckDelayToSendMs(uint32_t max_ack_delay_ms) {
return max_ack_delay_ms_.SetSendValue(max_ack_delay_ms);
}
-uint32_t QuicConfig::GetMaxAckDelayToToSendMs() const {
+uint32_t QuicConfig::GetMaxAckDelayToSendMs() const {
return max_ack_delay_ms_.GetSendValue();
}
@@ -620,20 +621,20 @@ uint32_t QuicConfig::ReceivedAckDelayExponent() const {
return ack_delay_exponent_.GetReceivedValue();
}
-void QuicConfig::SetMaxPacketSizeToSend(uint64_t max_packet_size) {
- max_packet_size_.SetSendValue(max_packet_size);
+void QuicConfig::SetMaxPacketSizeToSend(uint64_t max_udp_payload_size) {
+ max_udp_payload_size_.SetSendValue(max_udp_payload_size);
}
uint64_t QuicConfig::GetMaxPacketSizeToSend() const {
- return max_packet_size_.GetSendValue();
+ return max_udp_payload_size_.GetSendValue();
}
bool QuicConfig::HasReceivedMaxPacketSize() const {
- return max_packet_size_.HasReceivedValue();
+ return max_udp_payload_size_.HasReceivedValue();
}
uint64_t QuicConfig::ReceivedMaxPacketSize() const {
- return max_packet_size_.GetReceivedValue();
+ return max_udp_payload_size_.GetReceivedValue();
}
void QuicConfig::SetMaxDatagramFrameSizeToSend(
@@ -832,6 +833,19 @@ bool QuicConfig::DisableConnectionMigration() const {
return connection_migration_disabled_.HasReceivedValue();
}
+void QuicConfig::SetSupportHandshakeDone() {
+ support_handshake_done_.SetSendValue(1);
+}
+
+bool QuicConfig::HandshakeDoneSupported() const {
+ return support_handshake_done_.HasSendValue() &&
+ support_handshake_done_.GetSendValue() > 0;
+}
+
+bool QuicConfig::PeerSupportsHandshakeDone() const {
+ return support_handshake_done_.HasReceivedValue();
+}
+
void QuicConfig::SetIPv6AlternateServerAddressToSend(
const QuicSocketAddress& alternate_server_address_ipv6) {
if (!alternate_server_address_ipv6.host().IsIPv6()) {
@@ -871,12 +885,13 @@ const QuicSocketAddress& QuicConfig::ReceivedIPv4AlternateServerAddress()
}
void QuicConfig::SetOriginalConnectionIdToSend(
- const QuicConnectionId& original_connection_id) {
- original_connection_id_to_send_ = original_connection_id;
+ const QuicConnectionId& original_destination_connection_id) {
+ original_destination_connection_id_to_send_ =
+ original_destination_connection_id;
}
bool QuicConfig::HasReceivedOriginalConnectionId() const {
- return received_original_connection_id_.has_value();
+ return received_original_destination_connection_id_.has_value();
}
QuicConnectionId QuicConfig::ReceivedOriginalConnectionId() const {
@@ -884,7 +899,41 @@ QuicConnectionId QuicConfig::ReceivedOriginalConnectionId() const {
QUIC_BUG << "No received original connection ID";
return EmptyQuicConnectionId();
}
- return received_original_connection_id_.value();
+ return received_original_destination_connection_id_.value();
+}
+
+void QuicConfig::SetInitialSourceConnectionIdToSend(
+ const QuicConnectionId& initial_source_connection_id) {
+ initial_source_connection_id_to_send_ = initial_source_connection_id;
+}
+
+bool QuicConfig::HasReceivedInitialSourceConnectionId() const {
+ return received_initial_source_connection_id_.has_value();
+}
+
+QuicConnectionId QuicConfig::ReceivedInitialSourceConnectionId() const {
+ if (!HasReceivedInitialSourceConnectionId()) {
+ QUIC_BUG << "No received initial source connection ID";
+ return EmptyQuicConnectionId();
+ }
+ return received_initial_source_connection_id_.value();
+}
+
+void QuicConfig::SetRetrySourceConnectionIdToSend(
+ const QuicConnectionId& retry_source_connection_id) {
+ retry_source_connection_id_to_send_ = retry_source_connection_id;
+}
+
+bool QuicConfig::HasReceivedRetrySourceConnectionId() const {
+ return received_retry_source_connection_id_.has_value();
+}
+
+QuicConnectionId QuicConfig::ReceivedRetrySourceConnectionId() const {
+ if (!HasReceivedRetrySourceConnectionId()) {
+ QUIC_BUG << "No received retry source connection ID";
+ return EmptyQuicConnectionId();
+ }
+ return received_retry_source_connection_id_.value();
}
void QuicConfig::SetStatelessResetTokenToSend(
@@ -938,14 +987,16 @@ void QuicConfig::ToHandshakeMessage(
// the one received. Additionally, when QUIC_CRYPTO is used, the server
// MUST send an idle timeout no greater than the idle timeout it received
// from the client. We therefore send the received value if it is lower.
- QuicFixedUint32 idle_timeout_seconds(kICSL, PRESENCE_REQUIRED);
- uint32_t idle_timeout_to_send_seconds = idle_timeout_to_send_.ToSeconds();
- if (received_idle_timeout_.has_value() &&
- received_idle_timeout_->ToSeconds() < idle_timeout_to_send_seconds) {
- idle_timeout_to_send_seconds = received_idle_timeout_->ToSeconds();
+ QuicFixedUint32 max_idle_timeout_seconds(kICSL, PRESENCE_REQUIRED);
+ uint32_t max_idle_timeout_to_send_seconds =
+ max_idle_timeout_to_send_.ToSeconds();
+ if (received_max_idle_timeout_.has_value() &&
+ received_max_idle_timeout_->ToSeconds() <
+ max_idle_timeout_to_send_seconds) {
+ max_idle_timeout_to_send_seconds = received_max_idle_timeout_->ToSeconds();
}
- idle_timeout_seconds.SetSendValue(idle_timeout_to_send_seconds);
- idle_timeout_seconds.ToHandshakeMessage(out);
+ max_idle_timeout_seconds.SetSendValue(max_idle_timeout_to_send_seconds);
+ max_idle_timeout_seconds.ToHandshakeMessage(out);
// Do not need a version check here, max...bi... will encode
// as "MIDS" -- the max initial dynamic streams tag -- if
@@ -955,8 +1006,15 @@ void QuicConfig::ToHandshakeMessage(
max_unidirectional_streams_.ToHandshakeMessage(out);
ack_delay_exponent_.ToHandshakeMessage(out);
}
- if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 1, 4);
+ if (GetQuicReloadableFlag(quic_dont_send_max_ack_delay_if_default)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_dont_send_max_ack_delay_if_default);
+ if (max_ack_delay_ms_.GetSendValue() != kDefaultDelayedAckTimeMs) {
+ // Only send max ack delay if it is using a non-default value, because
+ // the default value is used by QuicSentPacketManager if it is not
+ // sent during the handshake, and we want to save bytes.
+ max_ack_delay_ms_.ToHandshakeMessage(out);
+ }
+ } else {
max_ack_delay_ms_.ToHandshakeMessage(out);
}
bytes_for_connection_id_.ToHandshakeMessage(out);
@@ -986,12 +1044,12 @@ QuicErrorCode QuicConfig::ProcessPeerHello(
// the one received. Additionally, when QUIC_CRYPTO is used, the server
// MUST send an idle timeout no greater than the idle timeout it received
// from the client.
- QuicFixedUint32 idle_timeout_seconds(kICSL, PRESENCE_REQUIRED);
- error = idle_timeout_seconds.ProcessPeerHello(peer_hello, hello_type,
- error_details);
+ QuicFixedUint32 max_idle_timeout_seconds(kICSL, PRESENCE_REQUIRED);
+ error = max_idle_timeout_seconds.ProcessPeerHello(peer_hello, hello_type,
+ error_details);
if (error == QUIC_NO_ERROR) {
- if (idle_timeout_seconds.GetReceivedValue() >
- idle_timeout_to_send_.ToSeconds()) {
+ if (max_idle_timeout_seconds.GetReceivedValue() >
+ max_idle_timeout_to_send_.ToSeconds()) {
// The received value is higher than ours, ignore it if from the client
// and raise an error if from the server.
if (hello_type == SERVER) {
@@ -1000,8 +1058,8 @@ QuicErrorCode QuicConfig::ProcessPeerHello(
"Invalid value received for " + QuicTagToString(kICSL);
}
} else {
- received_idle_timeout_ = QuicTime::Delta::FromSeconds(
- idle_timeout_seconds.GetReceivedValue());
+ received_max_idle_timeout_ = QuicTime::Delta::FromSeconds(
+ max_idle_timeout_seconds.GetReceivedValue());
}
}
}
@@ -1056,9 +1114,7 @@ QuicErrorCode QuicConfig::ProcessPeerHello(
error_details);
}
- if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time) &&
- error == QUIC_NO_ERROR) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 2, 4);
+ if (error == QUIC_NO_ERROR) {
error = max_ack_delay_ms_.ProcessPeerHello(peer_hello, hello_type,
error_details);
}
@@ -1073,12 +1129,13 @@ QuicErrorCode QuicConfig::ProcessPeerHello(
}
bool QuicConfig::FillTransportParameters(TransportParameters* params) const {
- if (original_connection_id_to_send_.has_value()) {
- params->original_connection_id = original_connection_id_to_send_.value();
+ if (original_destination_connection_id_to_send_.has_value()) {
+ params->original_destination_connection_id =
+ original_destination_connection_id_to_send_.value();
}
- params->idle_timeout_milliseconds.set_value(
- idle_timeout_to_send_.ToMilliseconds());
+ params->max_idle_timeout_ms.set_value(
+ max_idle_timeout_to_send_.ToMilliseconds());
if (stateless_reset_token_.HasSendValue()) {
QuicUint128 stateless_reset_token = stateless_reset_token_.GetSendValue();
@@ -1088,7 +1145,7 @@ bool QuicConfig::FillTransportParameters(TransportParameters* params) const {
sizeof(stateless_reset_token));
}
- params->max_packet_size.set_value(GetMaxPacketSizeToSend());
+ params->max_udp_payload_size.set_value(GetMaxPacketSizeToSend());
params->max_datagram_frame_size.set_value(GetMaxDatagramFrameSizeToSend());
params->initial_max_data.set_value(
GetInitialSessionFlowControlWindowToSend());
@@ -1108,14 +1165,12 @@ bool QuicConfig::FillTransportParameters(TransportParameters* params) const {
GetMaxBidirectionalStreamsToSend());
params->initial_max_streams_uni.set_value(
GetMaxUnidirectionalStreamsToSend());
- if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 3, 4);
- params->max_ack_delay.set_value(kDefaultDelayedAckTimeMs);
- }
+ params->max_ack_delay.set_value(GetMaxAckDelayToSendMs());
params->ack_delay_exponent.set_value(GetAckDelayExponentToSend());
- params->disable_migration =
+ params->disable_active_migration =
connection_migration_disabled_.HasSendValue() &&
connection_migration_disabled_.GetSendValue() != 0;
+ params->support_handshake_done = HandshakeDoneSupported();
if (alternate_server_address_ipv6_.HasSendValue() ||
alternate_server_address_ipv4_.HasSendValue()) {
@@ -1138,6 +1193,16 @@ bool QuicConfig::FillTransportParameters(TransportParameters* params) const {
active_connection_id_limit_.GetSendValue());
}
+ if (initial_source_connection_id_to_send_.has_value()) {
+ params->initial_source_connection_id =
+ initial_source_connection_id_to_send_.value();
+ }
+
+ if (retry_source_connection_id_to_send_.has_value()) {
+ params->retry_source_connection_id =
+ retry_source_connection_id_to_send_.value();
+ }
+
if (GetQuicRestartFlag(quic_google_transport_param_send_new)) {
QUIC_RESTART_FLAG_COUNT_N(quic_google_transport_param_send_new, 1, 3);
if (initial_round_trip_time_us_.HasSendValue()) {
@@ -1171,18 +1236,19 @@ QuicErrorCode QuicConfig::ProcessTransportParameters(
HelloType hello_type,
bool is_resumption,
std::string* error_details) {
- if (!is_resumption && params.original_connection_id.has_value()) {
- received_original_connection_id_ = params.original_connection_id.value();
+ if (!is_resumption && params.original_destination_connection_id.has_value()) {
+ received_original_destination_connection_id_ =
+ params.original_destination_connection_id.value();
}
- if (params.idle_timeout_milliseconds.value() > 0 &&
- params.idle_timeout_milliseconds.value() <
- static_cast<uint64_t>(idle_timeout_to_send_.ToMilliseconds())) {
+ if (params.max_idle_timeout_ms.value() > 0 &&
+ params.max_idle_timeout_ms.value() <
+ static_cast<uint64_t>(max_idle_timeout_to_send_.ToMilliseconds())) {
// An idle timeout of zero indicates it is disabled.
// We also ignore values higher than ours which will cause us to use the
// smallest value between ours and our peer's.
- received_idle_timeout_ = QuicTime::Delta::FromMilliseconds(
- params.idle_timeout_milliseconds.value());
+ received_max_idle_timeout_ =
+ QuicTime::Delta::FromMilliseconds(params.max_idle_timeout_ms.value());
}
if (!is_resumption && !params.stateless_reset_token.empty()) {
@@ -1198,8 +1264,8 @@ QuicErrorCode QuicConfig::ProcessTransportParameters(
stateless_reset_token_.SetReceivedValue(stateless_reset_token);
}
- if (params.max_packet_size.IsValid()) {
- max_packet_size_.SetReceivedValue(params.max_packet_size.value());
+ if (params.max_udp_payload_size.IsValid()) {
+ max_udp_payload_size_.SetReceivedValue(params.max_udp_payload_size.value());
}
if (params.max_datagram_frame_size.IsValid()) {
@@ -1233,10 +1299,7 @@ QuicErrorCode QuicConfig::ProcessTransportParameters(
params.initial_max_stream_data_uni.value());
if (!is_resumption) {
- if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 4, 4);
- max_ack_delay_ms_.SetReceivedValue(params.max_ack_delay.value());
- }
+ max_ack_delay_ms_.SetReceivedValue(params.max_ack_delay.value());
if (params.ack_delay_exponent.IsValid()) {
ack_delay_exponent_.SetReceivedValue(params.ack_delay_exponent.value());
}
@@ -1252,13 +1315,27 @@ QuicErrorCode QuicConfig::ProcessTransportParameters(
}
}
- if (params.disable_migration) {
+ if (params.disable_active_migration) {
connection_migration_disabled_.SetReceivedValue(1u);
}
+ if (params.support_handshake_done) {
+ support_handshake_done_.SetReceivedValue(1u);
+ }
active_connection_id_limit_.SetReceivedValue(
params.active_connection_id_limit.value());
+ if (!is_resumption) {
+ if (params.initial_source_connection_id.has_value()) {
+ received_initial_source_connection_id_ =
+ params.initial_source_connection_id.value();
+ }
+ if (params.retry_source_connection_id.has_value()) {
+ received_retry_source_connection_id_ =
+ params.retry_source_connection_id.value();
+ }
+ }
+
bool google_params_already_parsed = false;
if (GetQuicRestartFlag(quic_google_transport_param_send_new)) {
QUIC_RESTART_FLAG_COUNT_N(quic_google_transport_param_send_new, 2, 3);
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_config.h b/chromium/net/third_party/quiche/src/quic/core/quic_config.h
index 4d2bacce383..6f041b82f45 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_config.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_config.h
@@ -382,6 +382,11 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
void SetDisableConnectionMigration();
bool DisableConnectionMigration() const;
+ // Support handshake done.
+ void SetSupportHandshakeDone();
+ bool HandshakeDoneSupported() const;
+ bool PeerSupportsHandshakeDone() const;
+
// IPv6 alternate server address.
void SetIPv6AlternateServerAddressToSend(
const QuicSocketAddress& alternate_server_address_ipv6);
@@ -394,9 +399,9 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
bool HasReceivedIPv4AlternateServerAddress() const;
const QuicSocketAddress& ReceivedIPv4AlternateServerAddress() const;
- // Original connection ID.
+ // Original destination connection ID.
void SetOriginalConnectionIdToSend(
- const QuicConnectionId& original_connection_id);
+ const QuicConnectionId& original_destination_connection_id);
bool HasReceivedOriginalConnectionId() const;
QuicConnectionId ReceivedOriginalConnectionId() const;
@@ -411,7 +416,7 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
// The received delay is the value received from
// the peer (QuicSentPacketManager::peer_max_ack_delay_).
void SetMaxAckDelayToSendMs(uint32_t max_ack_delay_ms);
- uint32_t GetMaxAckDelayToToSendMs() const;
+ uint32_t GetMaxAckDelayToSendMs() const;
bool HasReceivedMaxAckDelayMs() const;
uint32_t ReceivedMaxAckDelayMs() const;
@@ -420,8 +425,8 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
bool HasReceivedAckDelayExponent() const;
uint32_t ReceivedAckDelayExponent() const;
- // IETF QUIC max_packet_size transport parameter.
- void SetMaxPacketSizeToSend(uint64_t max_packet_size);
+ // IETF QUIC max_udp_payload_size transport parameter.
+ void SetMaxPacketSizeToSend(uint64_t max_udp_payload_size);
uint64_t GetMaxPacketSizeToSend() const;
bool HasReceivedMaxPacketSize() const;
uint64_t ReceivedMaxPacketSize() const;
@@ -438,6 +443,18 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
bool HasReceivedActiveConnectionIdLimit() const;
uint64_t ReceivedActiveConnectionIdLimit() const;
+ // Initial source connection ID.
+ void SetInitialSourceConnectionIdToSend(
+ const QuicConnectionId& initial_source_connection_id);
+ bool HasReceivedInitialSourceConnectionId() const;
+ QuicConnectionId ReceivedInitialSourceConnectionId() const;
+
+ // Retry source connection ID.
+ void SetRetrySourceConnectionIdToSend(
+ const QuicConnectionId& retry_source_connection_id);
+ bool HasReceivedRetrySourceConnectionId() const;
+ QuicConnectionId ReceivedRetrySourceConnectionId() const;
+
bool negotiated() const;
void SetCreateSessionTagIndicators(QuicTagVector tags);
@@ -501,12 +518,12 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
QuicFixedTagVector connection_options_;
// Connection options which only affect the client side.
QuicFixedTagVector client_connection_options_;
- // Idle network timeout.
+ // Maximum idle network timeout.
// Uses the max_idle_timeout transport parameter in IETF QUIC.
- // Note that received_idle_timeout_ is only populated if we receive the
+ // Note that received_max_idle_timeout_ is only populated if we receive the
// peer's value, which isn't guaranteed in IETF QUIC as sending is optional.
- QuicTime::Delta idle_timeout_to_send_;
- quiche::QuicheOptional<QuicTime::Delta> received_idle_timeout_;
+ QuicTime::Delta max_idle_timeout_to_send_;
+ quiche::QuicheOptional<QuicTime::Delta> received_max_idle_timeout_;
// Maximum number of dynamic streams that a Google QUIC connection
// can support or the maximum number of bidirectional streams that
// an IETF QUIC connection can support.
@@ -554,6 +571,10 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
// Uses the disable_active_migration transport parameter in IETF QUIC.
QuicFixedUint32 connection_migration_disabled_;
+ // Whether handshake done is supported. Only used in T050.
+ // Uses the support_handshake_done transport parameter in IETF QUIC.
+ QuicFixedUint32 support_handshake_done_;
+
// Alternate server addresses the client could connect to.
// Uses the preferred_address transport parameter in IETF QUIC.
// Note that when QUIC_CRYPTO is in use, only one of the addresses is sent.
@@ -583,8 +604,8 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
QuicFixedUint32 ack_delay_exponent_;
// Maximum packet size in bytes.
- // Uses the max_packet_size transport parameter in IETF QUIC.
- QuicFixedUint62 max_packet_size_;
+ // Uses the max_udp_payload_size transport parameter in IETF QUIC.
+ QuicFixedUint62 max_udp_payload_size_;
// Maximum DATAGRAM/MESSAGE frame size in bytes.
// Uses the max_datagram_frame_size transport parameter in IETF QUIC.
@@ -594,10 +615,28 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
// Uses the active_connection_id_limit transport parameter in IETF QUIC.
QuicFixedUint62 active_connection_id_limit_;
- // Sent by the server when it has previously sent a RETRY packet.
- // Uses the original_connection_id transport parameter in IETF QUIC.
- quiche::QuicheOptional<QuicConnectionId> original_connection_id_to_send_;
- quiche::QuicheOptional<QuicConnectionId> received_original_connection_id_;
+ // The value of the Destination Connection ID field from the first
+ // Initial packet sent by the client.
+ // Uses the original_destination_connection_id transport parameter in
+ // IETF QUIC.
+ quiche::QuicheOptional<QuicConnectionId>
+ original_destination_connection_id_to_send_;
+ quiche::QuicheOptional<QuicConnectionId>
+ received_original_destination_connection_id_;
+
+ // The value that the endpoint included in the Source Connection ID field of
+ // the first Initial packet it sent.
+ // Uses the initial_source_connection_id transport parameter in IETF QUIC.
+ quiche::QuicheOptional<QuicConnectionId>
+ initial_source_connection_id_to_send_;
+ quiche::QuicheOptional<QuicConnectionId>
+ received_initial_source_connection_id_;
+
+ // The value that the server included in the Source Connection ID field of a
+ // Retry packet it sent.
+ // Uses the retry_source_connection_id transport parameter in IETF QUIC.
+ quiche::QuicheOptional<QuicConnectionId> retry_source_connection_id_to_send_;
+ quiche::QuicheOptional<QuicConnectionId> received_retry_source_connection_id_;
// Custom transport parameters that can be sent and received in the TLS
// handshake.
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc
index 4aa10ef40b0..050a091a8d2 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc
@@ -180,12 +180,8 @@ TEST_P(QuicConfigTest, ProcessClientHello) {
2 * kInitialStreamFlowControlWindowForTest);
EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(),
2 * kInitialSessionFlowControlWindowForTest);
- if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
- EXPECT_TRUE(config_.HasReceivedMaxAckDelayMs());
- EXPECT_EQ(kTestMaxAckDelayMs, config_.ReceivedMaxAckDelayMs());
- } else {
- EXPECT_FALSE(config_.HasReceivedMaxAckDelayMs());
- }
+ EXPECT_TRUE(config_.HasReceivedMaxAckDelayMs());
+ EXPECT_EQ(kTestMaxAckDelayMs, config_.ReceivedMaxAckDelayMs());
// IETF QUIC stream limits should not be received in QUIC crypto messages.
EXPECT_FALSE(
@@ -238,12 +234,8 @@ TEST_P(QuicConfigTest, ProcessServerHello) {
EXPECT_FALSE(config_.HasReceivedIPv6AlternateServerAddress());
EXPECT_TRUE(config_.HasReceivedStatelessResetToken());
EXPECT_EQ(kTestResetToken, config_.ReceivedStatelessResetToken());
- if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
- EXPECT_TRUE(config_.HasReceivedMaxAckDelayMs());
- EXPECT_EQ(kTestMaxAckDelayMs, config_.ReceivedMaxAckDelayMs());
- } else {
- EXPECT_FALSE(config_.HasReceivedMaxAckDelayMs());
- }
+ EXPECT_TRUE(config_.HasReceivedMaxAckDelayMs());
+ EXPECT_EQ(kTestMaxAckDelayMs, config_.ReceivedMaxAckDelayMs());
// IETF QUIC stream limits should not be received in QUIC crypto messages.
EXPECT_FALSE(
@@ -442,7 +434,7 @@ TEST_P(QuicConfigTest, IncomingLargeIdleTimeoutTransportParameter) {
// Since the received value is above ours, we should then use ours.
config_.SetIdleNetworkTimeout(quic::QuicTime::Delta::FromSeconds(60));
TransportParameters params;
- params.idle_timeout_milliseconds.set_value(120000);
+ params.max_idle_timeout_ms.set_value(120000);
std::string error_details = "foobar";
EXPECT_THAT(config_.ProcessTransportParameters(
@@ -468,6 +460,10 @@ TEST_P(QuicConfigTest, FillTransportParams) {
config_.SetMaxDatagramFrameSizeToSend(kMaxDatagramFrameSizeForTest);
config_.SetActiveConnectionIdLimitToSend(kFakeActiveConnectionIdLimit);
+ config_.SetOriginalConnectionIdToSend(TestConnectionId(0x1111));
+ config_.SetInitialSourceConnectionIdToSend(TestConnectionId(0x2222));
+ config_.SetRetrySourceConnectionIdToSend(TestConnectionId(0x3333));
+
TransportParameters params;
config_.FillTransportParameters(&params);
@@ -479,13 +475,23 @@ TEST_P(QuicConfigTest, FillTransportParams) {
params.initial_max_stream_data_uni.value());
EXPECT_EQ(static_cast<uint64_t>(kMaximumIdleTimeoutSecs * 1000),
- params.idle_timeout_milliseconds.value());
+ params.max_idle_timeout_ms.value());
- EXPECT_EQ(kMaxPacketSizeForTest, params.max_packet_size.value());
+ EXPECT_EQ(kMaxPacketSizeForTest, params.max_udp_payload_size.value());
EXPECT_EQ(kMaxDatagramFrameSizeForTest,
params.max_datagram_frame_size.value());
EXPECT_EQ(kFakeActiveConnectionIdLimit,
params.active_connection_id_limit.value());
+
+ ASSERT_TRUE(params.original_destination_connection_id.has_value());
+ EXPECT_EQ(TestConnectionId(0x1111),
+ params.original_destination_connection_id.value());
+ ASSERT_TRUE(params.initial_source_connection_id.has_value());
+ EXPECT_EQ(TestConnectionId(0x2222),
+ params.initial_source_connection_id.value());
+ ASSERT_TRUE(params.retry_source_connection_id.has_value());
+ EXPECT_EQ(TestConnectionId(0x3333),
+ params.retry_source_connection_id.value());
}
TEST_P(QuicConfigTest, ProcessTransportParametersServer) {
@@ -493,7 +499,6 @@ TEST_P(QuicConfigTest, ProcessTransportParametersServer) {
// TransportParameters are only used for QUIC+TLS.
return;
}
- SetQuicReloadableFlag(quic_negotiate_ack_delay_time, true);
TransportParameters params;
params.initial_max_stream_data_bidi_local.set_value(
@@ -502,13 +507,16 @@ TEST_P(QuicConfigTest, ProcessTransportParametersServer) {
3 * kMinimumFlowControlSendWindow);
params.initial_max_stream_data_uni.set_value(4 *
kMinimumFlowControlSendWindow);
- params.max_packet_size.set_value(kMaxPacketSizeForTest);
+ params.max_udp_payload_size.set_value(kMaxPacketSizeForTest);
params.max_datagram_frame_size.set_value(kMaxDatagramFrameSizeForTest);
params.initial_max_streams_bidi.set_value(kDefaultMaxStreamsPerConnection);
params.stateless_reset_token = CreateFakeStatelessResetToken();
params.max_ack_delay.set_value(kFakeMaxAckDelay);
params.ack_delay_exponent.set_value(kFakeAckDelayExponent);
params.active_connection_id_limit.set_value(kFakeActiveConnectionIdLimit);
+ params.original_destination_connection_id = TestConnectionId(0x1111);
+ params.initial_source_connection_id = TestConnectionId(0x2222);
+ params.retry_source_connection_id = TestConnectionId(0x3333);
std::string error_details;
EXPECT_THAT(config_.ProcessTransportParameters(
@@ -544,11 +552,15 @@ TEST_P(QuicConfigTest, ProcessTransportParametersServer) {
config_.ReceivedMaxBidirectionalStreams());
EXPECT_FALSE(config_.DisableConnectionMigration());
+ EXPECT_FALSE(config_.PeerSupportsHandshakeDone());
// The following config shouldn't be processed because of resumption.
EXPECT_FALSE(config_.HasReceivedStatelessResetToken());
EXPECT_FALSE(config_.HasReceivedMaxAckDelayMs());
EXPECT_FALSE(config_.HasReceivedAckDelayExponent());
+ EXPECT_FALSE(config_.HasReceivedOriginalConnectionId());
+ EXPECT_FALSE(config_.HasReceivedInitialSourceConnectionId());
+ EXPECT_FALSE(config_.HasReceivedRetrySourceConnectionId());
// Let the config process another slightly tweaked transport paramters.
// Note that the values for flow control and stream limit cannot be smaller
@@ -559,11 +571,12 @@ TEST_P(QuicConfigTest, ProcessTransportParametersServer) {
4 * kMinimumFlowControlSendWindow);
params.initial_max_stream_data_uni.set_value(5 *
kMinimumFlowControlSendWindow);
- params.max_packet_size.set_value(2 * kMaxPacketSizeForTest);
+ params.max_udp_payload_size.set_value(2 * kMaxPacketSizeForTest);
params.max_datagram_frame_size.set_value(2 * kMaxDatagramFrameSizeForTest);
params.initial_max_streams_bidi.set_value(2 *
kDefaultMaxStreamsPerConnection);
- params.disable_migration = true;
+ params.disable_active_migration = true;
+ params.support_handshake_done = true;
EXPECT_THAT(config_.ProcessTransportParameters(
params, SERVER, /* is_resumption = */ false, &error_details),
@@ -598,6 +611,7 @@ TEST_P(QuicConfigTest, ProcessTransportParametersServer) {
config_.ReceivedMaxBidirectionalStreams());
EXPECT_TRUE(config_.DisableConnectionMigration());
+ EXPECT_TRUE(config_.PeerSupportsHandshakeDone());
ASSERT_TRUE(config_.HasReceivedStatelessResetToken());
ASSERT_TRUE(config_.HasReceivedMaxAckDelayMs());
@@ -609,6 +623,15 @@ TEST_P(QuicConfigTest, ProcessTransportParametersServer) {
ASSERT_TRUE(config_.HasReceivedActiveConnectionIdLimit());
EXPECT_EQ(config_.ReceivedActiveConnectionIdLimit(),
kFakeActiveConnectionIdLimit);
+
+ ASSERT_TRUE(config_.HasReceivedOriginalConnectionId());
+ EXPECT_EQ(config_.ReceivedOriginalConnectionId(), TestConnectionId(0x1111));
+ ASSERT_TRUE(config_.HasReceivedInitialSourceConnectionId());
+ EXPECT_EQ(config_.ReceivedInitialSourceConnectionId(),
+ TestConnectionId(0x2222));
+ ASSERT_TRUE(config_.HasReceivedRetrySourceConnectionId());
+ EXPECT_EQ(config_.ReceivedRetrySourceConnectionId(),
+ TestConnectionId(0x3333));
}
TEST_P(QuicConfigTest, DisableMigrationTransportParameter) {
@@ -617,7 +640,7 @@ TEST_P(QuicConfigTest, DisableMigrationTransportParameter) {
return;
}
TransportParameters params;
- params.disable_migration = true;
+ params.disable_active_migration = true;
std::string error_details;
EXPECT_THAT(config_.ProcessTransportParameters(
params, SERVER, /* is_resumption = */ false, &error_details),
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc
index 4f089a44fe9..4a21277e942 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc
@@ -25,6 +25,7 @@
#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
#include "net/third_party/quiche/src/quic/core/quic_constants.h"
#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
@@ -33,6 +34,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_exported_stats.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_utils.h"
@@ -107,20 +109,6 @@ class SendAlarmDelegate : public QuicAlarm::Delegate {
QuicConnection* connection_;
};
-class PathDegradingAlarmDelegate : public QuicAlarm::Delegate {
- public:
- explicit PathDegradingAlarmDelegate(QuicConnection* connection)
- : connection_(connection) {}
- PathDegradingAlarmDelegate(const PathDegradingAlarmDelegate&) = delete;
- PathDegradingAlarmDelegate& operator=(const PathDegradingAlarmDelegate&) =
- delete;
-
- void OnAlarm() override { connection_->OnPathDegradingTimeout(); }
-
- private:
- QuicConnection* connection_;
-};
-
class TimeoutAlarmDelegate : public QuicAlarm::Delegate {
public:
explicit TimeoutAlarmDelegate(QuicConnection* connection)
@@ -260,7 +248,7 @@ QuicConnection::QuicConnection(
send_version_negotiation_packet_with_prefixed_lengths_(false),
idle_timeout_connection_close_behavior_(
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET),
- close_connection_after_five_rtos_(false),
+ num_rtos_for_blackhole_detection_(0),
uber_received_packet_manager_(&stats_),
stop_waiting_count_(0),
pending_retransmission_alarm_(false),
@@ -327,7 +315,6 @@ QuicConnection::QuicConnection(
supports_release_time_(false),
release_time_into_future_(QuicTime::Delta::Zero()),
drop_incoming_retry_packets_(false),
- max_consecutive_ptos_(0),
bytes_received_before_address_validation_(0),
bytes_sent_before_address_validation_(0),
address_validated_(false),
@@ -335,7 +322,8 @@ QuicConnection::QuicConnection(
idle_network_detector_(this,
clock_->ApproximateNow(),
&arena_,
- alarm_factory_) {
+ alarm_factory_),
+ support_handshake_done_(version().HasHandshakeDone()) {
QUIC_DLOG(INFO) << ENDPOINT << "Created connection with server connection ID "
<< server_connection_id
<< " and version: " << ParsedQuicVersionToString(version());
@@ -345,9 +333,6 @@ QuicConnection::QuicConnection(
<< "QuicConnection: attempted to use server connection ID "
<< server_connection_id << " which is invalid with version "
<< QuicVersionToString(transport_version());
- if (advance_ack_timeout_update_) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_advance_ack_timeout_update);
- }
framer_.set_visitor(this);
stats_.connection_creation_time = clock_->ApproximateNow();
// TODO(ianswett): Supply the NetworkChangeVisitor as a constructor argument
@@ -377,6 +362,9 @@ QuicConnection::QuicConnection(
if (perspective_ == Perspective::IS_SERVER) {
SetVersionNegotiated();
}
+ if (default_enable_5rto_blackhole_detection_) {
+ num_rtos_for_blackhole_detection_ = 5;
+ }
}
void QuicConnection::InstallInitialCrypters(QuicConnectionId connection_id) {
@@ -402,50 +390,158 @@ void QuicConnection::ClearQueuedPackets() {
buffered_packets_.clear();
}
-void QuicConnection::SetFromConfig(const QuicConfig& config) {
- if (config.negotiated()) {
- // Handshake complete, set handshake timeout to Infinite.
- SetNetworkTimeouts(QuicTime::Delta::Infinite(),
- config.IdleNetworkTimeout());
- idle_timeout_connection_close_behavior_ =
- ConnectionCloseBehavior::SILENT_CLOSE;
- if (original_connection_id_.has_value()) {
- DCHECK_EQ(perspective_, Perspective::IS_CLIENT);
- // We received a RETRY packet, validate that the |original_connection_id|
- // from the config matches the one from the RETRY.
- if (!config.HasReceivedOriginalConnectionId() ||
- config.ReceivedOriginalConnectionId() !=
- original_connection_id_.value()) {
+bool QuicConnection::ValidateConfigConnectionIdsOld(const QuicConfig& config) {
+ // This function validates connection IDs as defined in IETF draft-27 and
+ // earlier.
+ DCHECK(config.negotiated());
+ DCHECK(!version().AuthenticatesHandshakeConnectionIds());
+ if (original_destination_connection_id_.has_value() &&
+ retry_source_connection_id_.has_value()) {
+ DCHECK_EQ(perspective_, Perspective::IS_CLIENT);
+ // We received a RETRY packet, validate that the original destination
+ // connection ID from the config matches the one from the RETRY.
+ if (!config.HasReceivedOriginalConnectionId() ||
+ config.ReceivedOriginalConnectionId() !=
+ original_destination_connection_id_.value()) {
+ std::string received_value;
+ if (config.HasReceivedOriginalConnectionId()) {
+ received_value = config.ReceivedOriginalConnectionId().ToString();
+ } else {
+ received_value = "none";
+ }
+ std::string error_details = quiche::QuicheStrCat(
+ "Bad original_connection_id: expected ",
+ original_destination_connection_id_.value().ToString(), ", received ",
+ received_value, ", RETRY used ", server_connection_id_.ToString());
+ CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION, error_details,
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+ } else {
+ // We did not receive a RETRY packet, make sure we did not receive the
+ // original_destination_connection_id transport parameter.
+ if (config.HasReceivedOriginalConnectionId()) {
+ std::string error_details = quiche::QuicheStrCat(
+ "Bad original_connection_id: did not receive RETRY but received ",
+ config.ReceivedOriginalConnectionId().ToString());
+ CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION, error_details,
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool QuicConnection::ValidateConfigConnectionIds(const QuicConfig& config) {
+ DCHECK(config.negotiated());
+ if (!version().UsesTls()) {
+ // QUIC+TLS is required to transmit connection ID transport parameters.
+ return true;
+ }
+ if (!version().AuthenticatesHandshakeConnectionIds()) {
+ return ValidateConfigConnectionIdsOld(config);
+ }
+ // This function validates connection IDs as defined in IETF draft-28 and
+ // later.
+
+ // Validate initial_source_connection_id.
+ QuicConnectionId expected_initial_source_connection_id;
+ if (perspective_ == Perspective::IS_CLIENT) {
+ expected_initial_source_connection_id = server_connection_id_;
+ } else {
+ expected_initial_source_connection_id = client_connection_id_;
+ }
+ if (!config.HasReceivedInitialSourceConnectionId() ||
+ config.ReceivedInitialSourceConnectionId() !=
+ expected_initial_source_connection_id) {
+ std::string received_value;
+ if (config.HasReceivedInitialSourceConnectionId()) {
+ received_value = config.ReceivedInitialSourceConnectionId().ToString();
+ } else {
+ received_value = "none";
+ }
+ std::string error_details =
+ quiche::QuicheStrCat("Bad initial_source_connection_id: expected ",
+ expected_initial_source_connection_id.ToString(),
+ ", received ", received_value);
+ CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION, error_details,
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+ if (perspective_ == Perspective::IS_CLIENT) {
+ // Validate original_destination_connection_id.
+ if (!config.HasReceivedOriginalConnectionId() ||
+ config.ReceivedOriginalConnectionId() !=
+ GetOriginalDestinationConnectionId()) {
+ std::string received_value;
+ if (config.HasReceivedOriginalConnectionId()) {
+ received_value = config.ReceivedOriginalConnectionId().ToString();
+ } else {
+ received_value = "none";
+ }
+ std::string error_details = quiche::QuicheStrCat(
+ "Bad original_destination_connection_id: expected ",
+ GetOriginalDestinationConnectionId().ToString(), ", received ",
+ received_value);
+ CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION, error_details,
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+ // Validate retry_source_connection_id.
+ if (retry_source_connection_id_.has_value()) {
+ // We received a RETRY packet, validate that the retry source
+ // connection ID from the config matches the one from the RETRY.
+ if (!config.HasReceivedRetrySourceConnectionId() ||
+ config.ReceivedRetrySourceConnectionId() !=
+ retry_source_connection_id_.value()) {
std::string received_value;
- if (config.HasReceivedOriginalConnectionId()) {
- received_value = config.ReceivedOriginalConnectionId().ToString();
+ if (config.HasReceivedRetrySourceConnectionId()) {
+ received_value = config.ReceivedRetrySourceConnectionId().ToString();
} else {
received_value = "none";
}
- std::string error_details = quiche::QuicheStrCat(
- "Bad original_connection_id: expected ",
- original_connection_id_.value().ToString(), ", received ",
- received_value, ", RETRY used ", server_connection_id_.ToString());
+ std::string error_details =
+ quiche::QuicheStrCat("Bad retry_source_connection_id: expected ",
+ retry_source_connection_id_.value().ToString(),
+ ", received ", received_value);
CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION, error_details,
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
+ return false;
}
} else {
// We did not receive a RETRY packet, make sure we did not receive the
- // original_connection_id transport parameter.
- if (config.HasReceivedOriginalConnectionId()) {
+ // retry_source_connection_id transport parameter.
+ if (config.HasReceivedRetrySourceConnectionId()) {
std::string error_details = quiche::QuicheStrCat(
- "Bad original_connection_id: did not receive RETRY but received ",
- config.ReceivedOriginalConnectionId().ToString());
+ "Bad retry_source_connection_id: did not receive RETRY but "
+ "received ",
+ config.ReceivedRetrySourceConnectionId().ToString());
CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION, error_details,
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
+ return false;
}
}
+ }
+ return true;
+}
+
+void QuicConnection::SetFromConfig(const QuicConfig& config) {
+ if (config.negotiated()) {
+ // Handshake complete, set handshake timeout to Infinite.
+ SetNetworkTimeouts(QuicTime::Delta::Infinite(),
+ config.IdleNetworkTimeout());
+ idle_timeout_connection_close_behavior_ =
+ ConnectionCloseBehavior::SILENT_CLOSE;
+ if (!ValidateConfigConnectionIds(config)) {
+ return;
+ }
} else {
SetNetworkTimeouts(config.max_time_before_crypto_handshake(),
config.max_idle_time_before_crypto_handshake());
}
+ if (config.HandshakeDoneSupported()) {
+ support_handshake_done_ = true;
+ }
sent_packet_manager_.SetFromConfig(config);
if (config.HasReceivedBytesForConnectionId() &&
@@ -461,24 +557,41 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
if (config.HasClientRequestedIndependentOption(kMTUL, perspective_)) {
SetMtuDiscoveryTarget(kMtuDiscoveryTargetPacketSizeLow);
}
+ if (default_enable_5rto_blackhole_detection_) {
+ if (config.HasClientRequestedIndependentOption(kCBHD, perspective_)) {
+ QUIC_CODE_COUNT(quic_client_only_blackhole_detection);
+ blackhole_detection_disabled_ = true;
+ }
+ if (config.HasClientSentConnectionOption(k2RTO, perspective_)) {
+ QUIC_CODE_COUNT(quic_2rto_blackhole_detection);
+ num_rtos_for_blackhole_detection_ = 2;
+ }
+ if (config.HasClientSentConnectionOption(k3RTO, perspective_)) {
+ QUIC_CODE_COUNT(quic_3rto_blackhole_detection);
+ num_rtos_for_blackhole_detection_ = 3;
+ }
+ if (config.HasClientSentConnectionOption(k4RTO, perspective_)) {
+ QUIC_CODE_COUNT(quic_4rto_blackhole_detection);
+ num_rtos_for_blackhole_detection_ = 4;
+ }
+ if (config.HasClientSentConnectionOption(k6RTO, perspective_)) {
+ QUIC_CODE_COUNT(quic_6rto_blackhole_detection);
+ num_rtos_for_blackhole_detection_ = 6;
+ }
+ }
if (debug_visitor_ != nullptr) {
debug_visitor_->OnSetFromConfig(config);
}
uber_received_packet_manager_.SetFromConfig(config, perspective_);
if (config.HasClientSentConnectionOption(k5RTO, perspective_)) {
- close_connection_after_five_rtos_ = true;
+ num_rtos_for_blackhole_detection_ = 5;
}
if (sent_packet_manager_.pto_enabled()) {
- if (config.HasClientSentConnectionOption(k6PTO, perspective_)) {
- max_consecutive_ptos_ = 5;
- QUIC_CODE_COUNT(quic_close_connection_6pto);
- }
- if (config.HasClientSentConnectionOption(k7PTO, perspective_)) {
- max_consecutive_ptos_ = 6;
- }
- if (config.HasClientSentConnectionOption(k8PTO, perspective_)) {
- max_consecutive_ptos_ = 7;
+ if (config.HasClientSentConnectionOption(k6PTO, perspective_) ||
+ config.HasClientSentConnectionOption(k7PTO, perspective_) ||
+ config.HasClientSentConnectionOption(k8PTO, perspective_)) {
+ num_rtos_for_blackhole_detection_ = 5;
}
}
if (config.HasClientSentConnectionOption(kNSTP, perspective_)) {
@@ -502,8 +615,7 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
}
if (config.HasReceivedMaxPacketSize()) {
peer_max_packet_size_ = config.ReceivedMaxPacketSize();
- packet_creator_.SetMaxPacketLength(
- GetLimitedMaxPacketSize(packet_creator_.max_packet_length()));
+ MaybeUpdatePacketCreatorMaxPacketLengthAndPadding();
}
if (config.HasReceivedMaxDatagramFrameSize()) {
packet_creator_.SetMaxDatagramFrameSize(
@@ -519,6 +631,29 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
}
}
+void QuicConnection::EnableLegacyVersionEncapsulation(
+ const std::string& server_name) {
+ if (perspective_ != Perspective::IS_CLIENT) {
+ QUIC_BUG << "Cannot enable Legacy Version Encapsulation on the server";
+ return;
+ }
+ if (legacy_version_encapsulation_enabled_) {
+ QUIC_BUG << "Do not call EnableLegacyVersionEncapsulation twice";
+ return;
+ }
+ if (!QuicHostnameUtils::IsValidSNI(server_name)) {
+ // Legacy Version Encapsulation is only used when SNI is transmitted.
+ QUIC_DLOG(INFO)
+ << "Refusing to use Legacy Version Encapsulation with invalid SNI \""
+ << server_name << "\"";
+ return;
+ }
+ QUIC_DLOG(INFO) << "Enabling Legacy Version Encapsulation with SNI \""
+ << server_name << "\"";
+ legacy_version_encapsulation_enabled_ = true;
+ legacy_version_encapsulation_sni_ = server_name;
+}
+
void QuicConnection::ApplyConnectionOptions(
const QuicTagVector& connection_options) {
sent_packet_manager_.ApplyConnectionOptions(connection_options);
@@ -605,6 +740,7 @@ void QuicConnection::OnPublicResetPacket(const QuicPublicResetPacket& packet) {
// here. (Check for a bug regression.)
DCHECK_EQ(server_connection_id_, packet.connection_id);
DCHECK_EQ(perspective_, Perspective::IS_CLIENT);
+ DCHECK(!VersionHasIetfInvariantHeader(transport_version()));
if (debug_visitor_ != nullptr) {
debug_visitor_->OnPublicResetPacket(packet);
}
@@ -718,8 +854,12 @@ void QuicConnection::OnRetryPacket(
<< server_connection_id_ << " with " << new_connection_id
<< ", received token "
<< quiche::QuicheTextUtils::HexEncode(retry_token);
- DCHECK(!original_connection_id_.has_value());
- original_connection_id_ = server_connection_id_;
+ if (!original_destination_connection_id_.has_value()) {
+ original_destination_connection_id_ = server_connection_id_;
+ }
+ DCHECK(!retry_source_connection_id_.has_value())
+ << retry_source_connection_id_.value();
+ retry_source_connection_id_ = new_connection_id;
server_connection_id_ = new_connection_id;
packet_creator_.SetServerConnectionId(server_connection_id_);
packet_creator_.SetRetryToken(retry_token);
@@ -738,11 +878,27 @@ bool QuicConnection::HasIncomingConnectionId(QuicConnectionId connection_id) {
return false;
}
-void QuicConnection::AddIncomingConnectionId(QuicConnectionId connection_id) {
- if (HasIncomingConnectionId(connection_id)) {
- return;
+void QuicConnection::SetOriginalDestinationConnectionId(
+ const QuicConnectionId& original_destination_connection_id) {
+ QUIC_DLOG(INFO) << "Setting original_destination_connection_id to "
+ << original_destination_connection_id
+ << " on connection with server_connection_id "
+ << server_connection_id_;
+ DCHECK_NE(original_destination_connection_id, server_connection_id_);
+ if (!HasIncomingConnectionId(original_destination_connection_id)) {
+ incoming_connection_ids_.push_back(original_destination_connection_id);
+ }
+ InstallInitialCrypters(original_destination_connection_id);
+ DCHECK(!original_destination_connection_id_.has_value())
+ << original_destination_connection_id_.value();
+ original_destination_connection_id_ = original_destination_connection_id;
+}
+
+QuicConnectionId QuicConnection::GetOriginalDestinationConnectionId() {
+ if (original_destination_connection_id_.has_value()) {
+ return original_destination_connection_id_.value();
}
- incoming_connection_ids_.push_back(connection_id);
+ return server_connection_id_;
}
bool QuicConnection::OnUnauthenticatedPublicHeader(
@@ -841,6 +997,35 @@ void QuicConnection::OnSuccessfulVersionNegotiation() {
}
}
+void QuicConnection::OnSuccessfulMigrationAfterProbing() {
+ DCHECK_EQ(perspective_, Perspective::IS_CLIENT);
+ if (IsPathDegrading()) {
+ // If path was previously degrading, and migration is successful after
+ // probing, restart the path degrading and blackhole detection.
+ OnForwardProgressMade();
+ }
+ // TODO(b/159074035): notify SentPacketManger with RTT sample from probing and
+ // reset cwnd if this is a successful network migration.
+}
+
+void QuicConnection::OnTransportParametersSent(
+ const TransportParameters& transport_parameters) const {
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnTransportParametersSent(transport_parameters);
+ }
+}
+
+void QuicConnection::OnTransportParametersReceived(
+ const TransportParameters& transport_parameters) const {
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnTransportParametersReceived(transport_parameters);
+ }
+}
+
+bool QuicConnection::HasPendingAcks() const {
+ return ack_alarm_->IsSet();
+}
+
void QuicConnection::OnDecryptedPacket(EncryptionLevel level) {
last_decrypted_packet_level_ = level;
last_packet_decrypted_ = true;
@@ -849,13 +1034,10 @@ void QuicConnection::OnDecryptedPacket(EncryptionLevel level) {
// Address is validated by successfully processing a HANDSHAKE packet.
address_validated_ = true;
}
- if (extend_idle_time_on_decryptable_packets_) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_extend_idle_time_on_decryptable_packets);
- if (use_idle_network_detector_) {
- idle_network_detector_.OnPacketReceived(time_of_last_received_packet_);
- } else {
- time_of_last_decryptable_packet_ = time_of_last_received_packet_;
- }
+ if (use_idle_network_detector_) {
+ idle_network_detector_.OnPacketReceived(time_of_last_received_packet_);
+ } else {
+ time_of_last_decryptable_packet_ = time_of_last_received_packet_;
}
visitor_->OnPacketDecrypted(level);
@@ -923,6 +1105,9 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
--stats_.packets_dropped;
QUIC_DVLOG(1) << ENDPOINT << "Received packet header: " << header;
last_header_ = header;
+ if (!stats_.first_decrypted_packet.IsInitialized()) {
+ stats_.first_decrypted_packet = last_header_.packet_number;
+ }
// Record packet receipt to populate ack info before processing stream
// frames, since the processing may result in sending a bundled ack.
@@ -962,14 +1147,9 @@ bool QuicConnection::OnStreamFrame(const QuicStreamFrame& frame) {
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return false;
}
- if (advance_ack_timeout_update_) {
- MaybeUpdateAckTimeout();
- }
+ MaybeUpdateAckTimeout();
visitor_->OnStreamFrame(frame);
stats_.stream_bytes_received += frame.data_length;
- if (!advance_ack_timeout_update_) {
- should_last_packet_instigate_acks_ = true;
- }
consecutive_retransmittable_on_wire_ping_count_ = 0;
return connected_;
}
@@ -984,13 +1164,8 @@ bool QuicConnection::OnCryptoFrame(const QuicCryptoFrame& frame) {
if (debug_visitor_ != nullptr) {
debug_visitor_->OnCryptoFrame(frame);
}
- if (advance_ack_timeout_update_) {
- MaybeUpdateAckTimeout();
- }
+ MaybeUpdateAckTimeout();
visitor_->OnCryptoFrame(frame);
- if (!advance_ack_timeout_update_) {
- should_last_packet_instigate_acks_ = true;
- }
return connected_;
}
@@ -1032,11 +1207,6 @@ bool QuicConnection::OnAckFrameStart(QuicPacketNumber largest_acked,
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return false;
}
-
- if (!GetLargestAckedPacket().IsInitialized() ||
- largest_acked > GetLargestAckedPacket()) {
- visitor_->OnForwardProgressConfirmed();
- }
processing_ack_frame_ = true;
sent_packet_manager_.OnAckFrameStart(largest_acked, ack_delay_time,
GetTimeOfLastReceivedPacket());
@@ -1177,11 +1347,7 @@ bool QuicConnection::OnPingFrame(const QuicPingFrame& frame) {
if (debug_visitor_ != nullptr) {
debug_visitor_->OnPingFrame(frame);
}
- if (advance_ack_timeout_update_) {
- MaybeUpdateAckTimeout();
- } else {
- should_last_packet_instigate_acks_ = true;
- }
+ MaybeUpdateAckTimeout();
return true;
}
@@ -1223,13 +1389,8 @@ bool QuicConnection::OnRstStreamFrame(const QuicRstStreamFrame& frame) {
<< "RST_STREAM_FRAME received for stream: " << frame.stream_id
<< " with error: "
<< QuicRstStreamErrorCodeToString(frame.error_code);
- if (advance_ack_timeout_update_) {
- MaybeUpdateAckTimeout();
- }
+ MaybeUpdateAckTimeout();
visitor_->OnRstStream(frame);
- if (!advance_ack_timeout_update_) {
- should_last_packet_instigate_acks_ = true;
- }
return connected_;
}
@@ -1260,11 +1421,7 @@ bool QuicConnection::OnPathChallengeFrame(const QuicPathChallengeFrame& frame) {
// response.
received_path_challenge_payloads_.push_back(frame.data_buffer);
- if (advance_ack_timeout_update_) {
- MaybeUpdateAckTimeout();
- } else {
- should_last_packet_instigate_acks_ = true;
- }
+ MaybeUpdateAckTimeout();
return true;
}
@@ -1272,11 +1429,7 @@ bool QuicConnection::OnPathResponseFrame(const QuicPathResponseFrame& frame) {
if (debug_visitor_ != nullptr) {
debug_visitor_->OnPathResponseFrame(frame);
}
- if (advance_ack_timeout_update_) {
- MaybeUpdateAckTimeout();
- } else {
- should_last_packet_instigate_acks_ = true;
- }
+ MaybeUpdateAckTimeout();
if (!transmitted_connectivity_probe_payload_ ||
*transmitted_connectivity_probe_payload_ != frame.data_buffer) {
// Is not for the probe we sent, ignore it.
@@ -1363,13 +1516,8 @@ bool QuicConnection::OnGoAwayFrame(const QuicGoAwayFrame& frame) {
<< frame.last_good_stream_id
<< " and error: " << QuicErrorCodeToString(frame.error_code)
<< " and reason: " << frame.reason_phrase;
- if (advance_ack_timeout_update_) {
- MaybeUpdateAckTimeout();
- }
+ MaybeUpdateAckTimeout();
visitor_->OnGoAway(frame);
- if (!advance_ack_timeout_update_) {
- should_last_packet_instigate_acks_ = true;
- }
return connected_;
}
@@ -1384,13 +1532,8 @@ bool QuicConnection::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
debug_visitor_->OnWindowUpdateFrame(frame, GetTimeOfLastReceivedPacket());
}
QUIC_DVLOG(1) << ENDPOINT << "WINDOW_UPDATE_FRAME received " << frame;
- if (advance_ack_timeout_update_) {
- MaybeUpdateAckTimeout();
- }
+ MaybeUpdateAckTimeout();
visitor_->OnWindowUpdateFrame(frame);
- if (!advance_ack_timeout_update_) {
- should_last_packet_instigate_acks_ = true;
- }
return connected_;
}
@@ -1427,19 +1570,20 @@ bool QuicConnection::OnMessageFrame(const QuicMessageFrame& frame) {
if (debug_visitor_ != nullptr) {
debug_visitor_->OnMessageFrame(frame);
}
- if (advance_ack_timeout_update_) {
- MaybeUpdateAckTimeout();
- }
+ MaybeUpdateAckTimeout();
visitor_->OnMessageReceived(
quiche::QuicheStringPiece(frame.data, frame.message_length));
- if (!advance_ack_timeout_update_) {
- should_last_packet_instigate_acks_ = true;
- }
return connected_;
}
bool QuicConnection::OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& frame) {
- DCHECK(connected_ && VersionHasIetfQuicFrames(transport_version()));
+ DCHECK(connected_);
+ if (!support_handshake_done_) {
+ CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION,
+ "Handshake done frame is unsupported",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
if (perspective_ == Perspective::IS_SERVER) {
CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION,
@@ -1455,16 +1599,17 @@ bool QuicConnection::OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& frame) {
if (debug_visitor_ != nullptr) {
debug_visitor_->OnHandshakeDoneFrame(frame);
}
- if (advance_ack_timeout_update_) {
- MaybeUpdateAckTimeout();
- }
+ MaybeUpdateAckTimeout();
visitor_->OnHandshakeDoneReceived();
- if (!advance_ack_timeout_update_) {
- should_last_packet_instigate_acks_ = true;
- }
return connected_;
}
+bool QuicConnection::OnAckFrequencyFrame(
+ const QuicAckFrequencyFrame& /*frame*/) {
+ // TODO(b/148614353): implement this fully.
+ QUIC_LOG_EVERY_N_SEC(ERROR, 120) << "Get unexpected AckFrequencyFrame.";
+ return false;
+}
bool QuicConnection::OnBlockedFrame(const QuicBlockedFrame& frame) {
DCHECK(connected_);
@@ -1477,14 +1622,9 @@ bool QuicConnection::OnBlockedFrame(const QuicBlockedFrame& frame) {
}
QUIC_DLOG(INFO) << ENDPOINT
<< "BLOCKED_FRAME received for stream: " << frame.stream_id;
- if (advance_ack_timeout_update_) {
- MaybeUpdateAckTimeout();
- }
+ MaybeUpdateAckTimeout();
visitor_->OnBlockedFrame(frame);
stats_.blocked_frames_received++;
- if (!advance_ack_timeout_update_) {
- should_last_packet_instigate_acks_ = true;
- }
return connected_;
}
@@ -1556,7 +1696,7 @@ void QuicConnection::OnPacketComplete() {
// For IETF QUIC, it is guaranteed that TLS will give connection the
// corresponding write key before read key. In other words, connection should
// never process a packet while an ACK for it cannot be encrypted.
- if (!advance_ack_timeout_update_ || !should_last_packet_instigate_acks_) {
+ if (!should_last_packet_instigate_acks_) {
uber_received_packet_manager_.MaybeUpdateAckTimeout(
should_last_packet_instigate_acks_, last_decrypted_packet_level_,
last_header_.packet_number, GetTimeOfLastReceivedPacket(),
@@ -1576,6 +1716,14 @@ void QuicConnection::OnAuthenticatedIetfStatelessResetPacket(
const QuicIetfStatelessResetPacket& /*packet*/) {
// TODO(fayang): Add OnAuthenticatedIetfStatelessResetPacket to
// debug_visitor_.
+ DCHECK(VersionHasIetfInvariantHeader(transport_version()));
+ DCHECK_EQ(perspective_, Perspective::IS_CLIENT);
+ if (!visitor_->ValidateStatelessReset(last_packet_destination_address_,
+ last_packet_source_address_)) {
+ // This packet is received on a probing path. Do not close connection.
+ return;
+ }
+
const std::string error_details = "Received stateless reset.";
QUIC_CODE_COUNT(quic_tear_down_local_connection_on_stateless_reset);
TearDownLocalConnectionState(QUIC_PUBLIC_RESET, error_details,
@@ -1693,6 +1841,29 @@ void QuicConnection::SendVersionNegotiationPacket(bool ietf_quic,
pending_version_negotiation_packet_ = false;
}
+void QuicConnection::MaybeActivateLegacyVersionEncapsulation() {
+ if (!legacy_version_encapsulation_enabled_) {
+ return;
+ }
+ DCHECK(!legacy_version_encapsulation_in_progress_);
+ QUIC_BUG_IF(!packet_creator_.CanSetMaxPacketLength())
+ << "Cannot activate Legacy Version Encapsulation mid-packet";
+ QUIC_BUG_IF(coalesced_packet_.length() != 0u)
+ << "Cannot activate Legacy Version Encapsulation mid-coalesced-packet";
+ legacy_version_encapsulation_in_progress_ = true;
+ MaybeUpdatePacketCreatorMaxPacketLengthAndPadding();
+}
+void QuicConnection::MaybeDisactivateLegacyVersionEncapsulation() {
+ if (!legacy_version_encapsulation_in_progress_) {
+ return;
+ }
+ // Flush any remaining packet before disactivating encapsulation.
+ packet_creator_.FlushCurrentPacket();
+ DCHECK(legacy_version_encapsulation_enabled_);
+ legacy_version_encapsulation_in_progress_ = false;
+ MaybeUpdatePacketCreatorMaxPacketLengthAndPadding();
+}
+
size_t QuicConnection::SendCryptoData(EncryptionLevel level,
size_t write_length,
QuicStreamOffset offset) {
@@ -1700,11 +1871,21 @@ size_t QuicConnection::SendCryptoData(EncryptionLevel level,
QUIC_BUG << "Attempt to send empty crypto frame";
return 0;
}
- if (!ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA, IS_HANDSHAKE)) {
+ if (!GetQuicReloadableFlag(quic_fix_checking_should_generate_packet) &&
+ !ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA, IS_HANDSHAKE)) {
return 0;
}
- ScopedPacketFlusher flusher(this);
- return packet_creator_.ConsumeCryptoData(level, write_length, offset);
+ if (level == ENCRYPTION_INITIAL) {
+ MaybeActivateLegacyVersionEncapsulation();
+ }
+ size_t consumed_length;
+ {
+ ScopedPacketFlusher flusher(this);
+ consumed_length =
+ packet_creator_.ConsumeCryptoData(level, write_length, offset);
+ } // Added scope ensures packets are flushed before continuing.
+ MaybeDisactivateLegacyVersionEncapsulation();
+ return consumed_length;
}
QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id,
@@ -1716,13 +1897,24 @@ QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id,
return QuicConsumedData(0, false);
}
- // Opportunistically bundle an ack with every outgoing packet.
- // Particularly, we want to bundle with handshake packets since we don't know
- // which decrypter will be used on an ack packet following a handshake
- // packet (a handshake packet from client to server could result in a REJ or a
- // SHLO from the server, leading to two different decrypters at the server.)
- ScopedPacketFlusher flusher(this);
- return packet_creator_.ConsumeData(id, write_length, offset, state);
+ if (packet_creator_.encryption_level() == ENCRYPTION_INITIAL &&
+ QuicUtils::IsCryptoStreamId(transport_version(), id)) {
+ MaybeActivateLegacyVersionEncapsulation();
+ }
+ QuicConsumedData consumed_data(0, false);
+ {
+ // Opportunistically bundle an ack with every outgoing packet.
+ // Particularly, we want to bundle with handshake packets since we don't
+ // know which decrypter will be used on an ack packet following a handshake
+ // packet (a handshake packet from client to server could result in a REJ or
+ // a SHLO from the server, leading to two different decrypters at the
+ // server.)
+ ScopedPacketFlusher flusher(this);
+ consumed_data =
+ packet_creator_.ConsumeData(id, write_length, offset, state);
+ } // Added scope ensures packets are flushed before continuing.
+ MaybeDisactivateLegacyVersionEncapsulation();
+ return consumed_data;
}
bool QuicConnection::SendControlFrame(const QuicFrame& frame) {
@@ -1734,8 +1926,7 @@ bool QuicConnection::SendControlFrame(const QuicFrame& frame) {
// anti-amplification limit is used, client needs to send something to avoid
// handshake deadlock.
QUIC_DVLOG(1) << ENDPOINT << "Failed to send control frame: " << frame
- << " at encryption level: "
- << EncryptionLevelToString(encryption_level_);
+ << " at encryption level: " << encryption_level_;
return false;
}
ScopedPacketFlusher flusher(this);
@@ -1795,10 +1986,6 @@ const QuicConnectionStats& QuicConnection::GetStats() {
return stats_;
}
-void QuicConnection::ResetHasNonAppLimitedSampleAfterHandshakeCompletion() {
- stats_.has_non_app_limited_sample = false;
-}
-
void QuicConnection::OnCoalescedPacket(const QuicEncryptedPacket& packet) {
QueueCoalescedPacket(packet);
}
@@ -1809,39 +1996,85 @@ void QuicConnection::OnUndecryptablePacket(const QuicEncryptedPacket& packet,
QUIC_DVLOG(1) << ENDPOINT << "Received undecryptable packet of length "
<< packet.length() << " with"
<< (has_decryption_key ? "" : "out") << " key at level "
- << EncryptionLevelToString(decryption_level)
+ << decryption_level
<< " while connection is at encryption level "
- << EncryptionLevelToString(encryption_level_);
+ << encryption_level_;
DCHECK(EncryptionLevelIsValid(decryption_level));
if (encryption_level_ != ENCRYPTION_FORWARD_SECURE) {
++stats_.undecryptable_packets_received_before_handshake_complete;
}
- bool should_enqueue = true;
+ const bool should_enqueue =
+ ShouldEnqueueUnDecryptablePacket(decryption_level, has_decryption_key);
+ if (should_enqueue) {
+ QueueUndecryptablePacket(packet, decryption_level);
+ }
+
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnUndecryptablePacket(decryption_level,
+ /*dropped=*/!should_enqueue);
+ }
+}
+
+bool QuicConnection::ShouldEnqueueUnDecryptablePacket(
+ EncryptionLevel decryption_level,
+ bool has_decryption_key) const {
if (encryption_level_ == ENCRYPTION_FORWARD_SECURE) {
// We do not expect to install any further keys.
- should_enqueue = false;
- } else if (undecryptable_packets_.size() >= max_undecryptable_packets_) {
+ return false;
+ }
+ if (undecryptable_packets_.size() >= max_undecryptable_packets_) {
// We do not queue more than max_undecryptable_packets_ packets.
- should_enqueue = false;
- } else if (has_decryption_key) {
+ return false;
+ }
+ if (has_decryption_key) {
// We already have the key for this decryption level, therefore no
// future keys will allow it be decrypted.
- should_enqueue = false;
- } else if (version().KnowsWhichDecrypterToUse() &&
- decryption_level <= encryption_level_) {
+ return false;
+ }
+ if (version().KnowsWhichDecrypterToUse() &&
+ decryption_level <= encryption_level_) {
// On versions that know which decrypter to use, we install keys in order
// so we will not get newer keys for lower encryption levels.
- should_enqueue = false;
+ return false;
}
+ return true;
+}
- if (should_enqueue) {
- QueueUndecryptablePacket(packet, decryption_level);
+std::string QuicConnection::UndecryptablePacketsInfo() const {
+ std::string info = quiche::QuicheStrCat(
+ "num_undecryptable_packets: ", undecryptable_packets_.size(), " {");
+ for (const auto& packet : undecryptable_packets_) {
+ info = quiche::QuicheStrCat(
+ info, "[", EncryptionLevelToString(packet.encryption_level), ", ",
+ packet.packet->length(), ", ", packet.processed, "]");
+ }
+ info = quiche::QuicheStrCat(info, "}");
+ return info;
+}
+
+void QuicConnection::MaybeUpdatePacketCreatorMaxPacketLengthAndPadding() {
+ QuicByteCount max_packet_length = GetLimitedMaxPacketSize(long_term_mtu_);
+ if (legacy_version_encapsulation_in_progress_) {
+ DCHECK(legacy_version_encapsulation_enabled_);
+ const QuicByteCount minimum_overhead =
+ QuicLegacyVersionEncapsulator::GetMinimumOverhead(
+ legacy_version_encapsulation_sni_);
+ if (max_packet_length < minimum_overhead) {
+ QUIC_BUG << "Cannot apply Legacy Version Encapsulation overhead because "
+ << "max_packet_length " << max_packet_length
+ << " < minimum_overhead " << minimum_overhead;
+ legacy_version_encapsulation_in_progress_ = false;
+ legacy_version_encapsulation_enabled_ = false;
+ MaybeUpdatePacketCreatorMaxPacketLengthAndPadding();
+ return;
+ }
+ max_packet_length -= minimum_overhead;
}
-
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnUndecryptablePacket(decryption_level,
- /*dropped=*/!should_enqueue);
+ packet_creator_.SetMaxPacketLength(max_packet_length);
+ if (legacy_version_encapsulation_enabled_) {
+ packet_creator_.set_disable_padding_override(
+ legacy_version_encapsulation_in_progress_);
}
}
@@ -1899,14 +2132,9 @@ void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address,
<< " too far from current time:"
<< clock_->ApproximateNow().ToDebuggingValue();
}
- if (!extend_idle_time_on_decryptable_packets_ && use_idle_network_detector_) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_idle_network_detector, 1, 6);
- idle_network_detector_.OnPacketReceived(packet.receipt_time());
- } else {
- time_of_last_received_packet_ = packet.receipt_time();
- }
+ time_of_last_received_packet_ = packet.receipt_time();
QUIC_DVLOG(1) << ENDPOINT << "time of last received packet: "
- << GetTimeOfLastReceivedPacket().ToDebuggingValue();
+ << packet.receipt_time().ToDebuggingValue();
ScopedPacketFlusher flusher(this);
if (!framer_.ProcessPacket(packet)) {
@@ -2040,6 +2268,9 @@ bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) {
QUIC_DLOG(INFO) << ENDPOINT << "Replacing connection ID "
<< server_connection_id_ << " with "
<< header.source_connection_id;
+ if (!original_destination_connection_id_.has_value()) {
+ original_destination_connection_id_ = server_connection_id_;
+ }
server_connection_id_ = header.source_connection_id;
packet_creator_.SetServerConnectionId(server_connection_id_);
}
@@ -2122,12 +2353,7 @@ void QuicConnection::WriteQueuedPackets() {
// TODO(wub): Reduce max packet size to a safe default, or the actual MTU.
mtu_discoverer_.Disable();
mtu_discovery_alarm_->Cancel();
- if (GetQuicReloadableFlag(
- quic_ignore_msg_too_big_from_buffered_packets)) {
- QUIC_RELOADABLE_FLAG_COUNT(
- quic_ignore_msg_too_big_from_buffered_packets);
- buffered_packets_.pop_front();
- }
+ buffered_packets_.pop_front();
continue;
}
if (IsWriteError(result.status)) {
@@ -2156,17 +2382,26 @@ void QuicConnection::SendProbingRetransmissions() {
}
}
-void QuicConnection::RetransmitUnackedPackets(
- TransmissionType retransmission_type) {
- sent_packet_manager_.RetransmitUnackedPackets(retransmission_type);
+void QuicConnection::RetransmitZeroRttPackets() {
+ sent_packet_manager_.RetransmitZeroRttPackets();
- WriteIfNotBlocked();
+ if (!GetQuicReloadableFlag(
+ quic_do_not_retransmit_immediately_on_zero_rtt_reject)) {
+ WriteIfNotBlocked();
+ }
}
void QuicConnection::NeuterUnencryptedPackets() {
sent_packet_manager_.NeuterUnencryptedPackets();
// This may have changed the retransmission timer, so re-arm it.
SetRetransmissionAlarm();
+ if (default_enable_5rto_blackhole_detection_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_default_enable_5rto_blackhole_detection2,
+ 1, 3);
+ // Consider this as forward progress since this is called when initial key
+ // gets discarded (or previous unencrypted data is not needed anymore).
+ OnForwardProgressMade();
+ }
if (SupportsMultiplePacketNumberSpaces()) {
// Stop sending ack of initial packet number space.
uber_received_packet_manager_.ResetAckStates(ENCRYPTION_INITIAL);
@@ -2179,9 +2414,13 @@ void QuicConnection::NeuterUnencryptedPackets() {
bool QuicConnection::ShouldGeneratePacket(
HasRetransmittableData retransmittable,
IsHandshake handshake) {
+ DCHECK(handshake != IS_HANDSHAKE ||
+ QuicVersionUsesCryptoFrames(transport_version()))
+ << ENDPOINT
+ << "Handshake in STREAM frames should not check ShouldGeneratePacket";
// We should serialize handshake packets immediately to ensure that they
// end up sent at the right encryption level.
- if (handshake == IS_HANDSHAKE) {
+ if (!move_amplification_limit_ && handshake == IS_HANDSHAKE) {
if (LimitedByAmplificationFactor()) {
// Server is constrained by the amplification restriction.
QUIC_DVLOG(1) << ENDPOINT << "Constrained by amplification restriction";
@@ -2209,9 +2448,8 @@ const QuicFrames QuicConnection::MaybeBundleAckOpportunistically() {
QuicFrame updated_ack_frame = GetUpdatedAckFrame();
QUIC_BUG_IF(updated_ack_frame.ack_frame->packets.Empty())
<< ENDPOINT << "Attempted to opportunistically bundle an empty "
- << EncryptionLevelToString(encryption_level_) << " ACK, "
- << (has_pending_ack ? "" : "!") << "has_pending_ack, stop_waiting_count_ "
- << stop_waiting_count_;
+ << encryption_level_ << " ACK, " << (has_pending_ack ? "" : "!")
+ << "has_pending_ack, stop_waiting_count_ " << stop_waiting_count_;
frames.push_back(updated_ack_frame);
if (!no_stop_waiting_frames_) {
@@ -2227,6 +2465,14 @@ bool QuicConnection::CanWrite(HasRetransmittableData retransmittable) {
return false;
}
+ if (move_amplification_limit_ && LimitedByAmplificationFactor()) {
+ // Server is constrained by the amplification restriction.
+ QUIC_RELOADABLE_FLAG_COUNT(quic_move_amplification_limit);
+ QUIC_CODE_COUNT(quic_throttled_by_amplification_limit);
+ QUIC_DVLOG(1) << ENDPOINT << "Constrained by amplification restriction";
+ return false;
+ }
+
if (sent_packet_manager_.pending_timer_transmission_count() > 0) {
// Force sending the retransmissions for HANDSHAKE, TLP, RTO, PROBING cases.
return true;
@@ -2305,7 +2551,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
// Termination packets are encrypted and saved, so don't exit early.
const bool is_termination_packet = IsTerminationPacket(*packet);
QuicPacketNumber packet_number = packet->packet_number;
- const QuicPacketLength encrypted_length = packet->encrypted_length;
+ QuicPacketLength encrypted_length = packet->encrypted_length;
// Termination packets are eventually owned by TimeWaitListManager.
// Others are deleted at the end of this call.
if (is_termination_packet) {
@@ -2320,18 +2566,21 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
}
DCHECK_LE(encrypted_length, kMaxOutgoingPacketSize);
- if (!is_mtu_discovery) {
- DCHECK_LE(encrypted_length, packet_creator_.max_packet_length());
- }
+ DCHECK(is_mtu_discovery ||
+ encrypted_length <= packet_creator_.max_packet_length())
+ << " encrypted_length=" << encrypted_length
+ << " > packet_creator max_packet_length="
+ << packet_creator_.max_packet_length();
QUIC_DVLOG(1) << ENDPOINT << "Sending packet " << packet_number << " : "
<< (IsRetransmittable(*packet) == HAS_RETRANSMITTABLE_DATA
? "data bearing "
: " ack only ")
- << ", encryption level: "
- << EncryptionLevelToString(packet->encryption_level)
+ << ", encryption level: " << packet->encryption_level
<< ", encrypted length:" << encrypted_length
- << ", fate: " << SerializedPacketFateToString(fate);
- QUIC_DVLOG(2) << ENDPOINT << "packet(" << packet_number << "): " << std::endl
+ << ", fate: " << fate;
+ QUIC_DVLOG(2) << ENDPOINT << packet->encryption_level << " packet number "
+ << packet_number << " of length " << encrypted_length << ": "
+ << std::endl
<< quiche::QuicheTextUtils::HexDump(quiche::QuicheStringPiece(
packet->encrypted_buffer, encrypted_length));
@@ -2377,6 +2626,14 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
buffered_packets_.emplace_back(*packet, self_address(), peer_address());
break;
case SEND_TO_WRITER:
+ // At this point, packet->release_encrypted_buffer is either nullptr,
+ // meaning |packet->encrypted_buffer| is a stack buffer, or not-nullptr,
+ /// meaning it's a writer-allocated buffer. Note that connectivity probing
+ // packets do not use this function, so setting release_encrypted_buffer
+ // to nullptr will not cause probing packets to be leaked.
+ //
+ // writer_->WritePacket transfers buffer ownership back to the writer.
+ packet->release_encrypted_buffer = nullptr;
result = writer_->WritePacket(packet->encrypted_buffer, encrypted_length,
self_address().host(), peer_address(),
per_packet_options_);
@@ -2396,6 +2653,48 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
// write error has been handled.
QUIC_BUG_IF(!version().CanSendCoalescedPackets());
return false;
+ case LEGACY_VERSION_ENCAPSULATE: {
+ DCHECK(!is_mtu_discovery);
+ DCHECK_EQ(perspective_, Perspective::IS_CLIENT);
+ DCHECK_EQ(packet->encryption_level, ENCRYPTION_INITIAL);
+ DCHECK(legacy_version_encapsulation_enabled_);
+ DCHECK(legacy_version_encapsulation_in_progress_);
+ QuicPacketLength encapsulated_length =
+ QuicLegacyVersionEncapsulator::Encapsulate(
+ legacy_version_encapsulation_sni_,
+ quiche::QuicheStringPiece(packet->encrypted_buffer,
+ packet->encrypted_length),
+ server_connection_id_, framer_.creation_time(),
+ GetLimitedMaxPacketSize(long_term_mtu_),
+ const_cast<char*>(packet->encrypted_buffer));
+ if (encapsulated_length != 0) {
+ stats_.sent_legacy_version_encapsulated_packets++;
+ packet->encrypted_length = encapsulated_length;
+ encrypted_length = encapsulated_length;
+ QUIC_DVLOG(2)
+ << ENDPOINT
+ << "Successfully performed Legacy Version Encapsulation on "
+ << packet->encryption_level << " packet number " << packet_number
+ << " of length " << encrypted_length << ": " << std::endl
+ << quiche::QuicheTextUtils::HexDump(quiche::QuicheStringPiece(
+ packet->encrypted_buffer, encrypted_length));
+ } else {
+ QUIC_BUG << ENDPOINT
+ << "Failed to perform Legacy Version Encapsulation on "
+ << packet->encryption_level << " packet number "
+ << packet_number << " of length " << encrypted_length;
+ }
+ if (!buffered_packets_.empty() || HandleWriteBlocked()) {
+ // Buffer the packet.
+ buffered_packets_.emplace_back(*packet, self_address(), peer_address());
+ } else { // Send the packet to the writer.
+ // writer_->WritePacket transfers buffer ownership back to the writer.
+ packet->release_encrypted_buffer = nullptr;
+ result = writer_->WritePacket(packet->encrypted_buffer,
+ encrypted_length, self_address().host(),
+ peer_address(), per_packet_options_);
+ }
+ } break;
default:
DCHECK(false);
break;
@@ -2499,6 +2798,11 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
const bool in_flight = sent_packet_manager_.OnPacketSent(
packet, packet_send_time, packet->transmission_type,
IsRetransmittable(*packet));
+ QUIC_BUG_IF(default_enable_5rto_blackhole_detection_ &&
+ blackhole_detector_.IsDetectionInProgress() &&
+ !sent_packet_manager_.HasInFlightPackets())
+ << ENDPOINT
+ << "Trying to start blackhole detection without no bytes in flight";
if (in_flight || !retransmission_alarm_->IsSet()) {
SetRetransmissionAlarm();
@@ -2620,11 +2924,11 @@ void QuicConnection::OnWriteError(int error_code) {
}
}
-char* QuicConnection::GetPacketBuffer() {
+QuicPacketBuffer QuicConnection::GetPacketBuffer() {
if (version().CanSendCoalescedPackets() && !IsHandshakeConfirmed()) {
// Do not use writer's packet buffer for coalesced packets which may contain
// multiple QUIC packets.
- return nullptr;
+ return {nullptr, nullptr};
}
return writer_->GetNextWriteLocation(self_address().host(), peer_address());
}
@@ -2700,6 +3004,11 @@ void QuicConnection::OnHandshakeComplete() {
sent_packet_manager_.SetHandshakeConfirmed();
// This may have changed the retransmission timer, so re-arm it.
SetRetransmissionAlarm();
+ if (default_enable_5rto_blackhole_detection_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_default_enable_5rto_blackhole_detection2,
+ 2, 3);
+ OnForwardProgressMade();
+ }
if (!SupportsMultiplePacketNumberSpaces()) {
// The client should immediately ack the SHLO to confirm the handshake is
// complete with the server.
@@ -2753,11 +3062,6 @@ void QuicConnection::SendAck() {
visitor_->OnAckNeedsRetransmittableFrame();
}
-void QuicConnection::OnPathDegradingTimeout() {
- is_path_degrading_ = true;
- visitor_->OnPathDegrading();
-}
-
void QuicConnection::OnRetransmissionTimeout() {
#ifndef NDEBUG
if (sent_packet_manager_.unacked_packets().empty()) {
@@ -2784,6 +3088,13 @@ void QuicConnection::OnRetransmissionTimeout() {
debug_visitor_->OnNPacketNumbersSkipped(num_packet_numbers_to_skip);
}
}
+ if (default_enable_5rto_blackhole_detection_ &&
+ !sent_packet_manager_.HasInFlightPackets() &&
+ blackhole_detector_.IsDetectionInProgress()) {
+ // Stop detection in quiescence.
+ DCHECK_EQ(QuicSentPacketManager::LOSS_MODE, retransmission_mode);
+ blackhole_detector_.StopDetection();
+ }
WriteIfNotBlocked();
// A write failure can result in the connection being closed, don't attempt to
@@ -2817,8 +3128,9 @@ void QuicConnection::OnRetransmissionTimeout() {
if (retransmission_mode == QuicSentPacketManager::PTO_MODE) {
sent_packet_manager_.AdjustPendingTimerTransmissions();
}
- if (retransmission_mode != QuicSentPacketManager::LOSS_MODE) {
- // When timer fires in TLP or RTO mode, ensure 1) at least one packet is
+ if (retransmission_mode != QuicSentPacketManager::LOSS_MODE &&
+ retransmission_mode != QuicSentPacketManager::HANDSHAKE_MODE) {
+ // When timer fires in TLP/RTO/PTO mode, ensure 1) at least one packet is
// created, or there is data to send and available credit (such that
// packets will be sent eventually).
QUIC_BUG_IF(packet_creator_.packet_number() ==
@@ -2859,8 +3171,7 @@ void QuicConnection::SetDiversificationNonce(
void QuicConnection::SetDefaultEncryptionLevel(EncryptionLevel level) {
QUIC_DVLOG(1) << ENDPOINT << "Setting default encryption level from "
- << EncryptionLevelToString(encryption_level_) << " to "
- << EncryptionLevelToString(level);
+ << encryption_level_ << " to " << level;
if (level != encryption_level_ && packet_creator_.HasPendingFrames()) {
// Flush all queued frames when encryption level changes.
ScopedPacketFlusher flusher(this);
@@ -2936,27 +3247,79 @@ void QuicConnection::MaybeProcessUndecryptablePackets() {
return;
}
- while (connected_ && !undecryptable_packets_.empty()) {
- // Making sure there is no pending frames when processing next undecrypted
- // packet because the queued ack frame may change.
- packet_creator_.FlushCurrentPacket();
- if (!connected_) {
- return;
+ if (GetQuicReloadableFlag(quic_fix_undecryptable_packets)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_fix_undecryptable_packets);
+ auto iter = undecryptable_packets_.begin();
+ while (connected_ && iter != undecryptable_packets_.end()) {
+ // Making sure there is no pending frames when processing next undecrypted
+ // packet because the queued ack frame may change.
+ packet_creator_.FlushCurrentPacket();
+ if (!connected_) {
+ return;
+ }
+ UndecryptablePacket* undecryptable_packet = &*iter;
+ ++iter;
+ if (undecryptable_packet->processed) {
+ continue;
+ }
+ QUIC_DVLOG(1) << ENDPOINT << "Attempting to process undecryptable packet";
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnAttemptingToProcessUndecryptablePacket(
+ undecryptable_packet->encryption_level);
+ }
+ if (framer_.ProcessPacket(*undecryptable_packet->packet)) {
+ QUIC_DVLOG(1) << ENDPOINT << "Processed undecryptable packet!";
+ undecryptable_packet->processed = true;
+ ++stats_.packets_processed;
+ continue;
+ }
+ const bool has_decryption_key =
+ version().KnowsWhichDecrypterToUse() &&
+ framer_.HasDecrypterOfEncryptionLevel(
+ undecryptable_packet->encryption_level);
+ if (framer_.error() == QUIC_DECRYPTION_FAILURE &&
+ ShouldEnqueueUnDecryptablePacket(
+ undecryptable_packet->encryption_level, has_decryption_key)) {
+ QUIC_DVLOG(1)
+ << ENDPOINT
+ << "Need to attempt to process this undecryptable packet later";
+ continue;
+ }
+ undecryptable_packet->processed = true;
}
- QUIC_DVLOG(1) << ENDPOINT << "Attempting to process undecryptable packet";
- const auto& undecryptable_packet = undecryptable_packets_.front();
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnAttemptingToProcessUndecryptablePacket(
- undecryptable_packet.encryption_level);
+ // Remove processed packets. We cannot remove elements in the while loop
+ // above because currently QuicCircularDeque does not support removing
+ // mid elements.
+ while (!undecryptable_packets_.empty()) {
+ if (!undecryptable_packets_.front().processed) {
+ break;
+ }
+ undecryptable_packets_.pop_front();
}
- if (!framer_.ProcessPacket(*undecryptable_packet.packet) &&
- framer_.error() == QUIC_DECRYPTION_FAILURE) {
- QUIC_DVLOG(1) << ENDPOINT << "Unable to process undecryptable packet...";
- break;
+ } else {
+ while (connected_ && !undecryptable_packets_.empty()) {
+ // Making sure there is no pending frames when processing next undecrypted
+ // packet because the queued ack frame may change.
+ packet_creator_.FlushCurrentPacket();
+ if (!connected_) {
+ return;
+ }
+ QUIC_DVLOG(1) << ENDPOINT << "Attempting to process undecryptable packet";
+ const auto& undecryptable_packet = undecryptable_packets_.front();
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnAttemptingToProcessUndecryptablePacket(
+ undecryptable_packet.encryption_level);
+ }
+ if (!framer_.ProcessPacket(*undecryptable_packet.packet) &&
+ framer_.error() == QUIC_DECRYPTION_FAILURE) {
+ QUIC_DVLOG(1) << ENDPOINT
+ << "Unable to process undecryptable packet...";
+ break;
+ }
+ QUIC_DVLOG(1) << ENDPOINT << "Processed undecryptable packet!";
+ ++stats_.packets_processed;
+ undecryptable_packets_.pop_front();
}
- QUIC_DVLOG(1) << ENDPOINT << "Processed undecryptable packet!";
- ++stats_.packets_processed;
- undecryptable_packets_.pop_front();
}
// Once forward secure encryption is in use, there will be no
@@ -3074,8 +3437,8 @@ void QuicConnection::SendConnectionClosePacket(QuicErrorCode error,
if (!framer_.HasEncrypterOfEncryptionLevel(level)) {
continue;
}
- QUIC_DLOG(INFO) << ENDPOINT << "Sending connection close packet at level: "
- << EncryptionLevelToString(level);
+ QUIC_DLOG(INFO) << ENDPOINT
+ << "Sending connection close packet at level: " << level;
SetDefaultEncryptionLevel(level);
// Bundle an ACK of the corresponding packet number space for debugging
// purpose.
@@ -3156,7 +3519,7 @@ QuicByteCount QuicConnection::max_packet_length() const {
void QuicConnection::SetMaxPacketLength(QuicByteCount length) {
long_term_mtu_ = length;
- packet_creator_.SetMaxPacketLength(GetLimitedMaxPacketSize(length));
+ MaybeUpdatePacketCreatorMaxPacketLengthAndPadding();
}
bool QuicConnection::HasQueuedData() const {
@@ -3164,22 +3527,6 @@ bool QuicConnection::HasQueuedData() const {
packet_creator_.HasPendingFrames() || !buffered_packets_.empty();
}
-bool QuicConnection::CanWriteStreamData() {
- // Don't write stream data if there are negotiation or queued data packets
- // to send. Otherwise, continue and bundle as many frames as possible.
- if (pending_version_negotiation_packet_ || !buffered_packets_.empty()) {
- return false;
- }
-
- IsHandshake pending_handshake =
- visitor_->HasPendingHandshake() ? IS_HANDSHAKE : NOT_HANDSHAKE;
- // Sending queued packets may have caused the socket to become write blocked,
- // or the congestion manager to prohibit sending. If we've sent everything
- // we had queued and we're still not blocked, let the visitor know it can
- // write more.
- return ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA, pending_handshake);
-}
-
void QuicConnection::SetNetworkTimeouts(QuicTime::Delta handshake_timeout,
QuicTime::Delta idle_timeout) {
QUIC_BUG_IF(idle_timeout > handshake_timeout)
@@ -3868,15 +4215,7 @@ void QuicConnection::PostProcessAfterAckFrame(bool send_stop_waiting,
// have a better estimate of the current rtt than when it was set.
SetRetransmissionAlarm();
if (acked_new_packet) {
- is_path_degrading_ = false;
- if (sent_packet_manager_.HasInFlightPackets()) {
- // Restart detections if forward progress has been made.
- blackhole_detector_.RestartDetection(GetPathDegradingDeadline(),
- GetNetworkBlackholeDeadline());
- } else {
- // Stop detections in quiecense.
- blackhole_detector_.StopDetection();
- }
+ OnForwardProgressMade();
}
if (send_stop_waiting) {
@@ -3963,7 +4302,7 @@ EncryptionLevel QuicConnection::GetConnectionCloseEncryptionLevel() const {
// A forward secure packet has been received.
QUIC_BUG_IF(encryption_level_ != ENCRYPTION_FORWARD_SECURE)
<< ENDPOINT << "Unexpected connection close encryption level "
- << EncryptionLevelToString(encryption_level_);
+ << encryption_level_;
return ENCRYPTION_FORWARD_SECURE;
}
if (framer_.HasEncrypterOfEncryptionLevel(ENCRYPTION_ZERO_RTT)) {
@@ -3979,25 +4318,68 @@ EncryptionLevel QuicConnection::GetConnectionCloseEncryptionLevel() const {
return ENCRYPTION_INITIAL;
}
+void QuicConnection::MaybeBundleCryptoDataWithAckOfSpace(
+ PacketNumberSpace space) {
+ DCHECK(SupportsMultiplePacketNumberSpaces());
+ QUIC_BUG_IF(space == APPLICATION_DATA);
+ const QuicTime ack_timeout =
+ uber_received_packet_manager_.GetAckTimeout(space);
+ if (!ack_timeout.IsInitialized() ||
+ (ack_timeout > clock_->ApproximateNow() &&
+ ack_timeout > uber_received_packet_manager_.GetEarliestAckTimeout())) {
+ // No pending ACK of space.
+ return;
+ }
+ if (coalesced_packet_.length() > 0) {
+ // Do not bundle CRYPTO data if the ACK could be coalesced with other
+ // packets.
+ return;
+ }
+
+ sent_packet_manager_.RetransmitDataOfSpaceIfAny(space);
+}
+
void QuicConnection::SendAllPendingAcks() {
DCHECK(SupportsMultiplePacketNumberSpaces());
QUIC_DVLOG(1) << ENDPOINT << "Trying to send all pending ACKs";
ack_alarm_->Cancel();
+ QuicTime earliest_ack_timeout =
+ uber_received_packet_manager_.GetEarliestAckTimeout();
+ QUIC_BUG_IF(!earliest_ack_timeout.IsInitialized());
+ if (GetQuicReloadableFlag(quic_bundle_crypto_data_with_initial_ack)) {
+ // On the server side, sends INITIAL data with INITIAL ACK. On the client
+ // side, sends HANDSHAKE data (containing client Finished) with HANDSHAKE
+ // ACK.
+ PacketNumberSpace space =
+ perspective() == Perspective::IS_SERVER ? INITIAL_DATA : HANDSHAKE_DATA;
+ MaybeBundleCryptoDataWithAckOfSpace(space);
+ earliest_ack_timeout =
+ uber_received_packet_manager_.GetEarliestAckTimeout();
+ if (!earliest_ack_timeout.IsInitialized()) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_bundle_crypto_data_with_initial_ack);
+ return;
+ }
+ }
// Latches current encryption level.
const EncryptionLevel current_encryption_level = encryption_level_;
for (int8_t i = INITIAL_DATA; i <= APPLICATION_DATA; ++i) {
const QuicTime ack_timeout = uber_received_packet_manager_.GetAckTimeout(
static_cast<PacketNumberSpace>(i));
- if (!ack_timeout.IsInitialized() ||
- ack_timeout > clock_->ApproximateNow()) {
+ if (!ack_timeout.IsInitialized()) {
continue;
}
- if (!framer_.HasEncrypterOfEncryptionLevel(
- QuicUtils::GetEncryptionLevel(static_cast<PacketNumberSpace>(i)))) {
- QUIC_BUG << ENDPOINT << "Cannot send ACKs for packet number space "
- << PacketNumberSpaceToString(static_cast<PacketNumberSpace>(i))
- << " without corresponding encrypter";
- continue;
+ if (GetQuicReloadableFlag(quic_always_send_earliest_ack)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_always_send_earliest_ack);
+ }
+ if (ack_timeout > clock_->ApproximateNow()) {
+ if (!GetQuicReloadableFlag(quic_always_send_earliest_ack)) {
+ continue;
+ }
+ if (ack_timeout > earliest_ack_timeout) {
+ // Always send the earliest ACK to make forward progress in case alarm
+ // fires early.
+ continue;
+ }
}
QUIC_DVLOG(1) << ENDPOINT << "Sending ACK of packet number space "
<< PacketNumberSpaceToString(
@@ -4011,8 +4393,12 @@ void QuicConnection::SendAllPendingAcks() {
const bool flushed = packet_creator_.FlushAckFrame(frames);
if (!flushed) {
// Connection is write blocked.
- QUIC_BUG_IF(!writer_->IsWriteBlocked())
- << "Writer not blocked, but ACK not flushed for packet space:" << i;
+ QUIC_BUG_IF(
+ !writer_->IsWriteBlocked() &&
+ (!move_amplification_limit_ || !LimitedByAmplificationFactor()))
+ << "Writer not blocked and not throttled by amplification factor, "
+ "but ACK not flushed for packet space:"
+ << i;
break;
}
ResetAckStates();
@@ -4024,7 +4410,13 @@ void QuicConnection::SendAllPendingAcks() {
uber_received_packet_manager_.GetEarliestAckTimeout();
if (timeout.IsInitialized()) {
// If there are ACKs pending, re-arm ack alarm.
- ack_alarm_->Set(timeout);
+ if (update_ack_alarm_in_send_all_pending_acks_) {
+ QUIC_RELOADABLE_FLAG_COUNT(
+ quic_update_ack_alarm_in_send_all_pending_acks);
+ ack_alarm_->Update(timeout, kAlarmGranularity);
+ } else {
+ ack_alarm_->Set(timeout);
+ }
}
// Only try to bundle retransmittable data with ACK frame if default
// encryption level is forward secure.
@@ -4066,13 +4458,15 @@ bool QuicConnection::FlushCoalescedPacket() {
if (coalesced_packet_.length() == 0) {
return true;
}
- QUIC_DVLOG(1) << ENDPOINT << "Sending coalesced packet";
+
char buffer[kMaxOutgoingPacketSize];
const size_t length = packet_creator_.SerializeCoalescedPacket(
coalesced_packet_, buffer, coalesced_packet_.max_packet_length());
if (length == 0) {
return false;
}
+ QUIC_DVLOG(1) << ENDPOINT << "Sending coalesced packet "
+ << coalesced_packet_.ToString(length);
if (!buffered_packets_.empty() || HandleWriteBlocked()) {
QUIC_DVLOG(1) << ENDPOINT
@@ -4158,6 +4552,26 @@ void QuicConnection::SetLargestReceivedPacketWithAck(
}
}
+void QuicConnection::OnForwardProgressMade() {
+ if (is_path_degrading_) {
+ visitor_->OnForwardProgressMadeAfterPathDegrading();
+ is_path_degrading_ = false;
+ }
+ if (sent_packet_manager_.HasInFlightPackets()) {
+ // Restart detections if forward progress has been made.
+ blackhole_detector_.RestartDetection(GetPathDegradingDeadline(),
+ GetNetworkBlackholeDeadline());
+ } else {
+ // Stop detections in quiecense.
+ blackhole_detector_.StopDetection();
+ }
+ QUIC_BUG_IF(default_enable_5rto_blackhole_detection_ &&
+ blackhole_detector_.IsDetectionInProgress() &&
+ !sent_packet_manager_.HasInFlightPackets())
+ << ENDPOINT
+ << "Trying to start blackhole detection without no bytes in flight";
+}
+
QuicPacketNumber QuicConnection::GetLargestReceivedPacketWithAck() const {
if (SupportsMultiplePacketNumberSpaces()) {
return largest_seen_packets_with_ack_[QuicUtils::GetPacketNumberSpace(
@@ -4187,21 +4601,28 @@ bool QuicConnection::EnforceAntiAmplificationLimit() const {
bool QuicConnection::LimitedByAmplificationFactor() const {
return EnforceAntiAmplificationLimit() &&
bytes_sent_before_address_validation_ >=
- GetQuicFlag(FLAGS_quic_anti_amplification_factor) *
+ anti_amplification_factor_ *
bytes_received_before_address_validation_;
}
SerializedPacketFate QuicConnection::DeterminePacketFate(
bool is_mtu_discovery) {
- if (version().CanSendCoalescedPackets() && !IsHandshakeConfirmed() &&
- !is_mtu_discovery) {
- // Before receiving ACK for any 1-RTT packets, always try to coalesce
- // packet (except MTU discovery packet).
- return COALESCE;
+ if (legacy_version_encapsulation_in_progress_) {
+ DCHECK(!is_mtu_discovery);
+ return LEGACY_VERSION_ENCAPSULATE;
}
- // Packet cannot be coalesced, flush existing coalesced packet.
- if (version().CanSendCoalescedPackets() && !FlushCoalescedPacket()) {
- return FAILED_TO_WRITE_COALESCED_PACKET;
+ if (version().CanSendCoalescedPackets()) {
+ // Disable coalescing when Legacy Version Encapsulation is in use to avoid
+ // having to reframe encapsulated packets.
+ if (!IsHandshakeConfirmed() && !is_mtu_discovery) {
+ // Before receiving ACK for any 1-RTT packets, always try to coalesce
+ // packet (except MTU discovery packet).
+ return COALESCE;
+ }
+ // Packet cannot be coalesced, flush existing coalesced packet.
+ if (!FlushCoalescedPacket()) {
+ return FAILED_TO_WRITE_COALESCED_PACKET;
+ }
}
if (!buffered_packets_.empty() || HandleWriteBlocked()) {
return BUFFER;
@@ -4269,6 +4690,11 @@ void QuicConnection::OnPathDegradingDetected() {
}
void QuicConnection::OnBlackholeDetected() {
+ QUIC_BUG_IF(default_enable_5rto_blackhole_detection_ &&
+ !sent_packet_manager_.HasInFlightPackets())
+ << ENDPOINT
+ << "Closing connection because of blackhole, but there is no bytes in "
+ "flight";
CloseConnection(QUIC_TOO_MANY_RTOS, "Network blackhole detected.",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
@@ -4278,10 +4704,14 @@ void QuicConnection::OnHandshakeTimeout() {
DCHECK(use_idle_network_detector_);
const QuicTime::Delta duration =
clock_->ApproximateNow() - stats_.connection_creation_time;
- const std::string error_details = quiche::QuicheStrCat(
+ std::string error_details = quiche::QuicheStrCat(
"Handshake timeout expired after ", duration.ToDebuggingValue(),
". Timeout:",
idle_network_detector_.handshake_timeout().ToDebuggingValue());
+ if (perspective() == Perspective::IS_CLIENT && version().UsesTls()) {
+ error_details =
+ quiche::QuicheStrCat(error_details, UndecryptablePacketsInfo());
+ }
QUIC_DVLOG(1) << ENDPOINT << error_details;
CloseConnection(QUIC_HANDSHAKE_TIMEOUT, error_details,
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
@@ -4311,7 +4741,6 @@ void QuicConnection::OnIdleNetworkDetected() {
}
void QuicConnection::MaybeUpdateAckTimeout() {
- DCHECK(advance_ack_timeout_update_);
if (should_last_packet_instigate_acks_) {
return;
}
@@ -4345,20 +4774,27 @@ QuicTime QuicConnection::GetNetworkBlackholeDeadline() const {
if (!ShouldDetectBlackhole()) {
return QuicTime::Zero();
}
+ DCHECK_LT(0u, num_rtos_for_blackhole_detection_);
return clock_->ApproximateNow() +
- sent_packet_manager_.GetNetworkBlackholeDelay();
+ sent_packet_manager_.GetNetworkBlackholeDelay(
+ num_rtos_for_blackhole_detection_);
}
bool QuicConnection::ShouldDetectBlackhole() const {
- if (!connected_) {
+ if (!connected_ || blackhole_detection_disabled_) {
return false;
}
// No blackhole detection before handshake completes.
+ if (default_enable_5rto_blackhole_detection_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_default_enable_5rto_blackhole_detection2,
+ 3, 3);
+ return IsHandshakeComplete();
+ }
+
if (!GetHandshakeTimeout().IsInfinite()) {
return false;
}
- return close_connection_after_five_rtos_ ||
- (sent_packet_manager_.pto_enabled() && max_consecutive_ptos_ > 0);
+ return num_rtos_for_blackhole_detection_ > 0;
}
QuicTime::Delta QuicConnection::GetHandshakeTimeout() const {
@@ -4372,12 +4808,9 @@ QuicTime QuicConnection::GetTimeOfLastReceivedPacket() const {
if (use_idle_network_detector_) {
return idle_network_detector_.time_of_last_received_packet();
}
- if (extend_idle_time_on_decryptable_packets_) {
- DCHECK(time_of_last_decryptable_packet_ == time_of_last_received_packet_ ||
- !last_packet_decrypted_);
- return time_of_last_decryptable_packet_;
- }
- return time_of_last_received_packet_;
+ DCHECK(time_of_last_decryptable_packet_ == time_of_last_received_packet_ ||
+ !last_packet_decrypted_);
+ return time_of_last_decryptable_packet_;
}
#undef ENDPOINT // undef for jumbo builds
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection.h b/chromium/net/third_party/quiche/src/quic/core/quic_connection.h
index 6586fb2870a..c0f722dd0c8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection.h
@@ -26,6 +26,7 @@
#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
+#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h"
#include "net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.h"
#include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters_proto.h"
#include "net/third_party/quiche/src/quic/core/quic_alarm.h"
@@ -130,6 +131,12 @@ class QUIC_EXPORT_PRIVATE QuicConnectionVisitorInterface {
// bandwidth. Returns true if data was sent, false otherwise.
virtual bool SendProbingData() = 0;
+ // Called when stateless reset packet is received. Returns true if the
+ // connection needs to be closed.
+ virtual bool ValidateStatelessReset(
+ const quic::QuicSocketAddress& self_address,
+ const quic::QuicSocketAddress& peer_address) = 0;
+
// Called when the connection experiences a change in congestion window.
virtual void OnCongestionWindowChange(QuicTime now) = 0;
@@ -139,6 +146,9 @@ class QUIC_EXPORT_PRIVATE QuicConnectionVisitorInterface {
// Called when the peer seems unreachable over the current path.
virtual void OnPathDegrading() = 0;
+ // Called when forward progress made after path degrading.
+ virtual void OnForwardProgressMadeAfterPathDegrading() = 0;
+
// Called when the connection sends ack after
// max_consecutive_num_packets_with_no_retransmittable_frames_ consecutive not
// retransmittable packets sent. To instigate an ack from peer, a
@@ -155,9 +165,6 @@ class QUIC_EXPORT_PRIVATE QuicConnectionVisitorInterface {
// or yielded to other connections.
virtual bool WillingAndAbleToWrite() const = 0;
- // Called to ask if any handshake messages are pending in this visitor.
- virtual bool HasPendingHandshake() const = 0;
-
// Called to ask if the connection should be kept alive and prevented
// from timing out, for example if there are outstanding application
// transactions expecting a response.
@@ -170,10 +177,6 @@ class QUIC_EXPORT_PRIVATE QuicConnectionVisitorInterface {
// Called to get current handshake state.
virtual HandshakeState GetHandshakeState() const = 0;
- // Called when an ACK is received with a larger |largest_acked| than
- // previously observed.
- virtual void OnForwardProgressConfirmed() = 0;
-
// Called when a STOP_SENDING frame has been received.
virtual void OnStopSendingFrame(const QuicStopSendingFrame& frame) = 0;
@@ -341,6 +344,14 @@ class QUIC_EXPORT_PRIVATE QuicConnectionDebugVisitor
// Called when |count| packet numbers have been skipped.
virtual void OnNPacketNumbersSkipped(QuicPacketCount /*count*/) {}
+
+ // Called for QUIC+TLS versions when we send transport parameters.
+ virtual void OnTransportParametersSent(
+ const TransportParameters& /*transport_parameters*/) {}
+
+ // Called for QUIC+TLS versions when we receive transport parameters.
+ virtual void OnTransportParametersReceived(
+ const TransportParameters& /*transport_parameters*/) {}
};
class QUIC_EXPORT_PRIVATE QuicConnectionHelperInterface {
@@ -458,11 +469,6 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Returns statistics tracked for this connection.
const QuicConnectionStats& GetStats();
- // Mark stats_.has_non_app_limited_sample as false.
- // TODO(b/151166631) Remove this once the proper fix in b/151166631 is rolled
- // out.
- void ResetHasNonAppLimitedSampleAfterHandshakeCompletion();
-
// Processes an incoming UDP packet (consisting of a QuicEncryptedPacket) from
// the peer.
// In a client, the packet may be "stray" and have a different connection ID
@@ -578,6 +584,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection
bool OnNewTokenFrame(const QuicNewTokenFrame& frame) override;
bool OnMessageFrame(const QuicMessageFrame& frame) override;
bool OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& frame) override;
+ bool OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame) override;
void OnPacketComplete() override;
bool IsValidStatelessResetToken(QuicUint128 token) const override;
void OnAuthenticatedIetfStatelessResetPacket(
@@ -587,7 +594,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection
bool ShouldGeneratePacket(HasRetransmittableData retransmittable,
IsHandshake handshake) override;
const QuicFrames MaybeBundleAckOpportunistically() override;
- char* GetPacketBuffer() override;
+ QuicPacketBuffer GetPacketBuffer() override;
void OnSerializedPacket(SerializedPacket packet) override;
void OnUnrecoverableError(QuicErrorCode error,
const std::string& error_details) override;
@@ -669,14 +676,10 @@ class QUIC_EXPORT_PRIVATE QuicConnection
return server_supported_versions_;
}
- // Testing only.
+ bool HasQueuedPackets() const { return !buffered_packets_.empty(); }
+ // Testing only. TODO(ianswett): Use a peer instead.
size_t NumQueuedPackets() const { return buffered_packets_.size(); }
- // Returns true if the underlying UDP socket is writable, there is
- // no queued data and the connection is not congestion-control
- // blocked.
- bool CanWriteStreamData();
-
// Returns true if the connection has queued packets or frames.
bool HasQueuedData() const;
@@ -695,19 +698,13 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Sets up a packet with an QuicAckFrame and sends it out.
void SendAck();
- // Called when the path degrading alarm fires.
- void OnPathDegradingTimeout();
-
// Called when an RTO fires. Resets the retransmission alarm if there are
// remaining unacked packets.
void OnRetransmissionTimeout();
- // Retransmits all unacked packets with retransmittable frames if
- // |retransmission_type| is ALL_UNACKED_PACKETS, otherwise retransmits only
- // initially encrypted packets. Used when the negotiated protocol version is
- // different from what was initially assumed and when the initial encryption
- // changes.
- void RetransmitUnackedPackets(TransmissionType retransmission_type);
+ // Retransmits all sent 0-RTT encrypted packets. Called when new 0-RTT or
+ // 1-RTT key is available.
+ void RetransmitZeroRttPackets();
// Calls |sent_packet_manager_|'s NeuterUnencryptedPackets. Used when the
// connection becomes forward secure and hasn't received acks for all packets.
@@ -942,9 +939,13 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Returns the largest received packet number sent by peer.
QuicPacketNumber GetLargestReceivedPacket() const;
- // Adds the connection ID to a set of connection IDs that are accepted as
- // destination on incoming packets.
- void AddIncomingConnectionId(QuicConnectionId connection_id);
+ // Sets the original destination connection ID on the connection.
+ // This is called by QuicDispatcher when it has replaced the connection ID.
+ void SetOriginalDestinationConnectionId(
+ const QuicConnectionId& original_destination_connection_id);
+
+ // Returns the original destination connection ID used for this connection.
+ QuicConnectionId GetOriginalDestinationConnectionId();
// Called when ACK alarm goes off. Sends ACKs of those packet number spaces
// which have expired ACK timeout. Only used when this connection supports
@@ -965,6 +966,30 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Called when version is considered negotiated.
void OnSuccessfulVersionNegotiation();
+ // Called when self migration succeeds after probing.
+ void OnSuccessfulMigrationAfterProbing();
+
+ // Called for QUIC+TLS versions when we send transport parameters.
+ void OnTransportParametersSent(
+ const TransportParameters& transport_parameters) const;
+
+ // Called for QUIC+TLS versions when we receive transport parameters.
+ void OnTransportParametersReceived(
+ const TransportParameters& transport_parameters) const;
+
+ // Returns true if ack_alarm_ is set.
+ bool HasPendingAcks() const;
+
+ size_t anti_amplification_factor() const {
+ return anti_amplification_factor_;
+ }
+
+ void OnUserAgentIdKnown() { sent_packet_manager_.OnUserAgentIdKnown(); }
+
+ // Enables Legacy Version Encapsulation using |server_name| as SNI.
+ // Can only be set if this is a client connection.
+ void EnableLegacyVersionEncapsulation(const std::string& server_name);
+
protected:
// Calls cancel() on all the alarms owned by this connection.
void CancelAllAlarms();
@@ -1075,12 +1100,16 @@ class QUIC_EXPORT_PRIVATE QuicConnection
struct QUIC_EXPORT_PRIVATE UndecryptablePacket {
UndecryptablePacket(const QuicEncryptedPacket& packet,
EncryptionLevel encryption_level)
- : packet(packet.Clone()), encryption_level(encryption_level) {}
+ : packet(packet.Clone()),
+ encryption_level(encryption_level),
+ processed(false) {}
std::unique_ptr<QuicEncryptedPacket> packet;
- // Currently, |encryption_level| is only used for logging and does not
- // affect processing of the packet.
EncryptionLevel encryption_level;
+ // This gets set to true if 1) connection sucessfully processed the packet
+ // or 2) connection failed to process the packet and will not try to process
+ // it later.
+ bool processed;
};
// Notifies the visitor of the close and marks the connection as disconnected.
@@ -1237,6 +1266,10 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// received packet number which contains an ACK frame.
void SetLargestReceivedPacketWithAck(QuicPacketNumber new_value);
+ // Called when new packets have been acknowledged or old keys have been
+ // discarded.
+ void OnForwardProgressMade();
+
// Returns largest received packet number which contains an ACK frame.
QuicPacketNumber GetLargestReceivedPacketWithAck() const;
@@ -1285,6 +1318,30 @@ class QUIC_EXPORT_PRIVATE QuicConnection
QuicTime::Delta GetHandshakeTimeout() const;
QuicTime GetTimeOfLastReceivedPacket() const;
+ // Validate connection IDs used during the handshake. Closes the connection
+ // on validation failure.
+ bool ValidateConfigConnectionIds(const QuicConfig& config);
+ bool ValidateConfigConnectionIdsOld(const QuicConfig& config);
+
+ // Called when ACK alarm goes off. Try to bundle crypto data with the ACK of
+ // |space|.
+ void MaybeBundleCryptoDataWithAckOfSpace(PacketNumberSpace space);
+
+ // Returns true if an undecryptable packet of |decryption_level| should be
+ // buffered (such that connection can try to decrypt it later).
+ bool ShouldEnqueueUnDecryptablePacket(EncryptionLevel decryption_level,
+ bool has_decryption_key) const;
+
+ // Returns string which contains undecryptable packets information.
+ std::string UndecryptablePacketsInfo() const;
+
+ // Sets the max packet length on the packet creator if needed.
+ void MaybeUpdatePacketCreatorMaxPacketLengthAndPadding();
+
+ // Sets internal state to enable or disable Legacy Version Encapsulation.
+ void MaybeActivateLegacyVersionEncapsulation();
+ void MaybeDisactivateLegacyVersionEncapsulation();
+
QuicFramer framer_;
// Contents received in the current packet, especially used to identify
@@ -1394,9 +1451,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// a connection close packet is sent, but not after.
ConnectionCloseBehavior idle_timeout_connection_close_behavior_;
- // When true, close the QUIC connection after 5 RTOs. Due to the min rto of
- // 200ms, this is over 5 seconds.
- bool close_connection_after_five_rtos_;
+ // When > 0, close the QUIC connection after this number of RTOs.
+ size_t num_rtos_for_blackhole_detection_;
UberReceivedPacketManager uber_received_packet_manager_;
@@ -1601,18 +1657,19 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// vector to improve performance since it is expected to be very small.
std::vector<QuicConnectionId> incoming_connection_ids_;
- // When we receive a RETRY packet, we replace |server_connection_id_| with the
- // value from the RETRY packet and save off the original value of
- // |server_connection_id_| into |original_connection_id_| for validation.
- quiche::QuicheOptional<QuicConnectionId> original_connection_id_;
+ // When we receive a RETRY packet or some INITIAL packets, we replace
+ // |server_connection_id_| with the value from that packet and save off the
+ // original value of |server_connection_id_| into
+ // |original_destination_connection_id_| for validation.
+ quiche::QuicheOptional<QuicConnectionId> original_destination_connection_id_;
+
+ // After we receive a RETRY packet, |retry_source_connection_id_| contains
+ // the source connection ID from that packet.
+ quiche::QuicheOptional<QuicConnectionId> retry_source_connection_id_;
// Indicates whether received RETRY packets should be dropped.
bool drop_incoming_retry_packets_;
- // If max_consecutive_ptos_ > 0, close connection if consecutive PTOs is
- // greater than max_consecutive_ptos.
- size_t max_consecutive_ptos_;
-
// Bytes received before address validation. Only used when
// EnforceAntiAmplificationLimit returns true.
size_t bytes_received_before_address_validation_;
@@ -1644,14 +1701,40 @@ class QUIC_EXPORT_PRIVATE QuicConnection
QuicIdleNetworkDetector idle_network_detector_;
+ bool blackhole_detection_disabled_ = false;
+
+ // True if this connection supports handshake done frame.
+ bool support_handshake_done_;
+
const bool use_idle_network_detector_ =
GetQuicReloadableFlag(quic_use_idle_network_detector);
- const bool extend_idle_time_on_decryptable_packets_ =
- GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets);
-
- const bool advance_ack_timeout_update_ =
- GetQuicReloadableFlag(quic_advance_ack_timeout_update);
+ const bool update_ack_alarm_in_send_all_pending_acks_ =
+ GetQuicReloadableFlag(quic_update_ack_alarm_in_send_all_pending_acks);
+
+ const bool move_amplification_limit_ =
+ GetQuicReloadableFlag(quic_move_amplification_limit);
+
+ // TODO(fayang): Change the default value of quic_anti_amplification_factor to
+ // 5 when deprecating quic_move_amplification_limit.
+ // TODO(b/153892665): Change the default value of
+ // quic_anti_amplification_factor back to 3 when cert compression is
+ // supported.
+ const size_t anti_amplification_factor_ =
+ move_amplification_limit_
+ ? 5
+ : GetQuicFlag(FLAGS_quic_anti_amplification_factor);
+
+ const bool default_enable_5rto_blackhole_detection_ =
+ GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2);
+
+ // Whether the Legacy Version Encapsulation feature is enabled.
+ bool legacy_version_encapsulation_enabled_ = false;
+ // Whether we are in the middle of sending a packet using Legacy Version
+ // Encapsulation.
+ bool legacy_version_encapsulation_in_progress_ = false;
+ // SNI to send when using Legacy Version Encapsulation.
+ std::string legacy_version_encapsulation_sni_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc
index 89f7e546d88..191918c9887 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc
@@ -53,6 +53,8 @@ std::ostream& operator<<(std::ostream& os, const QuicConnectionStats& s) {
os << " num_coalesced_packets_processed: "
<< s.num_coalesced_packets_processed;
os << " num_ack_aggregation_epochs: " << s.num_ack_aggregation_epochs;
+ os << " sent_legacy_version_encapsulated_packets: "
+ << s.sent_legacy_version_encapsulated_packets;
os << " }";
return os;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h
index 3b0c85d2228..3579be0f6f4 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h
@@ -47,9 +47,21 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionStats {
QuicPacketCount packets_lost = 0;
QuicPacketCount packet_spuriously_detected_lost = 0;
- // The sum of the detection time of all lost packets. The detection time of a
- // lost packet is defined as: T(detection) - T(send).
- QuicTime::Delta total_loss_detection_time = QuicTime::Delta::Zero();
+ // The sum of loss detection response times of all lost packets, in number of
+ // round trips.
+ // Given a packet detected as lost:
+ // T(S) T(1Rtt) T(D)
+ // |_________________________________|_______|
+ // Where
+ // T(S) is the time when the packet is sent.
+ // T(1Rtt) is one rtt after T(S), using the rtt at the time of detection.
+ // T(D) is the time of detection, i.e. when the packet is declared as lost.
+ // The loss detection response time is defined as
+ // (T(D) - T(S)) / (T(1Rtt) - T(S))
+ //
+ // The average loss detection response time is this number divided by
+ // |packets_lost|. Smaller result means detection is faster.
+ float total_loss_detection_response_time = 0.0;
// Number of times this connection went through the slow start phase.
uint32_t slowstart_count = 0;
@@ -90,6 +102,7 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionStats {
int64_t min_rtt_us = 0; // Minimum RTT in microseconds.
int64_t srtt_us = 0; // Smoothed RTT in microseconds.
+ int64_t cwnd_bootstrapping_rtt_us = 0; // RTT used in cwnd_bootstrapping.
QuicByteCount max_packet_size = 0;
QuicByteCount max_received_packet_size = 0;
QuicBandwidth estimated_bandwidth = QuicBandwidth::Zero();
@@ -104,6 +117,9 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionStats {
// Maximum sequence reordering observed from acked packets.
QuicPacketCount sent_packets_max_sequence_reordering = 0;
+ // Number of times that a packet is not detected as lost per reordering_shift,
+ // but would have been if the reordering_shift increases by one.
+ QuicPacketCount sent_packets_num_borderline_time_reorderings = 0;
// The following stats are used only in TcpCubicSender.
// The number of loss events from TCP's perspective. Each loss event includes
@@ -136,6 +152,16 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionStats {
// Whether there is any non app-limited bandwidth sample.
bool has_non_app_limited_sample = false;
+
+ // Packet number of first decrypted packet.
+ QuicPacketNumber first_decrypted_packet;
+
+ // Max consecutive retransmission timeout before making forward progress.
+ size_t max_consecutive_rto_with_forward_progress = 0;
+
+ // Number of sent packets that were encapsulated using Legacy Version
+ // Encapsulation.
+ QuicPacketCount sent_legacy_version_encapsulated_packets = 0;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc
index 24f233ef233..7fc45caefb3 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc
@@ -18,6 +18,7 @@
#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
@@ -28,6 +29,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
#include "net/third_party/quiche/src/quic/test_tools/mock_random.h"
@@ -48,7 +50,6 @@ using testing::_;
using testing::AnyNumber;
using testing::AtLeast;
using testing::DoAll;
-using testing::Exactly;
using testing::Ge;
using testing::IgnoreResult;
using testing::InSequence;
@@ -336,6 +337,11 @@ class TestAlarmFactory : public QuicAlarmFactory {
};
class TestPacketWriter : public QuicPacketWriter {
+ struct PacketBuffer {
+ QUIC_CACHELINE_ALIGNED char buffer[1500];
+ bool in_use = false;
+ };
+
public:
TestPacketWriter(ParsedQuicVersion version, MockClock* clock)
: version_(version),
@@ -344,16 +350,40 @@ class TestPacketWriter : public QuicPacketWriter {
QuicFramerPeer::SetLastSerializedServerConnectionId(framer_.framer(),
TestConnectionId());
framer_.framer()->SetInitialObfuscators(TestConnectionId());
+
+ for (int i = 0; i < 128; ++i) {
+ PacketBuffer* p = new PacketBuffer();
+ packet_buffer_pool_.push_back(p);
+ packet_buffer_pool_index_[p->buffer] = p;
+ packet_buffer_free_list_.push_back(p);
+ }
}
TestPacketWriter(const TestPacketWriter&) = delete;
TestPacketWriter& operator=(const TestPacketWriter&) = delete;
+ ~TestPacketWriter() override {
+ EXPECT_EQ(packet_buffer_pool_.size(), packet_buffer_free_list_.size())
+ << packet_buffer_pool_.size() - packet_buffer_free_list_.size()
+ << " out of " << packet_buffer_pool_.size()
+ << " packet buffers have been leaked.";
+ for (auto p : packet_buffer_pool_) {
+ delete p;
+ }
+ }
+
// QuicPacketWriter interface
WriteResult WritePacket(const char* buffer,
size_t buf_len,
const QuicIpAddress& /*self_address*/,
const QuicSocketAddress& /*peer_address*/,
PerPacketOptions* /*options*/) override {
+ // If the buffer is allocated from the pool, return it back to the pool.
+ // Note the buffer content doesn't change.
+ if (packet_buffer_pool_index_.find(const_cast<char*>(buffer)) !=
+ packet_buffer_pool_index_.end()) {
+ FreePacketBuffer(buffer);
+ }
+
QuicEncryptedPacket packet(buffer, buf_len);
++packets_write_attempts_;
@@ -440,10 +470,15 @@ class TestPacketWriter : public QuicPacketWriter {
bool IsBatchMode() const override { return is_batch_mode_; }
- char* GetNextWriteLocation(
+ QuicPacketBuffer GetNextWriteLocation(
const QuicIpAddress& /*self_address*/,
const QuicSocketAddress& /*peer_address*/) override {
- return nullptr;
+ if (GetQuicReloadableFlag(quic_avoid_leak_writer_buffer)) {
+ return {AllocPacketBuffer(),
+ [this](const char* p) { FreePacketBuffer(p); }};
+ }
+ // Do not use writer buffer for serializing packets.
+ return {nullptr, nullptr};
}
WriteResult Flush() override {
@@ -591,6 +626,23 @@ class TestPacketWriter : public QuicPacketWriter {
SimpleQuicFramer* framer() { return &framer_; }
private:
+ char* AllocPacketBuffer() {
+ PacketBuffer* p = packet_buffer_free_list_.front();
+ EXPECT_FALSE(p->in_use);
+ p->in_use = true;
+ packet_buffer_free_list_.pop_front();
+ return p->buffer;
+ }
+
+ void FreePacketBuffer(const char* buffer) {
+ auto iter = packet_buffer_pool_index_.find(const_cast<char*>(buffer));
+ ASSERT_TRUE(iter != packet_buffer_pool_index_.end());
+ PacketBuffer* p = iter->second;
+ ASSERT_TRUE(p->in_use);
+ p->in_use = false;
+ packet_buffer_free_list_.push_back(p);
+ }
+
ParsedQuicVersion version_;
SimpleQuicFramer framer_;
size_t last_packet_size_ = 0;
@@ -619,6 +671,12 @@ class TestPacketWriter : public QuicPacketWriter {
QuicTime::Delta write_pause_time_delta_ = QuicTime::Delta::Zero();
QuicByteCount max_packet_size_ = kMaxOutgoingPacketSize;
bool supports_release_time_ = false;
+ // Used to verify writer-allocated packet buffers are properly released.
+ std::vector<PacketBuffer*> packet_buffer_pool_;
+ // Buffer address => Address of the owning PacketBuffer.
+ QuicHashMap<char*, PacketBuffer*> packet_buffer_pool_index_;
+ // Indices in packet_buffer_pool_ that are not allocated.
+ std::list<PacketBuffer*> packet_buffer_free_list_;
};
class TestConnection : public QuicConnection {
@@ -739,7 +797,7 @@ class TestConnection : public QuicConnection {
// Ensures the connection can write stream data before writing.
QuicConsumedData EnsureWritableAndSendStreamData5() {
- EXPECT_TRUE(CanWriteStreamData());
+ EXPECT_TRUE(CanWrite(HAS_RETRANSMITTABLE_DATA));
return SendStreamData5();
}
@@ -1091,14 +1149,12 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
EXPECT_CALL(*send_algorithm_, OnApplicationLimited(_)).Times(AnyNumber());
EXPECT_CALL(visitor_, WillingAndAbleToWrite()).Times(AnyNumber());
EXPECT_CALL(visitor_, OnPacketDecrypted(_)).Times(AnyNumber());
- EXPECT_CALL(visitor_, HasPendingHandshake()).Times(AnyNumber());
EXPECT_CALL(visitor_, OnCanWrite())
.WillRepeatedly(Invoke(&notifier_, &SimpleSessionNotifier::OnCanWrite));
EXPECT_CALL(visitor_, ShouldKeepConnectionAlive())
.WillRepeatedly(Return(false));
EXPECT_CALL(visitor_, OnCongestionWindowChange(_)).Times(AnyNumber());
EXPECT_CALL(visitor_, OnPacketReceived(_, _, _)).Times(AnyNumber());
- EXPECT_CALL(visitor_, OnForwardProgressConfirmed()).Times(AnyNumber());
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)).Times(AnyNumber());
EXPECT_CALL(visitor_, OnOneRttPacketAcknowledged())
.Times(testing::AtMost(1));
@@ -1317,9 +1373,8 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
level);
}
- size_t ProcessCryptoPacketAtLevel(uint64_t number,
- EncryptionLevel /*level*/) {
- QuicPacketHeader header = ConstructPacketHeader(number, ENCRYPTION_INITIAL);
+ size_t ProcessCryptoPacketAtLevel(uint64_t number, EncryptionLevel level) {
+ QuicPacketHeader header = ConstructPacketHeader(number, level);
QuicFrames frames;
if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
frames.push_back(QuicFrame(&crypto_frame_));
@@ -1329,10 +1384,10 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
frames.push_back(QuicFrame(QuicPaddingFrame(-1)));
std::unique_ptr<QuicPacket> packet = ConstructPacket(header, frames);
char buffer[kMaxOutgoingPacketSize];
- peer_creator_.set_encryption_level(ENCRYPTION_INITIAL);
- size_t encrypted_length = peer_framer_.EncryptPayload(
- ENCRYPTION_INITIAL, QuicPacketNumber(number), *packet, buffer,
- kMaxOutgoingPacketSize);
+ peer_creator_.set_encryption_level(level);
+ size_t encrypted_length =
+ peer_framer_.EncryptPayload(level, QuicPacketNumber(number), *packet,
+ buffer, kMaxOutgoingPacketSize);
connection_.ProcessUdpPacket(
kSelfAddress, kPeerAddress,
QuicReceivedPacket(buffer, encrypted_length, clock_.Now(), false));
@@ -1694,6 +1749,9 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
void MtuDiscoveryTestInit() {
set_perspective(Perspective::IS_SERVER);
QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
+ if (version().SupportsAntiAmplificationLimit()) {
+ QuicConnectionPeer::SetAddressValidated(&connection_);
+ }
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
peer_creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
// QuicFramer::GetMaxPlaintextSize uses the smallest max plaintext size
@@ -1712,9 +1770,21 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
EXPECT_TRUE(connection_.connected());
}
+ void PathProbeTestInit(Perspective perspective) {
+ set_perspective(perspective);
+ EXPECT_EQ(connection_.perspective(), perspective);
+ if (perspective == Perspective::IS_SERVER) {
+ QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
+ }
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ peer_creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+ }
+
void TestClientRetryHandling(bool invalid_retry_tag,
- bool missing_id_in_config,
- bool wrong_id_in_config);
+ bool missing_original_id_in_config,
+ bool wrong_original_id_in_config,
+ bool missing_retry_id_in_config,
+ bool wrong_retry_id_in_config);
QuicConnectionId connection_id_;
QuicFramer framer_;
@@ -1941,6 +2011,9 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) {
set_perspective(Perspective::IS_SERVER);
QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective());
+ if (version().SupportsAntiAmplificationLimit()) {
+ QuicConnectionPeer::SetAddressValidated(&connection_);
+ }
// Clear direct_peer_address.
QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress());
@@ -2022,9 +2095,7 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) {
}
TEST_P(QuicConnectionTest, ReceivePathProbeWithNoAddressChangeAtServer) {
- set_perspective(Perspective::IS_SERVER);
- QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
- EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective());
+ PathProbeTestInit(Perspective::IS_SERVER);
// Clear direct_peer_address.
QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress());
@@ -2068,9 +2139,6 @@ TEST_P(QuicConnectionTest, ReceivePathProbeWithNoAddressChangeAtServer) {
// Regression test for b/150161358.
TEST_P(QuicConnectionTest, BufferedMtuPacketTooBig) {
- if (!GetQuicReloadableFlag(quic_ignore_msg_too_big_from_buffered_packets)) {
- return;
- }
EXPECT_CALL(visitor_, OnWriteBlocked()).Times(1);
writer_->SetWriteBlocked();
@@ -2138,9 +2206,7 @@ TEST_P(QuicConnectionTest, DiscardQueuedPacketsAfterConnectionClose) {
// in IETF version: receive a packet contains PATH CHALLENGE with peer address
// change.
TEST_P(QuicConnectionTest, ReceivePathProbingAtServer) {
- set_perspective(Perspective::IS_SERVER);
- QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
- EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective());
+ PathProbeTestInit(Perspective::IS_SERVER);
// Clear direct_peer_address.
QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress());
@@ -2278,9 +2344,7 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingWithPortChangeAtServer) {
}
TEST_P(QuicConnectionTest, ReceiveReorderedPathProbingAtServer) {
- set_perspective(Perspective::IS_SERVER);
- QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
- EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective());
+ PathProbeTestInit(Perspective::IS_SERVER);
// Clear direct_peer_address.
QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress());
@@ -2336,9 +2400,7 @@ TEST_P(QuicConnectionTest, ReceiveReorderedPathProbingAtServer) {
}
TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) {
- set_perspective(Perspective::IS_SERVER);
- QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
- EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective());
+ PathProbeTestInit(Perspective::IS_SERVER);
// Clear direct_peer_address.
QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress());
@@ -2393,8 +2455,7 @@ TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) {
TEST_P(QuicConnectionTest, ReceivePaddedPingAtClient) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- set_perspective(Perspective::IS_CLIENT);
- EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective());
+ PathProbeTestInit(Perspective::IS_CLIENT);
// Clear direct_peer_address.
QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress());
@@ -2442,8 +2503,7 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingResponseAtClient) {
return;
}
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- set_perspective(Perspective::IS_CLIENT);
- EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective());
+ PathProbeTestInit(Perspective::IS_CLIENT);
// Clear direct_peer_address.
QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress());
@@ -3129,9 +3189,12 @@ TEST_P(QuicConnectionTest, BasicSending) {
if (connection_.SupportsMultiplePacketNumberSpaces()) {
return;
}
+ const QuicConnectionStats& stats = connection_.GetStats();
+ EXPECT_FALSE(stats.first_decrypted_packet.IsInitialized());
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacket(1);
+ EXPECT_EQ(QuicPacketNumber(1), stats.first_decrypted_packet);
QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 2);
QuicPacketNumber last_packet;
SendStreamDataToPeer(1, "foo", 0, NO_FIN, &last_packet); // Packet 1
@@ -3215,6 +3278,7 @@ TEST_P(QuicConnectionTest, BasicSending) {
} else {
EXPECT_EQ(QuicPacketNumber(7u), least_unacked());
}
+ EXPECT_EQ(QuicPacketNumber(1), stats.first_decrypted_packet);
}
// QuicConnection should record the packet sent-time prior to sending the
@@ -3480,8 +3544,7 @@ TEST_P(QuicConnectionTest, LargeSendWithPendingAck) {
// Processs a PING frame.
ProcessFramePacket(QuicFrame(QuicPingFrame()));
// Ensure that this has caused the ACK alarm to be set.
- QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
- EXPECT_TRUE(ack_alarm->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
// Send data and ensure the ack is bundled.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(8);
@@ -3506,7 +3569,7 @@ TEST_P(QuicConnectionTest, LargeSendWithPendingAck) {
writer_->stream_frames()[0]->stream_id);
EXPECT_TRUE(writer_->stream_frames()[0]->fin);
// Ensure the ack alarm was cancelled when the ack was sent.
- EXPECT_FALSE(ack_alarm->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
}
TEST_P(QuicConnectionTest, OnCanWrite) {
@@ -4241,6 +4304,12 @@ TEST_P(QuicConnectionTest, TailLossProbeDelayForNonStreamDataInTLPR) {
options.push_back(kTLPR);
config.SetConnectionOptionsToSend(options);
QuicConfigPeer::SetNegotiated(&config, true);
+ if (connection_.version().AuthenticatesHandshakeConnectionIds()) {
+ QuicConfigPeer::SetReceivedOriginalConnectionId(
+ &config, connection_.connection_id());
+ QuicConfigPeer::SetReceivedInitialSourceConnectionId(
+ &config, connection_.connection_id());
+ }
connection_.SetFromConfig(config);
connection_.SetMaxTailLossProbes(1);
@@ -4414,47 +4483,6 @@ TEST_P(QuicConnectionTest, RtoWithNoDataToRetransmit) {
}
}
-TEST_P(QuicConnectionTest, RetransmitWithSameEncryptionLevel) {
- use_tagging_decrypter();
-
- // A TaggingEncrypter puts kTagSize copies of the given byte (0x01 here) at
- // the end of the packet. We can test this to check which encrypter was used.
- connection_.SetEncrypter(ENCRYPTION_INITIAL,
- std::make_unique<TaggingEncrypter>(0x01));
- QuicByteCount packet_size;
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillOnce(SaveArg<3>(&packet_size));
- connection_.SendCryptoDataWithString("foo", 0);
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber());
- EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet());
-
- connection_.SetEncrypter(ENCRYPTION_ZERO_RTT,
- std::make_unique<TaggingEncrypter>(0x02));
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
- SendStreamDataToPeer(3, "foo", 0, NO_FIN, nullptr);
- EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
-
- {
- InSequence s;
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, _, QuicPacketNumber(3), _, _));
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, _, QuicPacketNumber(4), _, _));
- }
-
- // Manually mark both packets for retransmission.
- connection_.RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION);
- if (!connection_.version().CanSendCoalescedPackets()) {
- // Packet should have been sent with ENCRYPTION_INITIAL.
- // If connection can send coalesced packet, both retransmissions will be
- // coalesced in the same UDP datagram.
- EXPECT_EQ(0x01010101u, writer_->final_bytes_of_previous_packet());
- }
-
- // Packet should have been sent with ENCRYPTION_ZERO_RTT.
- EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
-}
-
TEST_P(QuicConnectionTest, SendHandshakeMessages) {
use_tagging_decrypter();
// A TaggingEncrypter puts kTagSize copies of the given byte (0x01 here) at
@@ -4514,6 +4542,8 @@ TEST_P(QuicConnectionTest,
}
TEST_P(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) {
+ SetQuicReloadableFlag(quic_do_not_retransmit_immediately_on_zero_rtt_reject,
+ true);
use_tagging_decrypter();
connection_.SetEncrypter(ENCRYPTION_INITIAL,
std::make_unique<TaggingEncrypter>(0x01));
@@ -4526,9 +4556,9 @@ TEST_P(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) {
connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
SendStreamDataToPeer(2, "bar", 0, NO_FIN, nullptr);
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
-
- connection_.RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION);
+ EXPECT_FALSE(notifier_.HasLostStreamData());
+ connection_.RetransmitZeroRttPackets();
+ EXPECT_TRUE(notifier_.HasLostStreamData());
}
TEST_P(QuicConnectionTest, BufferNonDecryptablePackets) {
@@ -4739,7 +4769,7 @@ TEST_P(QuicConnectionTest, InitialTimeout) {
EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
EXPECT_FALSE(connection_.connected());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
EXPECT_FALSE(connection_.GetSendAlarm()->IsSet());
@@ -4794,7 +4824,7 @@ TEST_P(QuicConnectionTest, IdleTimeoutAfterFirstSentPacket) {
EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
EXPECT_FALSE(connection_.connected());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
EXPECT_FALSE(connection_.GetSendAlarm()->IsSet());
@@ -4838,7 +4868,7 @@ TEST_P(QuicConnectionTest, IdleTimeoutAfterSendTwoPackets) {
EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
EXPECT_FALSE(connection_.connected());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
EXPECT_FALSE(connection_.GetSendAlarm()->IsSet());
@@ -4885,7 +4915,7 @@ TEST_P(QuicConnectionTest, HandshakeTimeout) {
EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
EXPECT_FALSE(connection_.connected());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
EXPECT_FALSE(connection_.GetSendAlarm()->IsSet());
@@ -5764,6 +5794,12 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendAfterHandshake) {
config.ProcessPeerHello(msg, CLIENT, &error_details);
EXPECT_THAT(error, IsQuicNoError());
+ if (connection_.version().AuthenticatesHandshakeConnectionIds()) {
+ QuicConfigPeer::SetReceivedOriginalConnectionId(
+ &config, connection_.connection_id());
+ QuicConfigPeer::SetReceivedInitialSourceConnectionId(
+ &config, connection_.connection_id());
+ }
connection_.SetFromConfig(config);
const QuicTime::Delta default_idle_timeout =
@@ -5910,6 +5946,12 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseWithOpenStreams) {
config.ProcessPeerHello(msg, CLIENT, &error_details);
EXPECT_THAT(error, IsQuicNoError());
+ if (connection_.version().AuthenticatesHandshakeConnectionIds()) {
+ QuicConfigPeer::SetReceivedOriginalConnectionId(
+ &config, connection_.connection_id());
+ QuicConfigPeer::SetReceivedInitialSourceConnectionId(
+ &config, connection_.connection_id());
+ }
connection_.SetFromConfig(config);
const QuicTime::Delta default_idle_timeout =
@@ -6074,6 +6116,16 @@ TEST_P(QuicConnectionTest, TimeoutAfter5ClientRTOs) {
connection_options.push_back(k5RTO);
config.SetConnectionOptionsToSend(connection_options);
QuicConfigPeer::SetNegotiated(&config, true);
+ if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
+ EXPECT_CALL(visitor_, GetHandshakeState())
+ .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
+ }
+ if (connection_.version().AuthenticatesHandshakeConnectionIds()) {
+ QuicConfigPeer::SetReceivedOriginalConnectionId(
+ &config, connection_.connection_id());
+ QuicConfigPeer::SetReceivedInitialSourceConnectionId(
+ &config, connection_.connection_id());
+ }
connection_.SetFromConfig(config);
// Send stream data.
@@ -6212,7 +6264,7 @@ TEST_P(QuicConnectionTest, LoopThroughSendingPacketsWithTruncation) {
TEST_P(QuicConnectionTest, SendDelayedAck) {
QuicTime ack_time = clock_.ApproximateNow() + DefaultDelayedAckTime();
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
const uint8_t tag = 0x07;
SetDecrypter(ENCRYPTION_ZERO_RTT,
std::make_unique<StrictTaggingDecrypter>(tag));
@@ -6227,7 +6279,7 @@ TEST_P(QuicConnectionTest, SendDelayedAck) {
ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
// Simulate delayed ack alarm firing.
clock_.AdvanceTime(DefaultDelayedAckTime());
@@ -6242,7 +6294,7 @@ TEST_P(QuicConnectionTest, SendDelayedAck) {
EXPECT_FALSE(writer_->stop_waiting_frames().empty());
}
EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
}
TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) {
@@ -6251,7 +6303,7 @@ TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) {
// The beginning of the connection counts as quiescence.
QuicTime ack_time = clock_.ApproximateNow() + kAlarmGranularity;
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
const uint8_t tag = 0x07;
SetDecrypter(ENCRYPTION_ZERO_RTT,
std::make_unique<StrictTaggingDecrypter>(tag));
@@ -6266,7 +6318,7 @@ TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) {
ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
// Simulate delayed ack alarm firing.
clock_.AdvanceTime(DefaultDelayedAckTime());
@@ -6281,7 +6333,7 @@ TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) {
EXPECT_FALSE(writer_->stop_waiting_frames().empty());
}
EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
// Process another packet immedately after sending the ack and expect the
// ack alarm to be set delayed ack time in the future.
@@ -6290,7 +6342,7 @@ TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) {
ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
// Simulate delayed ack alarm firing.
clock_.AdvanceTime(DefaultDelayedAckTime());
@@ -6305,7 +6357,7 @@ TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) {
EXPECT_FALSE(writer_->stop_waiting_frames().empty());
}
EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
// Wait 1 second and ensure the ack alarm is set to 1ms in the future.
clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
@@ -6314,7 +6366,7 @@ TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) {
ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
}
@@ -6331,7 +6383,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimation) {
QuicTime ack_time = clock_.ApproximateNow() +
QuicTime::Delta::FromMilliseconds(kMinRttMs / 4);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
const uint8_t tag = 0x07;
SetDecrypter(ENCRYPTION_ZERO_RTT,
std::make_unique<StrictTaggingDecrypter>(tag));
@@ -6346,7 +6398,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimation) {
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
// The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
// instead of ENCRYPTION_INITIAL.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
@@ -6354,12 +6406,12 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimation) {
ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
// The 10th received packet causes an ack to be sent.
for (int i = 0; i < 9; ++i) {
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting,
ENCRYPTION_ZERO_RTT);
@@ -6374,7 +6426,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimation) {
EXPECT_FALSE(writer_->stop_waiting_frames().empty());
}
EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
}
TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) {
@@ -6391,7 +6443,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) {
QuicTime ack_time =
clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
const uint8_t tag = 0x07;
SetDecrypter(ENCRYPTION_ZERO_RTT,
std::make_unique<StrictTaggingDecrypter>(tag));
@@ -6406,7 +6458,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) {
ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
// Simulate delayed ack alarm firing.
clock_.AdvanceTime(DefaultDelayedAckTime());
@@ -6421,7 +6473,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) {
EXPECT_FALSE(writer_->stop_waiting_frames().empty());
}
EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
// Process another packet immedately after sending the ack and expect the
// ack alarm to be set delayed ack time in the future.
@@ -6430,7 +6482,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) {
ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
// Simulate delayed ack alarm firing.
clock_.AdvanceTime(DefaultDelayedAckTime());
@@ -6445,7 +6497,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) {
EXPECT_FALSE(writer_->stop_waiting_frames().empty());
}
EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
// Wait 1 second and enesure the ack alarm is set to 1ms in the future.
clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
@@ -6454,7 +6506,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) {
ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
// Process enough packets to get into ack decimation behavior.
@@ -6467,7 +6519,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) {
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(4 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
// The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
// instead of ENCRYPTION_INITIAL.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
@@ -6475,12 +6527,12 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) {
ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
// The 10th received packet causes an ack to be sent.
for (int i = 0; i < 9; ++i) {
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting,
ENCRYPTION_ZERO_RTT);
@@ -6495,7 +6547,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) {
EXPECT_FALSE(writer_->stop_waiting_frames().empty());
}
EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
// Wait 1 second and enesure the ack alarm is set to 1ms in the future.
clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
@@ -6505,7 +6557,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) {
ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
}
@@ -6529,7 +6581,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationUnlimitedAggregation) {
QuicTime ack_time = clock_.ApproximateNow() +
QuicTime::Delta::FromMilliseconds(kMinRttMs / 4);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
const uint8_t tag = 0x07;
SetDecrypter(ENCRYPTION_ZERO_RTT,
std::make_unique<StrictTaggingDecrypter>(tag));
@@ -6544,7 +6596,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationUnlimitedAggregation) {
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
// The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
// instead of ENCRYPTION_INITIAL.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
@@ -6552,19 +6604,19 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationUnlimitedAggregation) {
ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
// 18 packets will not cause an ack to be sent. 19 will because when
// stop waiting frames are in use, we ack every 20 packets no matter what.
for (int i = 0; i < 18; ++i) {
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting,
ENCRYPTION_ZERO_RTT);
}
// The delayed ack timer should still be set to the expected deadline.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
}
@@ -6582,7 +6634,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) {
QuicTime ack_time = clock_.ApproximateNow() +
QuicTime::Delta::FromMilliseconds(kMinRttMs / 8);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
const uint8_t tag = 0x07;
SetDecrypter(ENCRYPTION_ZERO_RTT,
std::make_unique<StrictTaggingDecrypter>(tag));
@@ -6597,7 +6649,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) {
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
// The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
// instead of ENCRYPTION_INITIAL.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
@@ -6605,12 +6657,12 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) {
ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
// The 10th received packet causes an ack to be sent.
for (int i = 0; i < 9; ++i) {
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting,
ENCRYPTION_ZERO_RTT);
@@ -6625,7 +6677,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) {
EXPECT_FALSE(writer_->stop_waiting_frames().empty());
}
EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
}
TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) {
@@ -6641,7 +6693,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) {
QuicTime ack_time = clock_.ApproximateNow() +
QuicTime::Delta::FromMilliseconds(kMinRttMs / 4);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
const uint8_t tag = 0x07;
SetDecrypter(ENCRYPTION_ZERO_RTT,
std::make_unique<StrictTaggingDecrypter>(tag));
@@ -6656,7 +6708,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) {
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
// Receive one packet out of order and then the rest in order.
// The loop leaves a one packet gap between acks sent to simulate some loss.
@@ -6666,13 +6718,13 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) {
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 9 + (j * 11),
!kHasStopWaiting, ENCRYPTION_ZERO_RTT);
ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
// The 10th received packet causes an ack to be sent.
writer_->Reset();
for (int i = 0; i < 9; ++i) {
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
// The ACK shouldn't be sent until the 10th packet is processed.
EXPECT_TRUE(writer_->ack_frames().empty());
@@ -6689,7 +6741,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) {
EXPECT_FALSE(writer_->stop_waiting_frames().empty());
}
EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
}
}
@@ -6706,7 +6758,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) {
QuicTime ack_time = clock_.ApproximateNow() +
QuicTime::Delta::FromMilliseconds(kMinRttMs / 4);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
const uint8_t tag = 0x07;
SetDecrypter(ENCRYPTION_ZERO_RTT,
std::make_unique<StrictTaggingDecrypter>(tag));
@@ -6721,7 +6773,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) {
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
// The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
// instead of ENCRYPTION_INITIAL.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
@@ -6729,7 +6781,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) {
ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
// Process packet 10 first and ensure the alarm is one eighth min_rtt.
@@ -6737,12 +6789,12 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) {
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 19, !kHasStopWaiting,
ENCRYPTION_ZERO_RTT);
ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
// The 10th received packet causes an ack to be sent.
for (int i = 0; i < 8; ++i) {
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting,
ENCRYPTION_ZERO_RTT);
@@ -6756,11 +6808,11 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) {
EXPECT_FALSE(writer_->stop_waiting_frames().empty());
}
EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
// The next packet received in order will cause an immediate ack,
// because it fills a hole.
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 10, !kHasStopWaiting,
ENCRYPTION_ZERO_RTT);
@@ -6773,7 +6825,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) {
EXPECT_FALSE(writer_->stop_waiting_frames().empty());
}
EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
}
TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) {
@@ -6790,7 +6842,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) {
QuicTime ack_time = clock_.ApproximateNow() +
QuicTime::Delta::FromMilliseconds(kMinRttMs / 8);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
const uint8_t tag = 0x07;
SetDecrypter(ENCRYPTION_ZERO_RTT,
std::make_unique<StrictTaggingDecrypter>(tag));
@@ -6805,7 +6857,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) {
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
// The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
// instead of ENCRYPTION_INITIAL.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
@@ -6813,7 +6865,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) {
ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
// Process packet 10 first and ensure the alarm is one eighth min_rtt.
@@ -6821,12 +6873,12 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) {
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 9, !kHasStopWaiting,
ENCRYPTION_ZERO_RTT);
ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
// The 10th received packet causes an ack to be sent.
for (int i = 0; i < 8; ++i) {
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting,
ENCRYPTION_ZERO_RTT);
@@ -6841,7 +6893,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) {
EXPECT_FALSE(writer_->stop_waiting_frames().empty());
}
EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
}
TEST_P(QuicConnectionTest,
@@ -6859,7 +6911,7 @@ TEST_P(QuicConnectionTest,
QuicTime ack_time = clock_.ApproximateNow() +
QuicTime::Delta::FromMilliseconds(kMinRttMs / 8);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
const uint8_t tag = 0x07;
SetDecrypter(ENCRYPTION_ZERO_RTT,
std::make_unique<StrictTaggingDecrypter>(tag));
@@ -6874,7 +6926,7 @@ TEST_P(QuicConnectionTest,
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
// The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
// instead of ENCRYPTION_INITIAL.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
@@ -6882,7 +6934,7 @@ TEST_P(QuicConnectionTest,
ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
// Process packet 10 first and ensure the alarm is one eighth min_rtt.
@@ -6890,12 +6942,12 @@ TEST_P(QuicConnectionTest,
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 19, !kHasStopWaiting,
ENCRYPTION_ZERO_RTT);
ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
// The 10th received packet causes an ack to be sent.
for (int i = 0; i < 8; ++i) {
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting,
ENCRYPTION_ZERO_RTT);
@@ -6909,11 +6961,11 @@ TEST_P(QuicConnectionTest,
EXPECT_FALSE(writer_->stop_waiting_frames().empty());
}
EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
// The next packet received in order will cause an immediate ack,
// because it fills a hole.
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 10, !kHasStopWaiting,
ENCRYPTION_ZERO_RTT);
@@ -6926,27 +6978,27 @@ TEST_P(QuicConnectionTest,
EXPECT_FALSE(writer_->stop_waiting_frames().empty());
}
EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
}
TEST_P(QuicConnectionTest, SendDelayedAckOnHandshakeConfirmed) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(1);
// Check that ack is sent and that delayed ack alarm is set.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
QuicTime ack_time = clock_.ApproximateNow() + DefaultDelayedAckTime();
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
// Completing the handshake as the server does nothing.
QuicConnectionPeer::SetPerspective(&connection_, Perspective::IS_SERVER);
connection_.OnHandshakeComplete();
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
// Complete the handshake as the client decreases the delayed ack time to 0ms.
QuicConnectionPeer::SetPerspective(&connection_, Perspective::IS_CLIENT);
connection_.OnHandshakeComplete();
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
if (connection_.SupportsMultiplePacketNumberSpaces()) {
EXPECT_EQ(clock_.ApproximateNow() + DefaultDelayedAckTime(),
connection_.GetAckAlarm()->deadline());
@@ -6969,7 +7021,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckOnSecondPacket) {
EXPECT_FALSE(writer_->stop_waiting_frames().empty());
}
EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
}
TEST_P(QuicConnectionTest, NoAckOnOldNacks) {
@@ -7001,7 +7053,7 @@ TEST_P(QuicConnectionTest, NoAckOnOldNacks) {
ProcessPacket(6);
padding_frame_count = writer_->padding_frames().size();
EXPECT_EQ(padding_frame_count, writer_->frame_count());
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
}
TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingPacket) {
@@ -7025,7 +7077,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingPacket) {
EXPECT_FALSE(writer_->stop_waiting_frames().empty());
}
EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
}
TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingCryptoPacket) {
@@ -7045,7 +7097,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingCryptoPacket) {
EXPECT_EQ(4u, writer_->frame_count());
EXPECT_FALSE(writer_->stop_waiting_frames().empty());
}
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
}
TEST_P(QuicConnectionTest, BlockAndBufferOnFirstCHLOPacketOfTwo) {
@@ -7053,17 +7105,29 @@ TEST_P(QuicConnectionTest, BlockAndBufferOnFirstCHLOPacketOfTwo) {
ProcessPacket(1);
BlockOnNextWrite();
writer_->set_is_write_blocked_data_buffered(true);
+ if (GetQuicReloadableFlag(quic_move_amplification_limit) &&
+ QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+ }
connection_.SendCryptoDataWithString("foo", 0);
EXPECT_TRUE(writer_->IsWriteBlocked());
EXPECT_FALSE(connection_.HasQueuedData());
connection_.SendCryptoDataWithString("bar", 3);
EXPECT_TRUE(writer_->IsWriteBlocked());
- EXPECT_TRUE(connection_.HasQueuedData());
+ if (GetQuicReloadableFlag(quic_move_amplification_limit) &&
+ QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ // CRYPTO frames are not flushed when writer is blocked.
+ EXPECT_FALSE(connection_.HasQueuedData());
+ } else {
+ EXPECT_TRUE(connection_.HasQueuedData());
+ }
}
TEST_P(QuicConnectionTest, BundleAckForSecondCHLO) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
EXPECT_CALL(visitor_, OnCanWrite())
.WillOnce(IgnoreResult(InvokeWithoutArgs(
&connection_, &TestConnection::SendCryptoStreamData)));
@@ -7092,12 +7156,12 @@ TEST_P(QuicConnectionTest, BundleAckForSecondCHLO) {
EXPECT_EQ(1u, writer_->padding_frames().size());
ASSERT_FALSE(writer_->ack_frames().empty());
EXPECT_EQ(QuicPacketNumber(2u), LargestAcked(writer_->ack_frames().front()));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
}
TEST_P(QuicConnectionTest, BundleAckForSecondCHLOTwoPacketReject) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
// Process two packets from the crypto stream, which is frame1_'s default,
// simulating a 2 packet reject.
@@ -7136,7 +7200,7 @@ TEST_P(QuicConnectionTest, BundleAckForSecondCHLOTwoPacketReject) {
EXPECT_EQ(1u, writer_->padding_frames().size());
ASSERT_FALSE(writer_->ack_frames().empty());
EXPECT_EQ(QuicPacketNumber(2u), LargestAcked(writer_->ack_frames().front()));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
}
TEST_P(QuicConnectionTest, BundleAckWithDataOnIncomingAck) {
@@ -7171,7 +7235,7 @@ TEST_P(QuicConnectionTest, BundleAckWithDataOnIncomingAck) {
// Check that no packet is sent and the ack alarm isn't set.
EXPECT_EQ(0u, writer_->frame_count());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
writer_->Reset();
// Send the same ack, but send both data and an ack together.
@@ -7199,7 +7263,7 @@ TEST_P(QuicConnectionTest, BundleAckWithDataOnIncomingAck) {
LargestAcked(writer_->ack_frames().front()));
}
EXPECT_EQ(1u, writer_->stream_frames().size());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
}
TEST_P(QuicConnectionTest, NoAckSentForClose) {
@@ -7221,7 +7285,7 @@ TEST_P(QuicConnectionTest, SendWhenDisconnected) {
connection_.CloseConnection(QUIC_PEER_GOING_AWAY, "no reason",
ConnectionCloseBehavior::SILENT_CLOSE);
EXPECT_FALSE(connection_.connected());
- EXPECT_FALSE(connection_.CanWriteStreamData());
+ EXPECT_FALSE(connection_.CanWrite(HAS_RETRANSMITTABLE_DATA));
std::unique_ptr<QuicPacket> packet =
ConstructDataPacket(1, !kHasStopWaiting, ENCRYPTION_INITIAL);
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(1), _, _))
@@ -7245,7 +7309,7 @@ TEST_P(QuicConnectionTest, SendConnectivityProbingWhenDisconnected) {
connection_.CloseConnection(QUIC_PEER_GOING_AWAY, "no reason",
ConnectionCloseBehavior::SILENT_CLOSE);
EXPECT_FALSE(connection_.connected());
- EXPECT_FALSE(connection_.CanWriteStreamData());
+ EXPECT_FALSE(connection_.CanWrite(HAS_RETRANSMITTABLE_DATA));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(1), _, _))
.Times(0);
@@ -7260,7 +7324,7 @@ TEST_P(QuicConnectionTest, SendConnectivityProbingWhenDisconnected) {
}
TEST_P(QuicConnectionTest, WriteBlockedAfterClientSendsConnectivityProbe) {
- EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective());
+ PathProbeTestInit(Perspective::IS_CLIENT);
TestPacketWriter probing_writer(version(), &clock_);
// Block next write so that sending connectivity probe will encounter a
// blocked write when send a connectivity probe to the peer.
@@ -7276,8 +7340,7 @@ TEST_P(QuicConnectionTest, WriteBlockedAfterClientSendsConnectivityProbe) {
}
TEST_P(QuicConnectionTest, WriterBlockedAfterServerSendsConnectivityProbe) {
- set_perspective(Perspective::IS_SERVER);
- QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
+ PathProbeTestInit(Perspective::IS_SERVER);
// Block next write so that sending connectivity probe will encounter a
// blocked write when send a connectivity probe to the peer.
@@ -7293,7 +7356,7 @@ TEST_P(QuicConnectionTest, WriterBlockedAfterServerSendsConnectivityProbe) {
}
TEST_P(QuicConnectionTest, WriterErrorWhenClientSendsConnectivityProbe) {
- EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective());
+ PathProbeTestInit(Perspective::IS_CLIENT);
TestPacketWriter probing_writer(version(), &clock_);
probing_writer.SetShouldWriteFail();
@@ -7308,8 +7371,7 @@ TEST_P(QuicConnectionTest, WriterErrorWhenClientSendsConnectivityProbe) {
}
TEST_P(QuicConnectionTest, WriterErrorWhenServerSendsConnectivityProbe) {
- set_perspective(Perspective::IS_SERVER);
- QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
+ PathProbeTestInit(Perspective::IS_SERVER);
writer_->SetShouldWriteFail();
// Connection should not be closed if a connectivity probe is failed to be
@@ -7356,6 +7418,7 @@ TEST_P(QuicConnectionTest, IetfStatelessReset) {
kTestStatelessResetToken));
std::unique_ptr<QuicReceivedPacket> received(
ConstructReceivedPacket(*packet, QuicTime::Zero()));
+ EXPECT_CALL(visitor_, ValidateStatelessReset(_, _)).WillOnce(Return(true));
EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_PEER))
.WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame));
connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received);
@@ -7629,6 +7692,7 @@ TEST_P(QuicConnectionTest, ConnectionCloseWhenWriteBlocked) {
}
TEST_P(QuicConnectionTest, OnPacketSentDebugVisitor) {
+ PathProbeTestInit(Perspective::IS_CLIENT);
MockQuicConnectionDebugVisitor debug_visitor;
connection_.set_debug_visitor(&debug_visitor);
@@ -7681,8 +7745,7 @@ TEST_P(QuicConnectionTest, WindowUpdateInstigateAcks) {
ProcessFramePacket(QuicFrame(window_update));
// Ensure that this has caused the ACK alarm to be set.
- QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
- EXPECT_TRUE(ack_alarm->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
}
TEST_P(QuicConnectionTest, BlockedFrameInstigateAcks) {
@@ -7695,8 +7758,7 @@ TEST_P(QuicConnectionTest, BlockedFrameInstigateAcks) {
ProcessFramePacket(QuicFrame(blocked));
// Ensure that this has caused the ACK alarm to be set.
- QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
- EXPECT_TRUE(ack_alarm->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
}
TEST_P(QuicConnectionTest, ReevaluateTimeUntilSendOnAck) {
@@ -7838,32 +7900,8 @@ TEST_P(QuicConnectionTest, SetRetransmissionAlarmForCryptoPacket) {
connection_.GetRetransmissionAlarm()->Fire();
}
-TEST_P(QuicConnectionTest, PathDegradingAlarmForCryptoPacket) {
- EXPECT_TRUE(connection_.connected());
- EXPECT_FALSE(connection_.PathDegradingDetectionInProgress());
- EXPECT_FALSE(connection_.IsPathDegrading());
-
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- connection_.SendCryptoStreamData();
-
- EXPECT_TRUE(connection_.PathDegradingDetectionInProgress());
- EXPECT_FALSE(connection_.IsPathDegrading());
- QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_)
- ->GetPathDegradingDelay();
- EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
- clock_.ApproximateNow());
-
- // Fire the path degrading alarm, path degrading signal should be sent to
- // the visitor.
- EXPECT_CALL(visitor_, OnPathDegrading());
- clock_.AdvanceTime(delay);
- connection_.PathDegradingTimeout();
- EXPECT_TRUE(connection_.IsPathDegrading());
- EXPECT_FALSE(connection_.PathDegradingDetectionInProgress());
-}
-
// Includes regression test for b/69979024.
-TEST_P(QuicConnectionTest, PathDegradingAlarmForNonCryptoPackets) {
+TEST_P(QuicConnectionTest, PathDegradingDetectionForNonCryptoPackets) {
EXPECT_TRUE(connection_.connected());
EXPECT_FALSE(connection_.PathDegradingDetectionInProgress());
EXPECT_FALSE(connection_.IsPathDegrading());
@@ -7874,21 +7912,21 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForNonCryptoPackets) {
for (int i = 0; i < 2; ++i) {
// Send a packet. Now there's a retransmittable packet on the wire, so the
- // path degrading alarm should be set.
+ // path degrading detection should be set.
connection_.SendStreamDataWithString(
GetNthClientInitiatedStreamId(1, connection_.transport_version()), data,
offset, NO_FIN);
offset += data_size;
EXPECT_TRUE(connection_.PathDegradingDetectionInProgress());
- // Check the deadline of the path degrading alarm.
+ // Check the deadline of the path degrading detection.
QuicTime::Delta delay =
QuicConnectionPeer::GetSentPacketManager(&connection_)
->GetPathDegradingDelay();
EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
clock_.ApproximateNow());
- // Send a second packet. The path degrading alarm's deadline should remain
- // the same.
+ // Send a second packet. The path degrading detection's deadline should
+ // remain the same.
// Regression test for b/69979024.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
QuicTime prev_deadline =
@@ -7902,7 +7940,7 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForNonCryptoPackets) {
connection_.GetBlackholeDetectorAlarm()->deadline());
// Now receive an ACK of the first packet. This should advance the path
- // degrading alarm's deadline since forward progress has been made.
+ // degrading detection's deadline since forward progress has been made.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
if (i == 0) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -7912,7 +7950,7 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForNonCryptoPackets) {
{{QuicPacketNumber(1u + 2u * i), QuicPacketNumber(2u + 2u * i)}});
ProcessAckPacket(&frame);
EXPECT_TRUE(connection_.PathDegradingDetectionInProgress());
- // Check the deadline of the path degrading alarm.
+ // Check the deadline of the path degrading detection.
delay = QuicConnectionPeer::GetSentPacketManager(&connection_)
->GetPathDegradingDelay();
EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
@@ -7921,7 +7959,7 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForNonCryptoPackets) {
if (i == 0) {
// Now receive an ACK of the second packet. Since there are no more
// retransmittable packets on the wire, this should cancel the path
- // degrading alarm.
+ // degrading detection.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}});
@@ -8010,7 +8048,7 @@ TEST_P(QuicConnectionTest, RetransmittableOnWireSetsPingAlarm) {
// This test verifies that the connection marks path as degrading and does not
// spin timer to detect path degrading when a new packet is sent on the
// degraded path.
-TEST_P(QuicConnectionTest, NoPathDegradingAlarmIfPathIsDegrading) {
+TEST_P(QuicConnectionTest, NoPathDegradingDetectionIfPathIsDegrading) {
EXPECT_TRUE(connection_.connected());
EXPECT_FALSE(connection_.PathDegradingDetectionInProgress());
EXPECT_FALSE(connection_.IsPathDegrading());
@@ -8024,13 +8062,13 @@ TEST_P(QuicConnectionTest, NoPathDegradingAlarmIfPathIsDegrading) {
connection_.SendStreamDataWithString(1, data, offset, NO_FIN);
offset += data_size;
EXPECT_TRUE(connection_.PathDegradingDetectionInProgress());
- // Check the deadline of the path degrading alarm.
+ // Check the deadline of the path degrading detection.
QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_)
->GetPathDegradingDelay();
EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
clock_.ApproximateNow());
- // Send a second packet. The path degrading alarm's deadline should remain
+ // Send a second packet. The path degrading detection's deadline should remain
// the same.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
QuicTime prev_deadline = connection_.GetBlackholeDetectorAlarm()->deadline();
@@ -8040,7 +8078,7 @@ TEST_P(QuicConnectionTest, NoPathDegradingAlarmIfPathIsDegrading) {
EXPECT_EQ(prev_deadline, connection_.GetBlackholeDetectorAlarm()->deadline());
// Now receive an ACK of the first packet. This should advance the path
- // degrading alarm's deadline since forward progress has been made.
+ // degrading detection's deadline since forward progress has been made.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
@@ -8054,8 +8092,8 @@ TEST_P(QuicConnectionTest, NoPathDegradingAlarmIfPathIsDegrading) {
EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
clock_.ApproximateNow());
- // Advance time to the path degrading alarm's deadline and simulate
- // firing the path degrading alarm. This path will be considered as
+ // Advance time to the path degrading detection's deadline and simulate
+ // firing the path degrading detection. This path will be considered as
// degrading.
clock_.AdvanceTime(delay);
EXPECT_CALL(visitor_, OnPathDegrading()).Times(1);
@@ -8065,7 +8103,7 @@ TEST_P(QuicConnectionTest, NoPathDegradingAlarmIfPathIsDegrading) {
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
EXPECT_FALSE(connection_.PathDegradingDetectionInProgress());
- // Send a third packet. The path degrading alarm is no longer set but path
+ // Send a third packet. The path degrading detection is no longer set but path
// should still be marked as degrading.
connection_.SendStreamDataWithString(1, data, offset, NO_FIN);
offset += data_size;
@@ -8141,6 +8179,7 @@ TEST_P(QuicConnectionTest, UnmarkPathDegradingOnForwardProgress) {
// degrading. And will set a timer to detect new path degrading.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
+ EXPECT_CALL(visitor_, OnForwardProgressMadeAfterPathDegrading()).Times(1);
frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}});
ProcessAckPacket(&frame);
EXPECT_FALSE(connection_.IsPathDegrading());
@@ -8382,8 +8421,7 @@ TEST_P(QuicConnectionTest, DoNotForceSendingAckOnPacketTooLarge) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Send an ack by simulating delayed ack alarm firing.
ProcessPacket(1);
- QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
- EXPECT_TRUE(ack_alarm->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
connection_.GetAckAlarm()->Fire();
// Simulate data packet causes write error.
EXPECT_CALL(visitor_, OnConnectionClosed(_, _));
@@ -8973,45 +9011,6 @@ TEST_P(QuicConnectionTest, ResetBackOffRetransmitableOnWireTimeout) {
connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow());
}
-TEST_P(QuicConnectionTest, OnForwardProgressConfirmed) {
- EXPECT_CALL(visitor_, OnForwardProgressConfirmed()).Times(Exactly(0));
- EXPECT_TRUE(connection_.connected());
-
- const char data[] = "data";
- size_t data_size = strlen(data);
- QuicStreamOffset offset = 0;
-
- // Send two packets.
- connection_.SendStreamDataWithString(1, data, offset, NO_FIN);
- offset += data_size;
- connection_.SendStreamDataWithString(1, data, offset, NO_FIN);
- offset += data_size;
-
- // Ack packet 1. This increases the largest_acked to 1, so
- // OnForwardProgressConfirmed() should be called
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
- EXPECT_CALL(visitor_, OnForwardProgressConfirmed());
- QuicAckFrame frame =
- InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(2)}});
- ProcessAckPacket(&frame);
-
- // Ack packet 1 again. largest_acked remains at 1, so
- // OnForwardProgressConfirmed() should not be called.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- frame = InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(2)}});
- ProcessAckPacket(&frame);
-
- // Ack packet 2. This increases the largest_acked to 2, so
- // OnForwardProgressConfirmed() should be called.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
- EXPECT_CALL(visitor_, OnForwardProgressConfirmed());
- frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}});
- ProcessAckPacket(&frame);
-}
-
TEST_P(QuicConnectionTest, ValidStatelessResetToken) {
const QuicUint128 kTestToken = 1010101;
const QuicUint128 kWrongTestToken = 1010100;
@@ -9231,6 +9230,102 @@ TEST_P(QuicConnectionTest, PathChallengeResponse) {
sizeof(challenge_data)));
}
+TEST_P(QuicConnectionTest,
+ RestartPathDegradingDetectionAfterMigrationWithProbe) {
+ // TODO(b/150095484): add test coverage for IETF to verify that client takes
+ // PATH RESPONSE with peer address change as correct validation on the new
+ // path.
+ if (GetParam().version.HasIetfQuicFrames()) {
+ return;
+ }
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ PathProbeTestInit(Perspective::IS_CLIENT);
+
+ // Clear direct_peer_address and effective_peer_address.
+ QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress());
+ QuicConnectionPeer::SetEffectivePeerAddress(&connection_,
+ QuicSocketAddress());
+ EXPECT_FALSE(connection_.effective_peer_address().IsInitialized());
+
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_CALL(visitor_, ShouldKeepConnectionAlive())
+ .WillRepeatedly(Return(true));
+ EXPECT_FALSE(connection_.PathDegradingDetectionInProgress());
+ EXPECT_FALSE(connection_.IsPathDegrading());
+ EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
+
+ if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+ } else {
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+ }
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
+ EXPECT_EQ(kPeerAddress, connection_.peer_address());
+ EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
+
+ // Send data and verify the path degrading detection is set.
+ const char data[] = "data";
+ size_t data_size = strlen(data);
+ QuicStreamOffset offset = 0;
+ connection_.SendStreamDataWithString(1, data, offset, NO_FIN);
+ offset += data_size;
+
+ // Verify the path degrading detection is in progress.
+ EXPECT_TRUE(connection_.PathDegradingDetectionInProgress());
+ EXPECT_FALSE(connection_.IsPathDegrading());
+ QuicTime ddl = connection_.GetBlackholeDetectorAlarm()->deadline();
+
+ // Simulate the firing of path degrading.
+ clock_.AdvanceTime(ddl - clock_.ApproximateNow());
+ EXPECT_CALL(visitor_, OnPathDegrading()).Times(1);
+ connection_.PathDegradingTimeout();
+ EXPECT_TRUE(connection_.IsPathDegrading());
+ EXPECT_FALSE(connection_.PathDegradingDetectionInProgress());
+
+ // Simulate path degrading handling by sending a probe on an alternet path.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
+ TestPacketWriter probing_writer(version(), &clock_);
+ connection_.SendConnectivityProbingPacket(&probing_writer,
+ connection_.peer_address());
+ // Verify that path degrading detection is not reset.
+ EXPECT_FALSE(connection_.PathDegradingDetectionInProgress());
+
+ // Simulate successful path degrading handling by receiving probe response.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
+
+ if (!GetParam().version.HasIetfQuicFrames()) {
+ EXPECT_CALL(visitor_,
+ OnPacketReceived(_, _, /*is_connectivity_probe=*/true))
+ .Times(1);
+ } else {
+ EXPECT_CALL(visitor_, OnPacketReceived(_, _, _)).Times(0);
+ }
+ const QuicSocketAddress kNewSelfAddress =
+ QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456);
+
+ std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket();
+ std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
+ QuicEncryptedPacket(probing_packet->encrypted_buffer,
+ probing_packet->encrypted_length),
+ clock_.Now()));
+ uint64_t num_probing_received =
+ connection_.GetStats().num_connectivity_probing_received;
+ ProcessReceivedPacket(kNewSelfAddress, kPeerAddress, *received);
+
+ EXPECT_EQ(num_probing_received + 1,
+ connection_.GetStats().num_connectivity_probing_received);
+ EXPECT_EQ(kPeerAddress, connection_.peer_address());
+ EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
+ EXPECT_TRUE(connection_.IsPathDegrading());
+
+ // Verify new path degrading detection is activated.
+ EXPECT_CALL(visitor_, OnForwardProgressMadeAfterPathDegrading()).Times(1);
+ connection_.OnSuccessfulMigrationAfterProbing();
+ EXPECT_FALSE(connection_.IsPathDegrading());
+ EXPECT_TRUE(connection_.PathDegradingDetectionInProgress());
+}
+
// Regression test for b/110259444
TEST_P(QuicConnectionTest, DoNotScheduleSpuriousAckAlarm) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -9238,9 +9333,8 @@ TEST_P(QuicConnectionTest, DoNotScheduleSpuriousAckAlarm) {
writer_->SetWriteBlocked();
ProcessPacket(1);
- QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
// Verify ack alarm is set.
- EXPECT_TRUE(ack_alarm->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
// Fire the ack alarm, verify no packet is sent because the writer is blocked.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
connection_.GetAckAlarm()->Fire();
@@ -9249,7 +9343,7 @@ TEST_P(QuicConnectionTest, DoNotScheduleSpuriousAckAlarm) {
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
ProcessPacket(2);
// Verify ack alarm is not set.
- EXPECT_FALSE(ack_alarm->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
}
TEST_P(QuicConnectionTest, DisablePacingOffloadConnectionOptions) {
@@ -9428,7 +9522,7 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacesBasicReceiving) {
use_tagging_decrypter();
// Receives packet 1000 in initial data.
ProcessCryptoPacketAtLevel(1000, ENCRYPTION_INITIAL);
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
std::make_unique<TaggingEncrypter>(0x02));
SetDecrypter(ENCRYPTION_ZERO_RTT,
@@ -9437,13 +9531,13 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacesBasicReceiving) {
std::make_unique<TaggingEncrypter>(0x02));
// Receives packet 1000 in application data.
ProcessDataPacketAtLevel(1000, false, ENCRYPTION_ZERO_RTT);
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
connection_.SendApplicationDataAtLevel(ENCRYPTION_ZERO_RTT, 5, "data", 0,
NO_FIN);
// Verify application data ACK gets bundled with outgoing data.
EXPECT_EQ(2u, writer_->frame_count());
// Make sure ACK alarm is still set because initial data is not ACKed.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
// Receive packet 1001 in application data.
ProcessDataPacketAtLevel(1001, false, ENCRYPTION_ZERO_RTT);
clock_.AdvanceTime(DefaultRetransmissionTime());
@@ -9452,10 +9546,10 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacesBasicReceiving) {
connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
std::make_unique<TaggingEncrypter>(0x02));
connection_.GetAckAlarm()->Fire();
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
// Receives more packets in application data.
ProcessDataPacketAtLevel(1002, false, ENCRYPTION_ZERO_RTT);
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
peer_framer_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
std::make_unique<TaggingEncrypter>(0x02));
@@ -9464,7 +9558,7 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacesBasicReceiving) {
// Verify zero rtt and forward secure packets get acked in the same packet.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
ProcessDataPacket(1003);
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
}
TEST_P(QuicConnectionTest, CancelAckAlarmOnWriteBlocked) {
@@ -9479,7 +9573,7 @@ TEST_P(QuicConnectionTest, CancelAckAlarmOnWriteBlocked) {
use_tagging_decrypter();
// Receives packet 1000 in initial data.
ProcessCryptoPacketAtLevel(1000, ENCRYPTION_INITIAL);
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
std::make_unique<TaggingEncrypter>(0x02));
SetDecrypter(ENCRYPTION_ZERO_RTT,
@@ -9488,7 +9582,7 @@ TEST_P(QuicConnectionTest, CancelAckAlarmOnWriteBlocked) {
std::make_unique<TaggingEncrypter>(0x02));
// Receives packet 1000 in application data.
ProcessDataPacketAtLevel(1000, false, ENCRYPTION_ZERO_RTT);
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
writer_->SetWriteBlocked();
EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AnyNumber());
@@ -9500,13 +9594,13 @@ TEST_P(QuicConnectionTest, CancelAckAlarmOnWriteBlocked) {
std::make_unique<TaggingEncrypter>(0x02));
connection_.GetAckAlarm()->Fire();
// Verify ACK alarm is not set.
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
writer_->SetWritable();
// Verify 2 ACKs are sent when connection gets unblocked.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
connection_.OnCanWrite();
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
}
// Make sure a packet received with the right client connection ID is processed.
@@ -9618,12 +9712,11 @@ TEST_P(QuicConnectionTest, CheckConnectedBeforeFlush) {
}
ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
kPeerAddress);
- QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
- EXPECT_TRUE(ack_alarm->IsSet());
+ EXPECT_TRUE(connection_.HasPendingAcks());
ProcessFramePacketWithAddresses(QuicFrame(connection_close_frame.release()),
kSelfAddress, kPeerAddress);
// Verify ack alarm is not set.
- EXPECT_FALSE(ack_alarm->IsSet());
+ EXPECT_FALSE(connection_.HasPendingAcks());
}
// Verify that a packet containing three coalesced packets is parsed correctly.
@@ -9861,8 +9954,18 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter6ClientPTOs) {
connection_options.push_back(k6PTO);
config.SetConnectionOptionsToSend(connection_options);
QuicConfigPeer::SetNegotiated(&config, true);
+ if (connection_.version().AuthenticatesHandshakeConnectionIds()) {
+ QuicConfigPeer::SetReceivedOriginalConnectionId(
+ &config, connection_.connection_id());
+ QuicConfigPeer::SetReceivedInitialSourceConnectionId(
+ &config, connection_.connection_id());
+ }
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
connection_.SetFromConfig(config);
+ if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
+ EXPECT_CALL(visitor_, GetHandshakeState())
+ .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
+ }
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
// Send stream data.
@@ -9902,8 +10005,18 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter7ClientPTOs) {
connection_options.push_back(k7PTO);
config.SetConnectionOptionsToSend(connection_options);
QuicConfigPeer::SetNegotiated(&config, true);
+ if (connection_.version().AuthenticatesHandshakeConnectionIds()) {
+ QuicConfigPeer::SetReceivedOriginalConnectionId(
+ &config, connection_.connection_id());
+ QuicConfigPeer::SetReceivedInitialSourceConnectionId(
+ &config, connection_.connection_id());
+ }
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
connection_.SetFromConfig(config);
+ if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
+ EXPECT_CALL(visitor_, GetHandshakeState())
+ .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
+ }
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
// Send stream data.
@@ -9941,9 +10054,19 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter8ClientPTOs) {
connection_options.push_back(k2PTO);
connection_options.push_back(k8PTO);
QuicConfigPeer::SetNegotiated(&config, true);
+ if (connection_.version().AuthenticatesHandshakeConnectionIds()) {
+ QuicConfigPeer::SetReceivedOriginalConnectionId(
+ &config, connection_.connection_id());
+ QuicConfigPeer::SetReceivedInitialSourceConnectionId(
+ &config, connection_.connection_id());
+ }
config.SetConnectionOptionsToSend(connection_options);
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
connection_.SetFromConfig(config);
+ if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
+ EXPECT_CALL(visitor_, GetHandshakeState())
+ .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
+ }
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
// Send stream data.
@@ -10009,7 +10132,7 @@ TEST_P(QuicConnectionTest, DeprecateHandshakeMode) {
EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { SendPing(); }));
connection_.GetRetransmissionAlarm()->Fire();
EXPECT_EQ(1u, connection_.GetStats().pto_count);
- EXPECT_EQ(0u, connection_.GetStats().crypto_retransmit_count);
+ EXPECT_EQ(1u, connection_.GetStats().crypto_retransmit_count);
EXPECT_EQ(1u, writer_->ping_frames().size());
}
@@ -10023,13 +10146,17 @@ TEST_P(QuicConnectionTest, AntiAmplificationLimit) {
// Verify no data can be sent at the beginning because bytes received is 0.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
connection_.SendCryptoDataWithString("foo", 0);
+ if (GetQuicReloadableFlag(quic_move_amplification_limit)) {
+ EXPECT_FALSE(connection_.CanWrite(HAS_RETRANSMITTABLE_DATA));
+ EXPECT_FALSE(connection_.CanWrite(NO_RETRANSMITTABLE_DATA));
+ }
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
// Receives packet 1.
ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL);
const size_t anti_amplification_factor =
- GetQuicFlag(FLAGS_quic_anti_amplification_factor);
+ connection_.anti_amplification_factor();
// Verify now packets can be sent.
for (size_t i = 0; i < anti_amplification_factor; ++i) {
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
@@ -10064,6 +10191,48 @@ TEST_P(QuicConnectionTest, AntiAmplificationLimit) {
}
}
+TEST_P(QuicConnectionTest, AckPendingWithAmplificationLimited) {
+ if (!connection_.version().SupportsAntiAmplificationLimit() ||
+ !GetQuicReloadableFlag(quic_move_amplification_limit)) {
+ return;
+ }
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(AnyNumber());
+ set_perspective(Perspective::IS_SERVER);
+ use_tagging_decrypter();
+ connection_.SetEncrypter(ENCRYPTION_INITIAL,
+ std::make_unique<TaggingEncrypter>(0x01));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ // Receives packet 1.
+ ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL);
+ connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
+ std::make_unique<TaggingEncrypter>(0x02));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
+ EXPECT_TRUE(connection_.HasPendingAcks());
+ // Send response in different encryption level and cause amplification factor
+ // throttled.
+ size_t i = 0;
+ while (connection_.CanWrite(HAS_RETRANSMITTABLE_DATA)) {
+ connection_.SendCryptoDataWithString(std::string(1024, 'a'), i * 1024,
+ ENCRYPTION_HANDSHAKE);
+ ++i;
+ }
+ // Verify ACK is still pending.
+ EXPECT_TRUE(connection_.HasPendingAcks());
+
+ // Fire ACK alarm and verify ACK cannot be sent due to amplification factor.
+ clock_.AdvanceTime(connection_.GetAckAlarm()->deadline() - clock_.Now());
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ connection_.GetAckAlarm()->Fire();
+ // Verify ACK alarm is cancelled.
+ EXPECT_FALSE(connection_.HasPendingAcks());
+
+ // Receives packet 2 and verify ACK gets flushed.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ ProcessCryptoPacketAtLevel(2, ENCRYPTION_INITIAL);
+ EXPECT_FALSE(writer_->ack_frames().empty());
+}
+
TEST_P(QuicConnectionTest, ConnectionCloseFrameType) {
if (!VersionHasIetfQuicFrames(version().transport_version)) {
// Test relevent only for IETF QUIC.
@@ -10202,6 +10371,49 @@ TEST_P(QuicConnectionTest, SendCoalescedPackets) {
EXPECT_NE(nullptr, writer_->coalesced_packet());
}
+TEST_P(QuicConnectionTest, LegacyVersionEncapsulation) {
+ connection_.EnableLegacyVersionEncapsulation("test.example.org");
+
+ MockQuicConnectionDebugVisitor debug_visitor;
+ connection_.set_debug_visitor(&debug_visitor);
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1);
+
+ // Our TestPacketWriter normally parses the sent packet using the version
+ // from the connection, so here we need to tell it to use the encapsulation
+ // version, and reset the initial decrypter for that version.
+ writer_->framer()->SetSupportedVersions(
+ SupportedVersions(LegacyVersionForEncapsulation()));
+ writer_->framer()->framer()->SetInitialObfuscators(
+ connection_.connection_id());
+
+ {
+ QuicConnection::ScopedPacketFlusher flusher(&connection_);
+ connection_.SendCryptoDataWithString("TEST_CRYPTO_DATA", /*offset=*/0);
+ }
+
+ EXPECT_EQ(1u, writer_->packets_write_attempts());
+ // Verify that the packet is fully padded.
+ EXPECT_EQ(connection_.max_packet_length(), writer_->last_packet_size());
+
+ // Check that the connection stats show Legacy Version Encapsulation was used.
+ EXPECT_GT(connection_.GetStats().sent_legacy_version_encapsulated_packets,
+ 0u);
+
+ // Verify that the sent packet was in fact encapsulated, and check header.
+ const QuicPacketHeader& encapsulated_header = writer_->last_packet_header();
+ EXPECT_TRUE(encapsulated_header.version_flag);
+ EXPECT_EQ(encapsulated_header.version, LegacyVersionForEncapsulation());
+ EXPECT_EQ(encapsulated_header.destination_connection_id,
+ connection_.connection_id());
+
+ // Encapsulated packet should contain a stream frame for the crypto stream,
+ // optionally padding, and nothing else.
+ EXPECT_EQ(0u, writer_->crypto_frames().size());
+ EXPECT_EQ(1u, writer_->stream_frames().size());
+ EXPECT_EQ(writer_->frame_count(), writer_->framer()->padding_frames().size() +
+ writer_->stream_frames().size());
+}
+
TEST_P(QuicConnectionTest, ClientReceivedHandshakeDone) {
if (!connection_.version().HasHandshakeDone()) {
return;
@@ -10299,14 +10511,20 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacePto) {
EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet());
}
-void QuicConnectionTest::TestClientRetryHandling(bool invalid_retry_tag,
- bool missing_id_in_config,
- bool wrong_id_in_config) {
+void QuicConnectionTest::TestClientRetryHandling(
+ bool invalid_retry_tag,
+ bool missing_original_id_in_config,
+ bool wrong_original_id_in_config,
+ bool missing_retry_id_in_config,
+ bool wrong_retry_id_in_config) {
if (invalid_retry_tag) {
- ASSERT_FALSE(missing_id_in_config);
- ASSERT_FALSE(wrong_id_in_config);
+ ASSERT_FALSE(missing_original_id_in_config);
+ ASSERT_FALSE(wrong_original_id_in_config);
+ ASSERT_FALSE(missing_retry_id_in_config);
+ ASSERT_FALSE(wrong_retry_id_in_config);
} else {
- ASSERT_FALSE(missing_id_in_config && wrong_id_in_config);
+ ASSERT_FALSE(missing_original_id_in_config && wrong_original_id_in_config);
+ ASSERT_FALSE(missing_retry_id_in_config && wrong_retry_id_in_config);
}
if (!version().HasRetryIntegrityTag()) {
return;
@@ -10321,15 +10539,20 @@ void QuicConnectionTest::TestClientRetryHandling(bool invalid_retry_tag,
0xff, 0xff, 0x00, 0x00, 0x1b, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a,
0x42, 0x62, 0xb5, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0xa5, 0x23, 0xcb, 0x5b,
0xa5, 0x24, 0x69, 0x5f, 0x65, 0x69, 0xf2, 0x93, 0xa1, 0x35, 0x9d, 0x8e};
+ char retry_packet29[] = {
+ 0xff, 0xff, 0x00, 0x00, 0x1d, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a,
+ 0x42, 0x62, 0xb5, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0xd1, 0x69, 0x26, 0xd8,
+ 0x1f, 0x6f, 0x9c, 0xa2, 0x95, 0x3a, 0x8a, 0xa4, 0x57, 0x5e, 0x1e, 0x49};
char* retry_packet;
size_t retry_packet_length;
- if (version() ==
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27)) {
+ if (version() == ParsedQuicVersion::Draft29()) {
+ retry_packet = retry_packet29;
+ retry_packet_length = QUICHE_ARRAYSIZE(retry_packet29);
+ } else if (version() == ParsedQuicVersion::Draft27()) {
retry_packet = retry_packet27;
retry_packet_length = QUICHE_ARRAYSIZE(retry_packet27);
- } else if (version() ==
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25)) {
+ } else if (version() == ParsedQuicVersion::Draft25()) {
retry_packet = retry_packet25;
retry_packet_length = QUICHE_ARRAYSIZE(retry_packet25);
} else {
@@ -10360,11 +10583,17 @@ void QuicConnectionTest::TestClientRetryHandling(bool invalid_retry_tag,
}
QuicConnectionId config_original_connection_id = original_connection_id;
- if (wrong_id_in_config) {
+ if (wrong_original_id_in_config) {
// Flip the first bit of the connection ID.
ASSERT_FALSE(config_original_connection_id.IsEmpty());
config_original_connection_id.mutable_data()[0] ^= 0x80;
}
+ QuicConnectionId config_retry_source_connection_id = new_connection_id;
+ if (wrong_retry_id_in_config) {
+ // Flip the first bit of the connection ID.
+ ASSERT_FALSE(config_retry_source_connection_id.IsEmpty());
+ config_retry_source_connection_id.mutable_data()[0] ^= 0x80;
+ }
// Make sure the connection uses the connection ID from the test vectors,
QuicConnectionPeer::SetServerConnectionId(&connection_,
@@ -10397,11 +10626,21 @@ void QuicConnectionTest::TestClientRetryHandling(bool invalid_retry_tag,
// Test validating the original_connection_id from the config.
QuicConfig received_config;
QuicConfigPeer::SetNegotiated(&received_config, true);
- if (!missing_id_in_config) {
+ if (connection_.version().AuthenticatesHandshakeConnectionIds()) {
+ QuicConfigPeer::SetReceivedInitialSourceConnectionId(
+ &received_config, connection_.connection_id());
+ if (!missing_retry_id_in_config) {
+ QuicConfigPeer::SetReceivedRetrySourceConnectionId(
+ &received_config, config_retry_source_connection_id);
+ }
+ }
+ if (!missing_original_id_in_config) {
QuicConfigPeer::SetReceivedOriginalConnectionId(
&received_config, config_original_connection_id);
}
- if (missing_id_in_config || wrong_id_in_config) {
+
+ if (missing_original_id_in_config || wrong_original_id_in_config ||
+ missing_retry_id_in_config || wrong_retry_id_in_config) {
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF))
.Times(1);
@@ -10412,8 +10651,9 @@ void QuicConnectionTest::TestClientRetryHandling(bool invalid_retry_tag,
}
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber());
connection_.SetFromConfig(received_config);
- if (missing_id_in_config || wrong_id_in_config) {
- EXPECT_FALSE(connection_.connected());
+ if (missing_original_id_in_config || wrong_original_id_in_config ||
+ missing_retry_id_in_config || wrong_retry_id_in_config) {
+ ASSERT_FALSE(connection_.connected());
TestConnectionCloseQuicErrorCode(IETF_QUIC_PROTOCOL_VIOLATION);
} else {
EXPECT_TRUE(connection_.connected());
@@ -10422,31 +10662,74 @@ void QuicConnectionTest::TestClientRetryHandling(bool invalid_retry_tag,
TEST_P(QuicConnectionTest, ClientParsesRetry) {
TestClientRetryHandling(/*invalid_retry_tag=*/false,
- /*missing_id_in_config=*/false,
- /*wrong_id_in_config=*/false);
+ /*missing_original_id_in_config=*/false,
+ /*wrong_original_id_in_config=*/false,
+ /*missing_retry_id_in_config=*/false,
+ /*wrong_retry_id_in_config=*/false);
}
-TEST_P(QuicConnectionTest, ClientParsesInvalidRetry) {
+TEST_P(QuicConnectionTest, ClientParsesRetryInvalidTag) {
TestClientRetryHandling(/*invalid_retry_tag=*/true,
- /*missing_id_in_config=*/false,
- /*wrong_id_in_config=*/false);
+ /*missing_original_id_in_config=*/false,
+ /*wrong_original_id_in_config=*/false,
+ /*missing_retry_id_in_config=*/false,
+ /*wrong_retry_id_in_config=*/false);
}
-TEST_P(QuicConnectionTest, ClientParsesRetryMissingId) {
+TEST_P(QuicConnectionTest, ClientParsesRetryMissingOriginalId) {
TestClientRetryHandling(/*invalid_retry_tag=*/false,
- /*missing_id_in_config=*/true,
- /*wrong_id_in_config=*/false);
+ /*missing_original_id_in_config=*/true,
+ /*wrong_original_id_in_config=*/false,
+ /*missing_retry_id_in_config=*/false,
+ /*wrong_retry_id_in_config=*/false);
}
-TEST_P(QuicConnectionTest, ClientParsesRetryWrongId) {
+TEST_P(QuicConnectionTest, ClientParsesRetryWrongOriginalId) {
TestClientRetryHandling(/*invalid_retry_tag=*/false,
- /*missing_id_in_config=*/false,
- /*wrong_id_in_config=*/true);
+ /*missing_original_id_in_config=*/false,
+ /*wrong_original_id_in_config=*/true,
+ /*missing_retry_id_in_config=*/false,
+ /*wrong_retry_id_in_config=*/false);
+}
+
+TEST_P(QuicConnectionTest, ClientParsesRetryMissingRetryId) {
+ if (!connection_.version().AuthenticatesHandshakeConnectionIds()) {
+ // Versions that do not authenticate connection IDs never send the
+ // retry_source_connection_id transport parameter.
+ return;
+ }
+ TestClientRetryHandling(/*invalid_retry_tag=*/false,
+ /*missing_original_id_in_config=*/false,
+ /*wrong_original_id_in_config=*/false,
+ /*missing_retry_id_in_config=*/true,
+ /*wrong_retry_id_in_config=*/false);
+}
+
+TEST_P(QuicConnectionTest, ClientParsesRetryWrongRetryId) {
+ if (!connection_.version().AuthenticatesHandshakeConnectionIds()) {
+ // Versions that do not authenticate connection IDs never send the
+ // retry_source_connection_id transport parameter.
+ return;
+ }
+ TestClientRetryHandling(/*invalid_retry_tag=*/false,
+ /*missing_original_id_in_config=*/false,
+ /*wrong_original_id_in_config=*/false,
+ /*missing_retry_id_in_config=*/false,
+ /*wrong_retry_id_in_config=*/true);
}
TEST_P(QuicConnectionTest, ClientReceivesOriginalConnectionIdWithoutRetry) {
- // Make sure that receiving the original_connection_id transport parameter
- // fails the handshake when no RETRY packet was received before it.
+ if (!connection_.version().UsesTls()) {
+ // QUIC+TLS is required to transmit connection ID transport parameters.
+ return;
+ }
+ if (connection_.version().AuthenticatesHandshakeConnectionIds()) {
+ // Versions that authenticate connection IDs always send the
+ // original_destination_connection_id transport parameter.
+ return;
+ }
+ // Make sure that receiving the original_destination_connection_id transport
+ // parameter fails the handshake when no RETRY packet was received before it.
QuicConfig received_config;
QuicConfigPeer::SetNegotiated(&received_config, true);
QuicConfigPeer::SetReceivedOriginalConnectionId(&received_config,
@@ -10459,6 +10742,26 @@ TEST_P(QuicConnectionTest, ClientReceivesOriginalConnectionIdWithoutRetry) {
TestConnectionCloseQuicErrorCode(IETF_QUIC_PROTOCOL_VIOLATION);
}
+TEST_P(QuicConnectionTest, ClientReceivesRetrySourceConnectionIdWithoutRetry) {
+ if (!connection_.version().AuthenticatesHandshakeConnectionIds()) {
+ // Versions that do not authenticate connection IDs never send the
+ // retry_source_connection_id transport parameter.
+ return;
+ }
+ // Make sure that receiving the retry_source_connection_id transport parameter
+ // fails the handshake when no RETRY packet was received before it.
+ QuicConfig received_config;
+ QuicConfigPeer::SetNegotiated(&received_config, true);
+ QuicConfigPeer::SetReceivedRetrySourceConnectionId(&received_config,
+ TestConnectionId(0x12345));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber());
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF))
+ .Times(1);
+ connection_.SetFromConfig(received_config);
+ EXPECT_FALSE(connection_.connected());
+ TestConnectionCloseQuicErrorCode(IETF_QUIC_PROTOCOL_VIOLATION);
+}
+
// Regression test for http://crbug/1047977
TEST_P(QuicConnectionTest, MaxStreamsFrameCausesConnectionClose) {
if (!VersionHasIetfQuicFrames(connection_.transport_version())) {
@@ -10640,28 +10943,14 @@ TEST_P(QuicConnectionTest, DonotExtendIdleTimeOnUndecryptablePackets) {
peer_framer_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
std::make_unique<TaggingEncrypter>(tag));
ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_FORWARD_SECURE);
- if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets)) {
- // Verify deadline does not get extended.
- EXPECT_EQ(initial_deadline, connection_.GetTimeoutAlarm()->deadline());
- }
- if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets)) {
- EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(1);
- } else {
- EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(0);
- }
+ // Verify deadline does not get extended.
+ EXPECT_EQ(initial_deadline, connection_.GetTimeoutAlarm()->deadline());
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(1);
QuicTime::Delta delay = initial_deadline - clock_.ApproximateNow();
clock_.AdvanceTime(delay);
- if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets)) {
- connection_.GetTimeoutAlarm()->Fire();
- }
- if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets)) {
- // Verify connection gets closed.
- EXPECT_FALSE(connection_.connected());
- } else {
- // Verify the timeout alarm deadline is updated.
- EXPECT_TRUE(connection_.connected());
- EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
- }
+ connection_.GetTimeoutAlarm()->Fire();
+ // Verify connection gets closed.
+ EXPECT_FALSE(connection_.connected());
}
TEST_P(QuicConnectionTest, BundleAckWithImmediateResponse) {
@@ -10673,15 +10962,440 @@ TEST_P(QuicConnectionTest, BundleAckWithImmediateResponse) {
}));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
ProcessDataPacket(1);
- QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
- if (GetQuicReloadableFlag(quic_advance_ack_timeout_update)) {
- // Verify ACK is bundled with WINDOW_UPDATE.
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(ack_alarm->IsSet());
+ // Verify ACK is bundled with WINDOW_UPDATE.
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ EXPECT_FALSE(connection_.HasPendingAcks());
+}
+
+TEST_P(QuicConnectionTest, AckAlarmFiresEarly) {
+ if (!connection_.SupportsMultiplePacketNumberSpaces()) {
+ return;
+ }
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+ }
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+ use_tagging_decrypter();
+ // Receives packet 1000 in initial data.
+ ProcessCryptoPacketAtLevel(1000, ENCRYPTION_INITIAL);
+ EXPECT_TRUE(connection_.HasPendingAcks());
+
+ peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
+ std::make_unique<TaggingEncrypter>(0x02));
+ SetDecrypter(ENCRYPTION_ZERO_RTT,
+ std::make_unique<StrictTaggingDecrypter>(0x02));
+ connection_.SetEncrypter(ENCRYPTION_INITIAL,
+ std::make_unique<TaggingEncrypter>(0x02));
+ // Receives packet 1000 in application data.
+ ProcessDataPacketAtLevel(1000, false, ENCRYPTION_ZERO_RTT);
+ EXPECT_TRUE(connection_.HasPendingAcks());
+ // Verify ACK deadline does not change.
+ EXPECT_EQ(clock_.ApproximateNow() + kAlarmGranularity,
+ connection_.GetAckAlarm()->deadline());
+
+ // Ack alarm fires early.
+ if (GetQuicReloadableFlag(quic_always_send_earliest_ack)) {
+ // Verify the earliest ACK is flushed.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
} else {
- // ACK is pending.
- EXPECT_TRUE(writer_->ack_frames().empty());
- EXPECT_TRUE(ack_alarm->IsSet());
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ }
+ connection_.GetAckAlarm()->Fire();
+ EXPECT_TRUE(connection_.HasPendingAcks());
+ if (GetQuicReloadableFlag(quic_always_send_earliest_ack)) {
+ EXPECT_EQ(clock_.ApproximateNow() + DefaultDelayedAckTime(),
+ connection_.GetAckAlarm()->deadline());
+ } else {
+ // No forward progress has been made.
+ EXPECT_EQ(clock_.ApproximateNow() + kAlarmGranularity,
+ connection_.GetAckAlarm()->deadline());
+ }
+}
+
+TEST_P(QuicConnectionTest, ClientOnlyBlackholeDetectionClient) {
+ if (!GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
+ return;
+ }
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(kCBHD);
+ config.SetConnectionOptionsToSend(connection_options);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ EXPECT_CALL(visitor_, GetHandshakeState())
+ .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
+ EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet());
+ // Send stream data.
+ SendStreamDataToPeer(
+ GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo",
+ 0, FIN, nullptr);
+ // Verify blackhole detection is in progress.
+ EXPECT_TRUE(connection_.GetBlackholeDetectorAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, ClientOnlyBlackholeDetectionServer) {
+ if (!GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
+ return;
+ }
+ set_perspective(Perspective::IS_SERVER);
+ QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
+ if (version().SupportsAntiAmplificationLimit()) {
+ QuicConnectionPeer::SetAddressValidated(&connection_);
+ }
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(kCBHD);
+ config.SetInitialReceivedConnectionOptions(connection_options);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ EXPECT_CALL(visitor_, GetHandshakeState())
+ .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
+ EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet());
+ // Send stream data.
+ SendStreamDataToPeer(
+ GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo",
+ 0, FIN, nullptr);
+ // Verify blackhole detection is disabled.
+ EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, 2RtoBlackholeDetection) {
+ if (!GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
+ return;
+ }
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(k2RTO);
+ config.SetConnectionOptionsToSend(connection_options);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ const size_t kMinRttMs = 40;
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ EXPECT_CALL(visitor_, GetHandshakeState())
+ .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
+ EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet());
+ // Send stream data.
+ SendStreamDataToPeer(
+ GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo",
+ 0, FIN, nullptr);
+ // Verify blackhole delay is expected.
+ EXPECT_EQ(clock_.Now() +
+ connection_.sent_packet_manager().GetNetworkBlackholeDelay(2),
+ QuicConnectionPeer::GetBlackholeDetectionDeadline(&connection_));
+}
+
+TEST_P(QuicConnectionTest, 3RtoBlackholeDetection) {
+ if (!GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
+ return;
+ }
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(k3RTO);
+ config.SetConnectionOptionsToSend(connection_options);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ const size_t kMinRttMs = 40;
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ EXPECT_CALL(visitor_, GetHandshakeState())
+ .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
+ EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet());
+ // Send stream data.
+ SendStreamDataToPeer(
+ GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo",
+ 0, FIN, nullptr);
+ // Verify blackhole delay is expected.
+ EXPECT_EQ(clock_.Now() +
+ connection_.sent_packet_manager().GetNetworkBlackholeDelay(3),
+ QuicConnectionPeer::GetBlackholeDetectionDeadline(&connection_));
+}
+
+TEST_P(QuicConnectionTest, 4RtoBlackholeDetection) {
+ if (!GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
+ return;
+ }
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(k4RTO);
+ config.SetConnectionOptionsToSend(connection_options);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ const size_t kMinRttMs = 40;
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ EXPECT_CALL(visitor_, GetHandshakeState())
+ .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
+ EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet());
+ // Send stream data.
+ SendStreamDataToPeer(
+ GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo",
+ 0, FIN, nullptr);
+ // Verify blackhole delay is expected.
+ EXPECT_EQ(clock_.Now() +
+ connection_.sent_packet_manager().GetNetworkBlackholeDelay(4),
+ QuicConnectionPeer::GetBlackholeDetectionDeadline(&connection_));
+}
+
+TEST_P(QuicConnectionTest, 6RtoBlackholeDetection) {
+ if (!GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
+ return;
+ }
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(k6RTO);
+ config.SetConnectionOptionsToSend(connection_options);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ const size_t kMinRttMs = 40;
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ EXPECT_CALL(visitor_, GetHandshakeState())
+ .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
+ EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet());
+ // Send stream data.
+ SendStreamDataToPeer(
+ GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo",
+ 0, FIN, nullptr);
+ // Verify blackhole delay is expected.
+ EXPECT_EQ(clock_.Now() +
+ connection_.sent_packet_manager().GetNetworkBlackholeDelay(6),
+ QuicConnectionPeer::GetBlackholeDetectionDeadline(&connection_));
+}
+
+// Regresstion test for b/158491591.
+TEST_P(QuicConnectionTest, MadeForwardProgressOnDiscardingKeys) {
+ if (!connection_.SupportsMultiplePacketNumberSpaces()) {
+ return;
+ }
+ use_tagging_decrypter();
+ // Send handshake packet.
+ connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
+ std::make_unique<TaggingEncrypter>(0x02));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(k5RTO);
+ config.SetConnectionOptionsToSend(connection_options);
+ QuicConfigPeer::SetNegotiated(&config, true);
+ if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
+ EXPECT_CALL(visitor_, GetHandshakeState())
+ .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
+ }
+ if (connection_.version().AuthenticatesHandshakeConnectionIds()) {
+ QuicConfigPeer::SetReceivedOriginalConnectionId(
+ &config, connection_.connection_id());
+ QuicConfigPeer::SetReceivedInitialSourceConnectionId(
+ &config, connection_.connection_id());
+ }
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+
+ connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE);
+ EXPECT_TRUE(connection_.BlackholeDetectionInProgress());
+ // Discard handshake keys.
+ connection_.OnHandshakeComplete();
+ if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
+ // Verify blackhole detection stops.
+ EXPECT_FALSE(connection_.BlackholeDetectionInProgress());
+ } else {
+ // Problematic: although there is nothing in flight, blackhole detection is
+ // still in progress.
+ EXPECT_TRUE(connection_.BlackholeDetectionInProgress());
+ }
+}
+
+TEST_P(QuicConnectionTest, ProcessUndecryptablePacketsBasedOnEncryptionLevel) {
+ if (!connection_.SupportsMultiplePacketNumberSpaces()) {
+ return;
+ }
+ // SetFromConfig is always called after construction from InitializeSession.
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(AnyNumber());
+ QuicConfig config;
+ connection_.SetFromConfig(config);
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ connection_.RemoveDecrypter(ENCRYPTION_FORWARD_SECURE);
+ use_tagging_decrypter();
+
+ peer_framer_.SetEncrypter(ENCRYPTION_HANDSHAKE,
+ std::make_unique<TaggingEncrypter>(0x01));
+ peer_framer_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<TaggingEncrypter>(0x02));
+
+ for (uint64_t i = 1; i <= 3; ++i) {
+ ProcessDataPacketAtLevel(i, !kHasStopWaiting, ENCRYPTION_HANDSHAKE);
+ }
+ ProcessDataPacketAtLevel(4, !kHasStopWaiting, ENCRYPTION_FORWARD_SECURE);
+ for (uint64_t j = 5; j <= 7; ++j) {
+ ProcessDataPacketAtLevel(j, !kHasStopWaiting, ENCRYPTION_HANDSHAKE);
+ }
+ EXPECT_EQ(7u, QuicConnectionPeer::NumUndecryptablePackets(&connection_));
+ EXPECT_FALSE(connection_.GetProcessUndecryptablePacketsAlarm()->IsSet());
+ SetDecrypter(ENCRYPTION_HANDSHAKE,
+ std::make_unique<StrictTaggingDecrypter>(0x01));
+ EXPECT_TRUE(connection_.GetProcessUndecryptablePacketsAlarm()->IsSet());
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
+ connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
+ std::make_unique<TaggingEncrypter>(0x01));
+ if (GetQuicReloadableFlag(quic_fix_undecryptable_packets)) {
+ // Verify all ENCRYPTION_HANDSHAKE packets get processed.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(6);
+ } else {
+ // Verify packets before 4 get processed.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(3);
+ }
+ connection_.GetProcessUndecryptablePacketsAlarm()->Fire();
+ EXPECT_EQ(4u, QuicConnectionPeer::NumUndecryptablePackets(&connection_));
+
+ SetDecrypter(ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<StrictTaggingDecrypter>(0x02));
+ EXPECT_TRUE(connection_.GetProcessUndecryptablePacketsAlarm()->IsSet());
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<TaggingEncrypter>(0x02));
+ if (GetQuicReloadableFlag(quic_fix_undecryptable_packets)) {
+ // Verify the 1-RTT packet gets processed.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ } else {
+ // Verify all packets get processed.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(4);
+ }
+ connection_.GetProcessUndecryptablePacketsAlarm()->Fire();
+ EXPECT_EQ(0u, QuicConnectionPeer::NumUndecryptablePackets(&connection_));
+}
+
+TEST_P(QuicConnectionTest, ServerBundlesInitialDataWithInitialAck) {
+ if (!connection_.SupportsMultiplePacketNumberSpaces()) {
+ return;
+ }
+ set_perspective(Perspective::IS_SERVER);
+ if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+ }
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+ use_tagging_decrypter();
+ // Receives packet 1000 in initial data.
+ ProcessCryptoPacketAtLevel(1000, ENCRYPTION_INITIAL);
+ EXPECT_TRUE(connection_.HasPendingAcks());
+
+ connection_.SetEncrypter(ENCRYPTION_INITIAL,
+ std::make_unique<TaggingEncrypter>(0x01));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_INITIAL);
+ QuicTime expected_pto_time =
+ connection_.sent_packet_manager().GetRetransmissionTime();
+
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
+ connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
+ std::make_unique<TaggingEncrypter>(0x02));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
+ connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE);
+ // Verify PTO time does not change.
+ EXPECT_EQ(expected_pto_time,
+ connection_.sent_packet_manager().GetRetransmissionTime());
+
+ // Receives packet 1001 in initial data.
+ ProcessCryptoPacketAtLevel(1001, ENCRYPTION_INITIAL);
+ EXPECT_TRUE(connection_.HasPendingAcks());
+ // Receives packet 1002 in initial data.
+ ProcessCryptoPacketAtLevel(1002, ENCRYPTION_INITIAL);
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ if (GetQuicReloadableFlag(quic_bundle_crypto_data_with_initial_ack)) {
+ // Verify CRYPTO frame is bundled with INITIAL ACK.
+ EXPECT_FALSE(writer_->crypto_frames().empty());
+ // Verify PTO time changes.
+ EXPECT_NE(expected_pto_time,
+ connection_.sent_packet_manager().GetRetransmissionTime());
+ } else {
+ EXPECT_TRUE(writer_->crypto_frames().empty());
+ // Verify PTO time does not change.
+ EXPECT_EQ(expected_pto_time,
+ connection_.sent_packet_manager().GetRetransmissionTime());
+ }
+}
+
+TEST_P(QuicConnectionTest, ClientBundlesHandshakeDataWithHandshakeAck) {
+ if (!connection_.SupportsMultiplePacketNumberSpaces()) {
+ return;
+ }
+ EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective());
+ if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+ }
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+ use_tagging_decrypter();
+ connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
+ std::make_unique<TaggingEncrypter>(0x02));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
+ SetDecrypter(ENCRYPTION_HANDSHAKE,
+ std::make_unique<StrictTaggingDecrypter>(0x02));
+ peer_framer_.SetEncrypter(ENCRYPTION_HANDSHAKE,
+ std::make_unique<TaggingEncrypter>(0x02));
+ // Receives packet 1000 in handshake data.
+ ProcessCryptoPacketAtLevel(1000, ENCRYPTION_HANDSHAKE);
+ EXPECT_TRUE(connection_.HasPendingAcks());
+
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2);
+ connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE);
+
+ // Receives packet 1001 in handshake data.
+ ProcessCryptoPacketAtLevel(1001, ENCRYPTION_HANDSHAKE);
+ EXPECT_TRUE(connection_.HasPendingAcks());
+ // Receives packet 1002 in handshake data.
+ ProcessCryptoPacketAtLevel(1002, ENCRYPTION_HANDSHAKE);
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ if (GetQuicReloadableFlag(quic_bundle_crypto_data_with_initial_ack)) {
+ // Verify CRYPTO frame is bundled with HANDSHAKE ACK.
+ EXPECT_FALSE(writer_->crypto_frames().empty());
+ } else {
+ EXPECT_TRUE(writer_->crypto_frames().empty());
+ }
+}
+
+// Regresstion test for b/156232673.
+TEST_P(QuicConnectionTest, CoalescePacketOfLowerEncryptionLevel) {
+ if (!connection_.version().CanSendCoalescedPackets()) {
+ return;
+ }
+ if (GetQuicReloadableFlag(quic_fix_min_crypto_frame_size)) {
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
+ } else {
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(0);
+ }
+ {
+ QuicConnection::ScopedPacketFlusher flusher(&connection_);
+ use_tagging_decrypter();
+ connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
+ std::make_unique<TaggingEncrypter>(0x01));
+ connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<TaggingEncrypter>(0x02));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ SendStreamDataToPeer(2, std::string(1286, 'a'), 0, NO_FIN, nullptr);
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
+ // Try to coalesce a HANDSHAKE packet after 1-RTT packet.
+ if (GetQuicReloadableFlag(quic_fix_min_crypto_frame_size)) {
+ // Verify soft max packet length gets resumed and handshake packet gets
+ // successfully sent.
+ connection_.SendCryptoDataWithString("a", 0, ENCRYPTION_HANDSHAKE);
+ } else {
+ // Problematic: creator thinks there is space to consume 1-byte, however,
+ // extra paddings make the serialization fail because of
+ // MinPlaintextPacketSize.
+ EXPECT_CALL(visitor_,
+ OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
+ EXPECT_QUIC_BUG(
+ connection_.SendCryptoDataWithString("a", 0, ENCRYPTION_HANDSHAKE),
+ "AppendPaddingFrame of 3 failed");
+ }
}
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc
index e93fd071c07..a769da9cd60 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc
@@ -171,6 +171,12 @@ size_t QuicCryptoClientHandshaker::BufferSizeLimitForLevel(
return QuicCryptoHandshaker::BufferSizeLimitForLevel(level);
}
+void QuicCryptoClientHandshaker::OnConnectionClosed(
+ QuicErrorCode /*error*/,
+ ConnectionCloseSource /*source*/) {
+ next_state_ = STATE_CONNECTION_CLOSED;
+}
+
void QuicCryptoClientHandshaker::HandleServerConfigUpdateMessage(
const CryptoHandshakeMessage& server_config_update) {
DCHECK(server_config_update.tag() == kSCUP);
@@ -236,6 +242,9 @@ void QuicCryptoClientHandshaker::DoHandshakeLoop(
break;
case STATE_NONE:
QUIC_NOTREACHED();
+ return;
+ case STATE_CONNECTION_CLOSED:
+ rv = QUIC_FAILURE;
return; // We are done.
}
} while (rv != QUIC_PENDING && next_state_ != STATE_NONE);
@@ -281,7 +290,9 @@ void QuicCryptoClientHandshaker::DoSendCHLO(
// inchoate or subsequent hello.
session()->config()->ToHandshakeMessage(&out, session()->transport_version());
- if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
+ if (!cached->IsComplete(session()->connection()->clock()->WallNow()) ||
+ session()->config()->HasClientRequestedIndependentOption(
+ kQNZR, session()->perspective())) {
crypto_config_->FillInchoateClientHello(
server_id_, session()->supported_versions().front(), cached,
session()->connection()->random_generator(),
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h
index 5ba93f24848..90f011dd053 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h
@@ -53,9 +53,9 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker
void OnOneRttPacketAcknowledged() override {}
void OnHandshakePacketSent() override {}
void OnConnectionClosed(QuicErrorCode /*error*/,
- ConnectionCloseSource /*source*/) override {}
+ ConnectionCloseSource /*source*/) override;
void OnHandshakeDoneReceived() override;
- void OnApplicationState(
+ void SetServerApplicationStateForResumption(
std::unique_ptr<ApplicationState> /*application_state*/) override {
QUICHE_NOTREACHED();
}
@@ -103,6 +103,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker
STATE_RECV_SHLO,
STATE_INITIALIZE_SCUP,
STATE_NONE,
+ STATE_CONNECTION_CLOSED,
};
// Handles new server config and optional source-address token provided by the
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc
index 36dc4cdb4c3..62a261d1fc1 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc
@@ -126,9 +126,10 @@ void QuicCryptoClientStream::OnHandshakeDoneReceived() {
handshaker_->OnHandshakeDoneReceived();
}
-void QuicCryptoClientStream::OnApplicationState(
+void QuicCryptoClientStream::SetServerApplicationStateForResumption(
std::unique_ptr<ApplicationState> application_state) {
- handshaker_->OnApplicationState(std::move(application_state));
+ handshaker_->SetServerApplicationStateForResumption(
+ std::move(application_state));
}
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h
index 23f83c7e390..be99fb2b949 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h
@@ -63,9 +63,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStreamBase : public QuicCryptoStream {
// client. Does not count update messages that were received prior
// to handshake confirmation.
virtual int num_scup_messages_received() const = 0;
-
- virtual void OnApplicationState(
- std::unique_ptr<ApplicationState> application_state) = 0;
};
class QUIC_EXPORT_PRIVATE QuicCryptoClientStream
@@ -167,7 +164,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream
virtual void OnHandshakeDoneReceived() = 0;
// Called when application state is received.
- virtual void OnApplicationState(
+ virtual void SetServerApplicationStateForResumption(
std::unique_ptr<ApplicationState> application_state) = 0;
};
@@ -223,10 +220,9 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream
ConnectionCloseSource source) override;
void OnHandshakeDoneReceived() override;
HandshakeState GetHandshakeState() const override;
- size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
-
- void OnApplicationState(
+ void SetServerApplicationStateForResumption(
std::unique_ptr<ApplicationState> application_state) override;
+ size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
std::string chlo_hash() const;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc
index 6542382d670..7f6d7770eb6 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc
@@ -162,6 +162,25 @@ TEST_F(QuicCryptoClientStreamTest, ExpiredServerConfig) {
EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level());
}
+TEST_F(QuicCryptoClientStreamTest, ClientTurnedOffZeroRtt) {
+ // Seed the config with a cached server config.
+ CompleteCryptoHandshake();
+
+ // Recreate connection with the new config.
+ CreateConnection();
+
+ // Set connection option.
+ QuicTagVector options;
+ options.push_back(kQNZR);
+ session_->config()->SetClientConnectionOptions(options);
+
+ EXPECT_CALL(*session_, OnProofValid(testing::_));
+ stream()->CryptoConnect();
+ // Check that a client hello was sent.
+ ASSERT_EQ(1u, connection_->encrypted_packets_.size());
+ EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level());
+}
+
TEST_F(QuicCryptoClientStreamTest, ClockSkew) {
// Test that if the client's clock is skewed with respect to the server,
// the handshake succeeds. In the past, the client would get the server
@@ -299,7 +318,6 @@ TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateWithCert) {
// Recreate connection with the new config and verify a 0-RTT attempt.
CreateConnection();
- EXPECT_CALL(*connection_, OnCanWrite());
EXPECT_CALL(*session_, OnProofValid(testing::_));
EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_))
.Times(testing::AnyNumber());
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc
index 66f82298476..6c840671daf 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc
@@ -8,6 +8,7 @@
#include <string>
#include "third_party/boringssl/src/include/openssl/sha.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
@@ -298,6 +299,11 @@ bool QuicCryptoServerStream::IsZeroRtt() const {
num_handshake_messages_with_server_nonces_ == 0;
}
+bool QuicCryptoServerStream::IsResumption() const {
+ // QUIC Crypto doesn't have a non-0-RTT resumption mode.
+ return IsZeroRtt();
+}
+
int QuicCryptoServerStream::NumServerConfigUpdateMessagesSent() const {
return num_server_config_update_messages_sent_;
}
@@ -307,7 +313,7 @@ QuicCryptoServerStream::PreviousCachedNetworkParams() const {
return previous_cached_network_params_.get();
}
-bool QuicCryptoServerStream::ZeroRttAttempted() const {
+bool QuicCryptoServerStream::ResumptionAttempted() const {
return zero_rtt_attempted_;
}
@@ -370,6 +376,12 @@ HandshakeState QuicCryptoServerStream::GetHandshakeState() const {
return one_rtt_packet_decrypted_ ? HANDSHAKE_COMPLETE : HANDSHAKE_START;
}
+void QuicCryptoServerStream::SetServerApplicationStateForResumption(
+ std::unique_ptr<ApplicationState> /*state*/) {
+ // QUIC Crypto doesn't need to remember any application state as part of doing
+ // 0-RTT resumption, so this function is a no-op.
+}
+
size_t QuicCryptoServerStream::BufferSizeLimitForLevel(
EncryptionLevel level) const {
return QuicCryptoHandshaker::BufferSizeLimitForLevel(level);
@@ -389,6 +401,17 @@ void QuicCryptoServerStream::ProcessClientHello(
nullptr);
return;
}
+
+ if (GetQuicReloadableFlag(quic_save_user_agent_in_quic_session)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_save_user_agent_in_quic_session, 1, 3);
+ quiche::QuicheStringPiece user_agent_id;
+ message.GetStringPiece(quic::kUAID, &user_agent_id);
+ if (!session()->user_agent_id().has_value()) {
+ std::string uaid = user_agent_id.empty() ? "" : user_agent_id.data();
+ session()->SetUserAgentId(std::move(uaid));
+ }
+ }
+
if (!result->info.server_nonce.empty()) {
++num_handshake_messages_with_server_nonces_;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h
index 52d4874994d..9ed7764a078 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h
@@ -35,9 +35,10 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStream
void SendServerConfigUpdate(
const CachedNetworkParameters* cached_network_params) override;
bool IsZeroRtt() const override;
+ bool IsResumption() const override;
+ bool ResumptionAttempted() const override;
int NumServerConfigUpdateMessagesSent() const override;
const CachedNetworkParameters* PreviousCachedNetworkParams() const override;
- bool ZeroRttAttempted() const override;
void SetPreviousCachedNetworkParams(
CachedNetworkParameters cached_network_params) override;
void OnPacketDecrypted(EncryptionLevel level) override;
@@ -55,6 +56,8 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStream
const override;
CryptoMessageParser* crypto_message_parser() override;
HandshakeState GetHandshakeState() const override;
+ void SetServerApplicationStateForResumption(
+ std::unique_ptr<ApplicationState> state) override;
size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
// From QuicCryptoHandshaker
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h
index cdf12a3143d..540b7a42174 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h
@@ -62,8 +62,17 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStreamBase : public QuicCryptoStream {
virtual void SendServerConfigUpdate(
const CachedNetworkParameters* cached_network_params) = 0;
+ // Returns true if the connection was a successful 0-RTT resumption.
virtual bool IsZeroRtt() const = 0;
- virtual bool ZeroRttAttempted() const = 0;
+
+ // Returns true if the connection was the result of a resumption handshake,
+ // whether 0-RTT or not.
+ virtual bool IsResumption() const = 0;
+
+ // Returns true if the client attempted a resumption handshake, whether or not
+ // the resumption actually occurred.
+ virtual bool ResumptionAttempted() const = 0;
+
virtual const CachedNetworkParameters* PreviousCachedNetworkParams()
const = 0;
virtual void SetPreviousCachedNetworkParams(
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc
index debfc3b0f52..9ff7dc05d47 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc
@@ -226,7 +226,7 @@ TEST_F(QuicCryptoServerStreamTest, ZeroRTT) {
// Do a first handshake in order to prime the client config with the server's
// information.
AdvanceHandshakeWithFakeClient();
- EXPECT_FALSE(server_stream()->ZeroRttAttempted());
+ EXPECT_FALSE(server_stream()->ResumptionAttempted());
// Now do another handshake, hopefully in 0-RTT.
QUIC_LOG(INFO) << "Resetting for 0-RTT handshake attempt";
@@ -247,7 +247,7 @@ TEST_F(QuicCryptoServerStreamTest, ZeroRTT) {
client_connection_, client_stream(), server_connection_, server_stream());
EXPECT_EQ(1, client_stream()->num_sent_client_hellos());
- EXPECT_TRUE(server_stream()->ZeroRttAttempted());
+ EXPECT_TRUE(server_stream()->ResumptionAttempted());
}
TEST_F(QuicCryptoServerStreamTest, FailByPolicy) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc
index 20704fb627a..59a012224e8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc
@@ -268,6 +268,12 @@ void QuicCryptoStream::WritePendingCryptoRetransmission() {
level, pending.length, pending.offset, HANDSHAKE_RETRANSMISSION);
send_buffer->OnStreamDataRetransmitted(pending.offset, bytes_consumed);
if (bytes_consumed < pending.length) {
+ if (GetQuicReloadableFlag(
+ quic_fix_write_pending_crypto_retransmission)) {
+ QUIC_RELOADABLE_FLAG_COUNT(
+ quic_fix_write_pending_crypto_retransmission);
+ return;
+ }
break;
}
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h
index 49d37042390..54d1b2525c2 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h
@@ -100,6 +100,21 @@ class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream {
// Returns current handshake state.
virtual HandshakeState GetHandshakeState() const = 0;
+ // Called to provide the server-side application state that must be checked
+ // when performing a 0-RTT TLS resumption.
+ //
+ // On a client, this may be called at any time; 0-RTT tickets will not be
+ // cached until this function is called. When a 0-RTT resumption is attempted,
+ // QuicSession::SetApplicationState will be called with the state provided by
+ // a call to this function on a previous connection.
+ //
+ // On a server, this function must be called before commencing the handshake,
+ // otherwise 0-RTT tickets will not be issued. On subsequent connections,
+ // 0-RTT will be rejected if the data passed into this function does not match
+ // the data passed in on the connection where the 0-RTT ticket was issued.
+ virtual void SetServerApplicationStateForResumption(
+ std::unique_ptr<ApplicationState> state) = 0;
+
// Returns the maximum number of bytes that can be buffered at a particular
// encryption level |level|.
virtual size_t BufferSizeLimitForLevel(EncryptionLevel level) const;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc
index 5f414e6a98a..f763d2d4782 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc
@@ -61,6 +61,8 @@ class MockQuicCryptoStream : public QuicCryptoStream,
void OnHandshakePacketSent() override {}
void OnHandshakeDoneReceived() override {}
HandshakeState GetHandshakeState() const override { return HANDSHAKE_START; }
+ void SetServerApplicationStateForResumption(
+ std::unique_ptr<ApplicationState> /*application_state*/) override {}
private:
QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;
@@ -419,7 +421,7 @@ TEST_F(QuicCryptoStreamTest, RetransmitStreamData) {
.WillOnce(InvokeWithoutArgs([this]() {
return session_.ConsumeData(
QuicUtils::GetCryptoStreamId(connection_->transport_version()), 150,
- 1350, NO_FIN, HANDSHAKE_RETRANSMISSION, QuicheNullOpt);
+ 1350, NO_FIN, HANDSHAKE_RETRANSMISSION, QUICHE_NULLOPT);
}));
EXPECT_FALSE(stream_->RetransmitStreamData(1350, 1350, false,
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_default_packet_writer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_default_packet_writer.cc
index 42220050885..b34bed49fcf 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_default_packet_writer.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_default_packet_writer.cc
@@ -54,10 +54,10 @@ bool QuicDefaultPacketWriter::IsBatchMode() const {
return false;
}
-char* QuicDefaultPacketWriter::GetNextWriteLocation(
+QuicPacketBuffer QuicDefaultPacketWriter::GetNextWriteLocation(
const QuicIpAddress& /*self_address*/,
const QuicSocketAddress& /*peer_address*/) {
- return nullptr;
+ return {nullptr, nullptr};
}
WriteResult QuicDefaultPacketWriter::Flush() {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_default_packet_writer.h b/chromium/net/third_party/quiche/src/quic/core/quic_default_packet_writer.h
index 36d4d8aa267..5388cae2314 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_default_packet_writer.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_default_packet_writer.h
@@ -35,8 +35,9 @@ class QUIC_EXPORT_PRIVATE QuicDefaultPacketWriter : public QuicPacketWriter {
const QuicSocketAddress& peer_address) const override;
bool SupportsReleaseTime() const override;
bool IsBatchMode() const override;
- char* GetNextWriteLocation(const QuicIpAddress& self_address,
- const QuicSocketAddress& peer_address) override;
+ QuicPacketBuffer GetNextWriteLocation(
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address) override;
WriteResult Flush() override;
void set_fd(int fd) { fd_ = fd; }
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc
index c0d39700f41..afdec636120 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc
@@ -68,9 +68,9 @@ class PacketCollector : public QuicPacketCreator::DelegateInterface,
serialized_packet.encrypted_length, true));
}
- char* GetPacketBuffer() override {
+ QuicPacketBuffer GetPacketBuffer() override {
// Let QuicPacketCreator to serialize packets on stack buffer.
- return nullptr;
+ return {nullptr, nullptr};
}
void OnUnrecoverableError(QuicErrorCode /*error*/,
@@ -181,21 +181,113 @@ class StatelessConnectionTerminator {
// Class which extracts the ALPN from a QUIC_CRYPTO CHLO packet.
class ChloAlpnExtractor : public ChloExtractor::Delegate {
public:
- void OnChlo(QuicTransportVersion /*version*/,
+ void OnChlo(QuicTransportVersion version,
QuicConnectionId /*server_connection_id*/,
const CryptoHandshakeMessage& chlo) override {
quiche::QuicheStringPiece alpn_value;
if (chlo.GetStringPiece(kALPN, &alpn_value)) {
alpn_ = std::string(alpn_value);
}
+ if (GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_dispatcher_legacy_version_encapsulation,
+ 1, 3);
+ if (version == LegacyVersionForEncapsulation().transport_version) {
+ quiche::QuicheStringPiece qlve_value;
+ if (chlo.GetStringPiece(kQLVE, &qlve_value)) {
+ legacy_version_encapsulation_inner_packet_ = std::string(qlve_value);
+ }
+ }
+ }
}
std::string&& ConsumeAlpn() { return std::move(alpn_); }
+ std::string&& ConsumeLegacyVersionEncapsulationInnerPacket() {
+ DCHECK(GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation));
+ return std::move(legacy_version_encapsulation_inner_packet_);
+ }
+
private:
std::string alpn_;
+ std::string legacy_version_encapsulation_inner_packet_;
};
+bool MaybeHandleLegacyVersionEncapsulation(
+ QuicDispatcher* dispatcher,
+ ChloAlpnExtractor* alpn_extractor,
+ const ReceivedPacketInfo& packet_info) {
+ DCHECK(GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation));
+ std::string legacy_version_encapsulation_inner_packet =
+ alpn_extractor->ConsumeLegacyVersionEncapsulationInnerPacket();
+ if (legacy_version_encapsulation_inner_packet.empty()) {
+ // This CHLO did not contain the Legacy Version Encapsulation tag.
+ return false;
+ }
+ PacketHeaderFormat format;
+ QuicLongHeaderType long_packet_type;
+ bool version_present;
+ bool has_length_prefix;
+ QuicVersionLabel version_label;
+ ParsedQuicVersion parsed_version = ParsedQuicVersion::Unsupported();
+ QuicConnectionId destination_connection_id, source_connection_id;
+ bool retry_token_present;
+ quiche::QuicheStringPiece retry_token;
+ std::string detailed_error;
+ const QuicErrorCode error = QuicFramer::ParsePublicHeaderDispatcher(
+ QuicEncryptedPacket(legacy_version_encapsulation_inner_packet.data(),
+ legacy_version_encapsulation_inner_packet.length()),
+ kQuicDefaultConnectionIdLength, &format, &long_packet_type,
+ &version_present, &has_length_prefix, &version_label, &parsed_version,
+ &destination_connection_id, &source_connection_id, &retry_token_present,
+ &retry_token, &detailed_error);
+ if (error != QUIC_NO_ERROR) {
+ QUIC_DLOG(ERROR)
+ << "Failed to parse Legacy Version Encapsulation inner packet:"
+ << detailed_error;
+ return false;
+ }
+ if (destination_connection_id != packet_info.destination_connection_id) {
+ // We enforce that the inner and outer connection IDs match to make sure
+ // this never impacts routing of packets.
+ QUIC_DLOG(ERROR) << "Ignoring Legacy Version Encapsulation packet "
+ "with mismatched connection ID "
+ << destination_connection_id << " vs "
+ << packet_info.destination_connection_id;
+ return false;
+ }
+ if (legacy_version_encapsulation_inner_packet.length() >=
+ packet_info.packet.length()) {
+ QUIC_BUG << "Inner packet cannot be larger than outer "
+ << legacy_version_encapsulation_inner_packet.length() << " vs "
+ << packet_info.packet.length();
+ return false;
+ }
+
+ QUIC_DVLOG(1) << "Extracted a Legacy Version Encapsulation "
+ << legacy_version_encapsulation_inner_packet.length()
+ << " byte packet of version " << parsed_version;
+
+ // Append zeroes to the end of the packet. This will ensure that
+ // we use the right number of bytes for calculating anti-amplification
+ // limits. Note that this only works for long headers of versions that carry
+ // long header lengths, since they'll ignore any trailing zeroes. We still
+ // do this for all packets to ensure version negotiation works.
+ legacy_version_encapsulation_inner_packet.append(
+ packet_info.packet.length() -
+ legacy_version_encapsulation_inner_packet.length(),
+ 0x00);
+
+ // Process the inner packet as if it had been received by itself.
+ QuicReceivedPacket received_encapsulated_packet(
+ legacy_version_encapsulation_inner_packet.data(),
+ legacy_version_encapsulation_inner_packet.length(),
+ packet_info.packet.receipt_time());
+ dispatcher->ProcessPacket(packet_info.self_address, packet_info.peer_address,
+ received_encapsulated_packet);
+ QUIC_CODE_COUNT(quic_legacy_version_encapsulation_decapsulated);
+ return true;
+}
+
} // namespace
QuicDispatcher::QuicDispatcher(
@@ -307,30 +399,54 @@ void QuicDispatcher::ProcessPacket(const QuicSocketAddress& self_address,
}
QuicConnectionId QuicDispatcher::MaybeReplaceServerConnectionId(
- QuicConnectionId server_connection_id,
- ParsedQuicVersion version) const {
- if (server_connection_id.length() == expected_server_connection_id_length_) {
+ const QuicConnectionId& server_connection_id,
+ const ParsedQuicVersion& version) const {
+ const uint8_t server_connection_id_length = server_connection_id.length();
+ if (server_connection_id_length == expected_server_connection_id_length_) {
return server_connection_id;
}
DCHECK(version.AllowsVariableLengthConnectionIds());
-
- QuicConnectionId new_connection_id =
- GenerateNewServerConnectionId(version, server_connection_id);
+ QuicConnectionId new_connection_id;
+ if (server_connection_id_length < expected_server_connection_id_length_) {
+ new_connection_id = ReplaceShortServerConnectionId(
+ version, server_connection_id, expected_server_connection_id_length_);
+ // Verify that ReplaceShortServerConnectionId is deterministic.
+ DCHECK_EQ(new_connection_id, ReplaceShortServerConnectionId(
+ version, server_connection_id,
+ expected_server_connection_id_length_));
+ } else {
+ new_connection_id = ReplaceLongServerConnectionId(
+ version, server_connection_id, expected_server_connection_id_length_);
+ // Verify that ReplaceLongServerConnectionId is deterministic.
+ DCHECK_EQ(new_connection_id, ReplaceLongServerConnectionId(
+ version, server_connection_id,
+ expected_server_connection_id_length_));
+ }
DCHECK_EQ(expected_server_connection_id_length_, new_connection_id.length());
- // Verify that GenerateNewServerConnectionId is deterministic.
- DCHECK_EQ(new_connection_id,
- GenerateNewServerConnectionId(version, server_connection_id));
-
QUIC_DLOG(INFO) << "Replacing incoming connection ID " << server_connection_id
<< " with " << new_connection_id;
return new_connection_id;
}
-QuicConnectionId QuicDispatcher::GenerateNewServerConnectionId(
- ParsedQuicVersion /*version*/,
- QuicConnectionId connection_id) const {
- return QuicUtils::CreateReplacementConnectionId(connection_id);
+QuicConnectionId QuicDispatcher::ReplaceShortServerConnectionId(
+ const ParsedQuicVersion& /*version*/,
+ const QuicConnectionId& server_connection_id,
+ uint8_t expected_server_connection_id_length) const {
+ DCHECK_LT(server_connection_id.length(),
+ expected_server_connection_id_length);
+ return QuicUtils::CreateReplacementConnectionId(
+ server_connection_id, expected_server_connection_id_length);
+}
+
+QuicConnectionId QuicDispatcher::ReplaceLongServerConnectionId(
+ const ParsedQuicVersion& /*version*/,
+ const QuicConnectionId& server_connection_id,
+ uint8_t expected_server_connection_id_length) const {
+ DCHECK_GT(server_connection_id.length(),
+ expected_server_connection_id_length);
+ return QuicUtils::CreateReplacementConnectionId(
+ server_connection_id, expected_server_connection_id_length);
}
bool QuicDispatcher::MaybeDispatchPacket(
@@ -367,6 +483,26 @@ bool QuicDispatcher::MaybeDispatchPacket(
auto it = session_map_.find(server_connection_id);
if (it != session_map_.end()) {
DCHECK(!buffered_packets_.HasBufferedPackets(server_connection_id));
+ if (GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_dispatcher_legacy_version_encapsulation,
+ 2, 3);
+ if (packet_info.version_flag &&
+ packet_info.version != it->second->version() &&
+ packet_info.version == LegacyVersionForEncapsulation()) {
+ // This packet is using the Legacy Version Encapsulation version but the
+ // corresponding session isn't, attempt extraction of inner packet.
+ ChloAlpnExtractor alpn_extractor;
+ if (ChloExtractor::Extract(packet_info.packet, packet_info.version,
+ config_->create_session_tag_indicators(),
+ &alpn_extractor,
+ server_connection_id.length())) {
+ if (MaybeHandleLegacyVersionEncapsulation(this, &alpn_extractor,
+ packet_info)) {
+ return true;
+ }
+ }
+ }
+ }
it->second->ProcessUdpPacket(packet_info.self_address,
packet_info.peer_address, packet_info.packet);
return true;
@@ -521,6 +657,29 @@ void QuicDispatcher::ProcessHeader(ReceivedPacketInfo* packet_info) {
BufferEarlyPacket(*packet_info);
break;
}
+ if (GetQuicReloadableFlag(quic_dont_pad_chlo)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_dont_pad_chlo, 2, 2);
+ // We only apply this check for versions that do not use the IETF
+ // invariant header because those versions are already checked in
+ // QuicDispatcher::MaybeDispatchPacket.
+ if (packet_info->version_flag &&
+ !packet_info->version.HasIetfInvariantHeader() &&
+ crypto_config()->validate_chlo_size() &&
+ packet_info->packet.length() < kMinClientInitialPacketLength) {
+ QUIC_DVLOG(1) << "Dropping CHLO packet which is too short, length: "
+ << packet_info->packet.length();
+ QUIC_CODE_COUNT(quic_drop_small_chlo_packets);
+ break;
+ }
+ }
+ if (GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(
+ quic_dispatcher_legacy_version_encapsulation, 3, 3);
+ if (MaybeHandleLegacyVersionEncapsulation(this, &alpn_extractor,
+ *packet_info)) {
+ break;
+ }
+ }
ProcessChlo({alpn_extractor.ConsumeAlpn()}, packet_info);
} break;
case kFateTimeWait:
@@ -568,36 +727,6 @@ std::string QuicDispatcher::SelectAlpn(const std::vector<std::string>& alpns) {
QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks(
const ReceivedPacketInfo& packet_info) {
if (!packet_info.version_flag) {
- // The Android network conformance test contains a UDP test that sends a
- // 12-byte packet with the following format:
- // - 0x0c (public flags: 8-byte connection ID, 1-byte packet number)
- // - randomized 8-byte connection ID
- // - 0x01 (1-byte packet number)
- // - 0x00 (private flags)
- // - 0x07 (PING frame).
- // That packet is invalid and we would normally drop it but in order to
- // unblock this conformance testing we have the following workaround that
- // will be removed once the fixed test is deployed.
- // TODO(b/139691956) Remove this workaround once fixed test is deployed.
- if (!GetQuicReloadableFlag(
- quic_remove_android_conformance_test_workaround) &&
- packet_info.packet.length() == 12 &&
- packet_info.packet.data()[0] == 0x0c &&
- packet_info.packet.data()[9] == 0x01 &&
- packet_info.packet.data()[10] == 0x00 &&
- packet_info.packet.data()[11] == 0x07) {
- QUIC_DLOG(INFO) << "Received Android UDP network conformance test "
- "packet with connection ID "
- << packet_info.destination_connection_id;
- // Respond with a public reset that the test will know how to parse
- // then return kFateDrop to stop processing of this packet.
- time_wait_list_manager()->SendPublicReset(
- packet_info.self_address, packet_info.peer_address,
- packet_info.destination_connection_id,
- /*ietf_quic=*/false, GetPerPacketContext());
- return kFateDrop;
- }
-
QUIC_DLOG(INFO)
<< "Packet without version arrived for unknown connection ID "
<< packet_info.destination_connection_id;
@@ -884,8 +1013,8 @@ void QuicDispatcher::ProcessBufferedChlos(size_t max_connections_to_create) {
CreateQuicSession(server_connection_id, packets.front().peer_address,
alpn, packet_list.version);
if (original_connection_id != server_connection_id) {
- session->connection()->AddIncomingConnectionId(original_connection_id);
- session->connection()->InstallInitialCrypters(original_connection_id);
+ session->connection()->SetOriginalDestinationConnectionId(
+ original_connection_id);
}
QUIC_DLOG(INFO) << "Created new session for " << server_connection_id;
@@ -976,10 +1105,16 @@ void QuicDispatcher::ProcessChlo(const std::vector<std::string>& alpns,
std::unique_ptr<QuicSession> session =
CreateQuicSession(packet_info->destination_connection_id,
packet_info->peer_address, alpn, packet_info->version);
- DCHECK(session);
+ if (QUIC_PREDICT_FALSE(session == nullptr)) {
+ QUIC_BUG << "CreateQuicSession returned nullptr for "
+ << packet_info->destination_connection_id << " from "
+ << packet_info->peer_address << " ALPN \"" << alpn << "\" version "
+ << packet_info->version;
+ return;
+ }
if (original_connection_id != packet_info->destination_connection_id) {
- session->connection()->AddIncomingConnectionId(original_connection_id);
- session->connection()->InstallInitialCrypters(original_connection_id);
+ session->connection()->SetOriginalDestinationConnectionId(
+ original_connection_id);
}
QUIC_DLOG(INFO) << "Created new session for "
<< packet_info->destination_connection_id;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h
index 73ab3ec4fd0..f0c35eae152 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h
@@ -103,30 +103,17 @@ class QUIC_NO_EXPORT QuicDispatcher
void OnConnectionAddedToTimeWaitList(
QuicConnectionId server_connection_id) override;
- using SessionMap = QuicUnorderedMap<QuicConnectionId,
- std::unique_ptr<QuicSession>,
- QuicConnectionIdHash>;
+ using SessionMap = QuicHashMap<QuicConnectionId,
+ std::unique_ptr<QuicSession>,
+ QuicConnectionIdHash>;
const SessionMap& session_map() const { return session_map_; }
// Deletes all sessions on the closed session list and clears the list.
virtual void DeleteSessions();
- using ConnectionIdMap = QuicUnorderedMap<QuicConnectionId,
- QuicConnectionId,
- QuicConnectionIdHash>;
-
- // The largest packet number we expect to receive with a connection
- // ID for a connection that is not established yet. The current design will
- // send a handshake and then up to 50 or so data packets, and then it may
- // resend the handshake packet up to 10 times. (Retransmitted packets are
- // sent with unique packet numbers.)
- static const uint64_t kMaxReasonableInitialPacketNumber = 100;
- static_assert(kMaxReasonableInitialPacketNumber >=
- kInitialCongestionWindow + 10,
- "kMaxReasonableInitialPacketNumber is unreasonably small "
- "relative to kInitialCongestionWindow.");
-
+ using ConnectionIdMap =
+ QuicHashMap<QuicConnectionId, QuicConnectionId, QuicConnectionIdHash>;
// QuicBufferedPacketStore::VisitorInterface implementation.
void OnExpiredPackets(QuicConnectionId server_connection_id,
@@ -162,11 +149,29 @@ class QUIC_NO_EXPORT QuicDispatcher
virtual bool MaybeDispatchPacket(const ReceivedPacketInfo& packet_info);
// Generate a connection ID with a length that is expected by the dispatcher.
+ // Called only when |server_connection_id| is shorter than
+ // |expected_connection_id_length|.
// Note that this MUST produce a deterministic result (calling this method
// with two connection IDs that are equal must produce the same result).
- virtual QuicConnectionId GenerateNewServerConnectionId(
- ParsedQuicVersion version,
- QuicConnectionId connection_id) const;
+ // Note that this is not used in general operation because our default
+ // |expected_server_connection_id_length| is 8, and the IETF specification
+ // requires clients to use an initial length of at least 8. However, we
+ // allow disabling that requirement via
+ // |allow_short_initial_server_connection_ids_|.
+ virtual QuicConnectionId ReplaceShortServerConnectionId(
+ const ParsedQuicVersion& version,
+ const QuicConnectionId& server_connection_id,
+ uint8_t expected_server_connection_id_length) const;
+
+ // Generate a connection ID with a length that is expected by the dispatcher.
+ // Called only when |server_connection_id| is longer than
+ // |expected_connection_id_length|.
+ // Note that this MUST produce a deterministic result (calling this method
+ // with two connection IDs that are equal must produce the same result).
+ virtual QuicConnectionId ReplaceLongServerConnectionId(
+ const ParsedQuicVersion& version,
+ const QuicConnectionId& server_connection_id,
+ uint8_t expected_server_connection_id_length) const;
// Values to be returned by ValidityChecks() to indicate what should be done
// with a packet. Fates with greater values are considered to be higher
@@ -308,11 +313,12 @@ class QUIC_NO_EXPORT QuicDispatcher
std::string SelectAlpn(const std::vector<std::string>& alpns);
// If the connection ID length is different from what the dispatcher expects,
- // replace the connection ID with a random one of the right length,
- // and save it to make sure the mapping is persistent.
+ // replace the connection ID with one of the right length.
+ // Note that this MUST produce a deterministic result (calling this method
+ // with two connection IDs that are equal must produce the same result).
QuicConnectionId MaybeReplaceServerConnectionId(
- QuicConnectionId server_connection_id,
- ParsedQuicVersion version) const;
+ const QuicConnectionId& server_connection_id,
+ const ParsedQuicVersion& version) const;
private:
friend class test::QuicDispatcherPeer;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc
index 814462e9d01..ef4190d470a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc
@@ -580,6 +580,73 @@ TEST_P(QuicDispatcherTestAllVersions, TlsMultiPacketClientHelloWithReordering) {
TestTlsMultiPacketClientHello(/*add_reordering=*/true);
}
+TEST_P(QuicDispatcherTestAllVersions, LegacyVersionEncapsulation) {
+ if (!version_.HasLongHeaderLengths()) {
+ // Decapsulating Legacy Version Encapsulation packets from these versions
+ // is not currently supported in QuicDispatcher.
+ return;
+ }
+ SetQuicReloadableFlag(quic_dont_pad_chlo, true);
+ SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true);
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
+ QuicConnectionId server_connection_id = TestConnectionId();
+ QuicConfig client_config = DefaultQuicConfig();
+ client_config.SetClientConnectionOptions(QuicTagVector{kQLVE});
+ std::vector<std::unique_ptr<QuicReceivedPacket>> packets =
+ GetFirstFlightOfPackets(version_, client_config, server_connection_id);
+ ASSERT_EQ(packets.size(), 1u);
+
+ // Validate that Legacy Version Encapsulation is actually being used by
+ // checking the version of the packet before processing it.
+ PacketHeaderFormat format = IETF_QUIC_LONG_HEADER_PACKET;
+ QuicLongHeaderType long_packet_type;
+ bool version_present;
+ bool has_length_prefix;
+ QuicVersionLabel version_label;
+ ParsedQuicVersion parsed_version = ParsedQuicVersion::Unsupported();
+ QuicConnectionId destination_connection_id, source_connection_id;
+ bool retry_token_present;
+ quiche::QuicheStringPiece retry_token;
+ std::string detailed_error;
+ const QuicErrorCode error = QuicFramer::ParsePublicHeaderDispatcher(
+ QuicEncryptedPacket(packets[0]->data(), packets[0]->length()),
+ kQuicDefaultConnectionIdLength, &format, &long_packet_type,
+ &version_present, &has_length_prefix, &version_label, &parsed_version,
+ &destination_connection_id, &source_connection_id, &retry_token_present,
+ &retry_token, &detailed_error);
+ ASSERT_THAT(error, IsQuicNoError()) << detailed_error;
+ EXPECT_EQ(format, GOOGLE_QUIC_PACKET);
+ EXPECT_TRUE(version_present);
+ EXPECT_FALSE(has_length_prefix);
+ EXPECT_EQ(parsed_version, LegacyVersionForEncapsulation());
+ EXPECT_EQ(destination_connection_id, server_connection_id);
+ EXPECT_EQ(source_connection_id, EmptyQuicConnectionId());
+ EXPECT_FALSE(retry_token_present);
+ EXPECT_TRUE(detailed_error.empty());
+
+ // Processing the packet should create a new session.
+ EXPECT_CALL(*dispatcher_,
+ CreateQuicSession(server_connection_id, client_address,
+ Eq(ExpectedAlpn()), _))
+ .WillOnce(Return(ByMove(CreateSession(
+ dispatcher_.get(), config_, server_connection_id, client_address,
+ &mock_helper_, &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_))));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .Times(2);
+
+ ProcessReceivedPacket(packets[0]->Clone(), client_address, version_,
+ server_connection_id);
+ EXPECT_EQ(dispatcher_->session_map().size(), 1u);
+
+ // Processing the same packet a second time should also be routed by the
+ // dispatcher to the right connection (we expect ProcessUdpPacket to be
+ // called twice, see the EXPECT_CALL above).
+ ProcessReceivedPacket(std::move(packets[0]), client_address, version_,
+ server_connection_id);
+}
+
TEST_P(QuicDispatcherTestAllVersions, ProcessPackets) {
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
@@ -1010,57 +1077,20 @@ TEST_P(QuicDispatcherTestAllVersions,
ProcessFirstFlight(client_address, EmptyQuicConnectionId());
}
-TEST_P(QuicDispatcherTestAllVersions, OKSeqNoPacketProcessed) {
- if (version_.UsesTls()) {
- // QUIC+TLS allows clients to start with any packet number.
- return;
- }
- QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
- QuicConnectionId connection_id = TestConnectionId(1);
-
- EXPECT_CALL(*dispatcher_,
- CreateQuicSession(TestConnectionId(1), client_address,
- Eq(ExpectedAlpn()), _))
- .WillOnce(Return(ByMove(CreateSession(
- dispatcher_.get(), config_, TestConnectionId(1), client_address,
- &mock_helper_, &mock_alarm_factory_, &crypto_config_,
- QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_))));
- EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
- ProcessUdpPacket(_, _, _))
- .WillOnce(WithArg<2>(Invoke([this](const QuicEncryptedPacket& packet) {
- ValidatePacket(TestConnectionId(1), packet);
- })));
-
- // A packet whose packet number is the largest that is allowed to start a
- // connection.
- EXPECT_CALL(*dispatcher_,
- ShouldCreateOrBufferPacketForConnection(
- ReceivedPacketInfoConnectionIdEquals(connection_id)));
- ProcessPacket(client_address, connection_id, true, SerializeCHLO(),
- CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER,
- QuicDispatcher::kMaxReasonableInitialPacketNumber);
-}
-
TEST_P(QuicDispatcherTestOneVersion, VersionsChangeInFlight) {
VerifyVersionNotSupported(QuicVersionReservedForNegotiation());
for (ParsedQuicVersion version : CurrentSupportedVersions()) {
VerifyVersionSupported(version);
+ QuicDisableVersion(version);
+ VerifyVersionNotSupported(version);
+ QuicEnableVersion(version);
+ VerifyVersionSupported(version);
}
-
- // Turn off version Q050.
- SetQuicReloadableFlag(quic_disable_version_q050, true);
- VerifyVersionNotSupported(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50));
-
- // Turn on version Q050.
- SetQuicReloadableFlag(quic_disable_version_q050, false);
- VerifyVersionSupported(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50));
}
TEST_P(QuicDispatcherTestOneVersion,
RejectDeprecatedVersionsWithVersionNegotiation) {
- static_assert(quic::SupportedVersions().size() == 8u,
+ static_assert(quic::SupportedVersions().size() == 9u,
"Please add deprecated versions to this test");
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
CreateTimeWaitListManager();
@@ -1275,55 +1305,6 @@ TEST_P(QuicDispatcherTestOneVersion, VersionNegotiationProbeEndToEnd) {
destination_connection_id_bytes, sizeof(destination_connection_id_bytes));
}
-TEST_P(QuicDispatcherTestOneVersion, AndroidConformanceTestOld) {
- if (GetQuicReloadableFlag(quic_remove_android_conformance_test_workaround)) {
- // TODO(b/139691956) Remove this test once the flag is deprecated.
- return;
- }
- SavingWriter* saving_writer = new SavingWriter();
- // dispatcher_ takes ownership of saving_writer.
- QuicDispatcherPeer::UseWriter(dispatcher_.get(), saving_writer);
-
- QuicTimeWaitListManager* time_wait_list_manager = new QuicTimeWaitListManager(
- saving_writer, dispatcher_.get(), mock_helper_.GetClock(),
- &mock_alarm_factory_);
- // dispatcher_ takes ownership of time_wait_list_manager.
- QuicDispatcherPeer::SetTimeWaitListManager(dispatcher_.get(),
- time_wait_list_manager);
- // clang-format off
- static const unsigned char packet[] = {
- // Android UDP network conformance test packet as it was before this change:
- // https://android-review.googlesource.com/c/platform/cts/+/1104285
- 0x0c, // public flags: 8-byte connection ID, 1-byte packet number
- 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, // 8-byte connection ID
- 0x01, // 1-byte packet number
- 0x00, // private flags
- 0x07, // PING frame
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet),
- sizeof(packet), false);
- std::unique_ptr<QuicReceivedPacket> received_packet(
- ConstructReceivedPacket(encrypted, mock_helper_.GetClock()->Now()));
- EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0);
-
- QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
- dispatcher_->ProcessPacket(server_address_, client_address, *received_packet);
- ASSERT_EQ(1u, saving_writer->packets()->size());
-
- // The Android UDP network conformance test directly checks that bytes 1-9
- // of the response match the connection ID that was sent.
- static const char connection_id_bytes[] = {0x71, 0x72, 0x73, 0x74,
- 0x75, 0x76, 0x77, 0x78};
- ASSERT_GE((*(saving_writer->packets()))[0]->length(),
- 1u + sizeof(connection_id_bytes));
- quiche::test::CompareCharArraysWithHexError(
- "response connection ID", &(*(saving_writer->packets()))[0]->data()[1],
- sizeof(connection_id_bytes), connection_id_bytes,
- sizeof(connection_id_bytes));
-}
-
TEST_P(QuicDispatcherTestOneVersion, AndroidConformanceTest) {
// WARNING: do not remove or modify this test without making sure that we
// still have adequate coverage for the Android conformance test.
@@ -1373,8 +1354,12 @@ TEST_P(QuicDispatcherTestOneVersion, AndroidConformanceTest) {
}
TEST_P(QuicDispatcherTestAllVersions, DoNotProcessSmallPacket) {
- if (!version_.HasIetfInvariantHeader()) {
- // We only drop small packets when using IETF_QUIC_LONG_HEADER_PACKET.
+ if (!version_.HasIetfInvariantHeader() &&
+ !GetQuicReloadableFlag(quic_dont_pad_chlo)) {
+ // When quic_dont_pad_chlo is false, we only drop small packets when using
+ // IETF_QUIC_LONG_HEADER_PACKET. When quic_dont_pad_chlo is true, we drop
+ // small packets for all versions.
+ // TODO(dschinazi) remove this early return when we deprecate the flag.
return;
}
CreateTimeWaitListManager();
@@ -2340,7 +2325,8 @@ TEST_P(BufferedPacketStoreTest, ReceiveCHLOForBufferedConnection) {
// Regression test for b/117874922.
TEST_P(BufferedPacketStoreTest, ProcessBufferedChloWithDifferentVersion) {
// Ensure the preferred version is not supported by the server.
- SetQuicReloadableFlag(quic_enable_version_draft_27, false);
+ QuicDisableVersion(AllSupportedVersions().front());
+
uint64_t last_connection_id = kMaxNumSessionsToCreate + 5;
ParsedQuicVersionVector supported_versions = CurrentSupportedVersions();
for (uint64_t conn_id = 1; conn_id <= last_connection_id; ++conn_id) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc
index 6afccfece10..1c0984aae17 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc
@@ -203,6 +203,8 @@ const char* QuicErrorCodeToString(QuicErrorCode error) {
RETURN_STRING_LITERAL(QUIC_HTTP_DUPLICATE_SETTING_IDENTIFIER);
RETURN_STRING_LITERAL(QUIC_HTTP_INVALID_MAX_PUSH_ID);
RETURN_STRING_LITERAL(QUIC_HTTP_STREAM_LIMIT_TOO_LOW);
+ RETURN_STRING_LITERAL(QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH);
+ RETURN_STRING_LITERAL(QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH);
RETURN_STRING_LITERAL(QUIC_HPACK_INDEX_VARINT_ERROR);
RETURN_STRING_LITERAL(QUIC_HPACK_NAME_LENGTH_VARINT_ERROR);
RETURN_STRING_LITERAL(QUIC_HPACK_VALUE_LENGTH_VARINT_ERROR);
@@ -221,6 +223,9 @@ const char* QuicErrorCodeToString(QuicErrorCode error) {
RETURN_STRING_LITERAL(QUIC_HPACK_TRUNCATED_BLOCK);
RETURN_STRING_LITERAL(QUIC_HPACK_FRAGMENT_TOO_LONG);
RETURN_STRING_LITERAL(QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT);
+ RETURN_STRING_LITERAL(QUIC_ZERO_RTT_UNRETRANSMITTABLE);
+ RETURN_STRING_LITERAL(QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED);
+ RETURN_STRING_LITERAL(QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED);
RETURN_STRING_LITERAL(QUIC_LAST_ERROR);
// Intentionally have no default case, so we'll break the build
@@ -567,6 +572,10 @@ QuicErrorCodeToIetfMapping QuicErrorCodeToTransportErrorCode(
case QUIC_HTTP_STREAM_LIMIT_TOO_LOW:
return {false, static_cast<uint64_t>(
QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR)};
+ case QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH:
+ return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::SETTINGS_ERROR)};
+ case QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
case QUIC_HPACK_INDEX_VARINT_ERROR:
return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
case QUIC_HPACK_NAME_LENGTH_VARINT_ERROR:
@@ -599,6 +608,12 @@ QuicErrorCodeToIetfMapping QuicErrorCodeToTransportErrorCode(
return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
case QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT:
return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_ZERO_RTT_UNRETRANSMITTABLE:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
case QUIC_LAST_ERROR:
return {false, static_cast<uint64_t>(QUIC_LAST_ERROR)};
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h
index f057fea1028..4c13f2c8382 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h
@@ -431,6 +431,12 @@ enum QuicErrorCode {
QUIC_HTTP_INVALID_MAX_PUSH_ID = 159,
// Received unidirectional stream limit is lower than required by HTTP/3.
QUIC_HTTP_STREAM_LIMIT_TOO_LOW = 160,
+ // Received mismatched SETTINGS frame from HTTP/3 connection where early data
+ // is accepted. Server violated the HTTP/3 spec.
+ QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH = 164,
+ // Received mismatched SETTINGS frame from HTTP/3 connection where early data
+ // is rejected. Our implementation currently doesn't support it.
+ QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH = 165,
// HPACK header block decoding errors.
// Index varint beyond implementation limit.
@@ -466,8 +472,20 @@ enum QuicErrorCode {
// Total compressed HPACK data size exceeds limit.
QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT = 150,
+ // Stream/flow control limit from 1-RTT handshake is too low to retransmit
+ // 0-RTT data. This is our implentation error. We could in theory keep the
+ // connection alive but chose not to for simplicity.
+ QUIC_ZERO_RTT_UNRETRANSMITTABLE = 161,
+ // Stream/flow control limit from 0-RTT rejection reduces cached limit.
+ // This is our implentation error. We could in theory keep the connection
+ // alive but chose not to for simplicity.
+ QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED = 162,
+ // Stream/flow control limit from 0-RTT resumption reduces cached limit.
+ // This is the peer violating QUIC spec.
+ QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED = 163,
+
// No error. Used as bound while iterating.
- QUIC_LAST_ERROR = 161,
+ QUIC_LAST_ERROR = 166,
};
// QuicErrorCodes is encoded as four octets on-the-wire when doing Google QUIC,
// or a varint62 when doing IETF QUIC. Ensure that its value does not exceed
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller.h b/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller.h
index 29c3c02d1a3..daad3d9d560 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller.h
@@ -91,6 +91,8 @@ class QUIC_EXPORT_PRIVATE QuicFlowController
QuicByteCount bytes_consumed() const { return bytes_consumed_; }
+ QuicByteCount bytes_sent() const { return bytes_sent_; }
+
QuicStreamOffset send_window_offset() const { return send_window_offset_; }
QuicStreamOffset highest_received_byte_offset() const {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc
index b05b4576d8e..139896560d6 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc
@@ -6,6 +6,7 @@
#include <cstddef>
#include <cstdint>
+#include <limits>
#include <memory>
#include <string>
#include <utility>
@@ -20,6 +21,7 @@
#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h"
#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
#include "net/third_party/quiche/src/quic/core/quic_constants.h"
#include "net/third_party/quiche/src/quic/core/quic_data_reader.h"
@@ -28,6 +30,7 @@
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_socket_address_coder.h"
#include "net/third_party/quiche/src/quic/core/quic_stream_frame_data_producer.h"
+#include "net/third_party/quiche/src/quic/core/quic_time.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
@@ -622,6 +625,17 @@ size_t QuicFramer::GetStopSendingFrameSize(const QuicStopSendingFrame& frame) {
}
// static
+size_t QuicFramer::GetAckFrequencyFrameSize(
+ const QuicAckFrequencyFrame& frame) {
+ return QuicDataWriter::GetVarInt62Len(IETF_ACK_FREQUENCY) +
+ QuicDataWriter::GetVarInt62Len(frame.sequence_number) +
+ QuicDataWriter::GetVarInt62Len(frame.packet_tolerance) +
+ QuicDataWriter::GetVarInt62Len(frame.max_ack_delay.ToMicroseconds()) +
+ // One byte for encoding boolean
+ 1;
+}
+
+// static
size_t QuicFramer::GetPathChallengeFrameSize(
const QuicPathChallengeFrame& frame) {
return kQuicFrameTypeSize + sizeof(frame.data_buffer);
@@ -675,7 +689,8 @@ size_t QuicFramer::GetRetransmittableControlFrameSize(
case HANDSHAKE_DONE_FRAME:
// HANDSHAKE_DONE has no payload.
return kQuicFrameTypeSize;
-
+ case ACK_FREQUENCY_FRAME:
+ return GetAckFrequencyFrameSize(*frame.ack_frequency_frame);
case STREAM_FRAME:
case ACK_FRAME:
case STOP_WAITING_FRAME:
@@ -1013,6 +1028,9 @@ size_t QuicFramer::BuildDataPacket(const QuicPacketHeader& header,
return 0;
}
break;
+ case HANDSHAKE_DONE_FRAME:
+ // HANDSHAKE_DONE has no payload.
+ break;
default:
RaiseError(QUIC_INVALID_FRAME_DATA);
QUIC_BUG << "QUIC_INVALID_FRAME_DATA";
@@ -1034,8 +1052,8 @@ size_t QuicFramer::AppendIetfFrames(const QuicFrames& frames,
for (const QuicFrame& frame : frames) {
// Determine if we should write stream frame length in header.
const bool last_frame_in_packet = i == frames.size() - 1;
- if (!AppendIetfTypeByte(frame, last_frame_in_packet, writer)) {
- QUIC_BUG << "AppendIetfTypeByte failed: " << detailed_error();
+ if (!AppendIetfFrameType(frame, last_frame_in_packet, writer)) {
+ QUIC_BUG << "AppendIetfFrameType failed: " << detailed_error();
return 0;
}
@@ -1182,6 +1200,12 @@ size_t QuicFramer::AppendIetfFrames(const QuicFrames& frames,
case HANDSHAKE_DONE_FRAME:
// HANDSHAKE_DONE has no payload.
break;
+ case ACK_FREQUENCY_FRAME:
+ if (!AppendAckFrequencyFrame(*frame.ack_frequency_frame, writer)) {
+ QUIC_BUG << "AppendAckFrequencyFrame failed: " << detailed_error();
+ return 0;
+ }
+ break;
default:
set_detailed_error("Tried to append unknown frame type.");
RaiseError(QUIC_INVALID_FRAME_DATA);
@@ -2004,6 +2028,10 @@ bool QuicFramer::HasEncrypterOfEncryptionLevel(EncryptionLevel level) const {
return encrypter_[level] != nullptr;
}
+bool QuicFramer::HasDecrypterOfEncryptionLevel(EncryptionLevel level) const {
+ return decrypter_[level] != nullptr;
+}
+
bool QuicFramer::AppendPacketHeader(const QuicPacketHeader& header,
QuicDataWriter* writer,
size_t* length_field_offset) {
@@ -2986,6 +3014,19 @@ bool QuicFramer::ProcessFrameData(QuicDataReader* reader,
}
break;
}
+ case HANDSHAKE_DONE_FRAME: {
+ // HANDSHAKE_DONE has no payload.
+ QuicHandshakeDoneFrame handshake_done_frame;
+ QUIC_DVLOG(2) << ENDPOINT << "Processing handshake done frame "
+ << handshake_done_frame;
+ if (!visitor_->OnHandshakeDoneFrame(handshake_done_frame)) {
+ QUIC_DVLOG(1) << ENDPOINT
+ << "Visitor asked to stop further processing.";
+ // Returning true since there was no parsing error.
+ return true;
+ }
+ break;
+ }
default:
set_detailed_error("Illegal frame type.");
@@ -3329,7 +3370,20 @@ bool QuicFramer::ProcessIetfFrameData(QuicDataReader* reader,
<< handshake_done_frame;
break;
}
-
+ case IETF_ACK_FREQUENCY: {
+ QuicAckFrequencyFrame frame;
+ if (!ProcessAckFrequencyFrame(reader, &frame)) {
+ return RaiseError(QUIC_INVALID_FRAME_DATA);
+ }
+ QUIC_DVLOG(2) << ENDPOINT << "Processing IETF ack frequency frame "
+ << frame;
+ if (!visitor_->OnAckFrequencyFrame(frame)) {
+ QUIC_DVLOG(1) << "Visitor asked to stop further processing.";
+ // Returning true since there was no parsing error.
+ return true;
+ }
+ break;
+ }
default:
set_detailed_error("Illegal frame type.");
QUIC_DLOG(WARNING)
@@ -3509,6 +3563,47 @@ bool QuicFramer::ProcessCryptoFrame(QuicDataReader* reader,
return true;
}
+bool QuicFramer::ProcessAckFrequencyFrame(QuicDataReader* reader,
+ QuicAckFrequencyFrame* frame) {
+ if (!reader->ReadVarInt62(&frame->sequence_number)) {
+ set_detailed_error("Unable to read sequence number.");
+ return false;
+ }
+
+ if (!reader->ReadVarInt62(&frame->packet_tolerance)) {
+ set_detailed_error("Unable to read packet tolerance.");
+ return false;
+ }
+ if (frame->packet_tolerance == 0) {
+ set_detailed_error("Invalid packet tolerance.");
+ return false;
+ }
+ uint64_t max_ack_delay_us;
+ if (!reader->ReadVarInt62(&max_ack_delay_us)) {
+ set_detailed_error("Unable to read max_ack_delay_us.");
+ return false;
+ }
+ constexpr uint64_t kMaxAckDelayUsBound = 1u << 24;
+ if (max_ack_delay_us > kMaxAckDelayUsBound) {
+ set_detailed_error("Invalid max_ack_delay_us.");
+ return false;
+ }
+ frame->max_ack_delay = QuicTime::Delta::FromMicroseconds(max_ack_delay_us);
+
+ uint8_t ignore_order;
+ if (!reader->ReadUInt8(&ignore_order)) {
+ set_detailed_error("Unable to read ignore_order.");
+ return false;
+ }
+ if (ignore_order > 1) {
+ set_detailed_error("Invalid ignore_order.");
+ return false;
+ }
+ frame->ignore_order = ignore_order;
+
+ return true;
+}
+
bool QuicFramer::ProcessAckFrame(QuicDataReader* reader, uint8_t frame_type) {
const bool has_ack_blocks =
ExtractBit(frame_type, kQuicHasMultipleAckBlocksOffset);
@@ -4097,8 +4192,7 @@ void QuicFramer::SetDecrypter(EncryptionLevel level,
DCHECK_GE(level, decrypter_level_);
DCHECK(!version_.KnowsWhichDecrypterToUse());
QUIC_DVLOG(1) << ENDPOINT << "Setting decrypter from level "
- << EncryptionLevelToString(decrypter_level_) << " to "
- << EncryptionLevelToString(level);
+ << decrypter_level_ << " to " << level;
decrypter_[decrypter_level_] = nullptr;
decrypter_[level] = std::move(decrypter);
decrypter_level_ = level;
@@ -4111,8 +4205,7 @@ void QuicFramer::SetAlternativeDecrypter(
DCHECK_NE(level, decrypter_level_);
DCHECK(!version_.KnowsWhichDecrypterToUse());
QUIC_DVLOG(1) << ENDPOINT << "Setting alternative decrypter from level "
- << EncryptionLevelToString(alternative_decrypter_level_)
- << " to " << EncryptionLevelToString(level);
+ << alternative_decrypter_level_ << " to " << level;
if (alternative_decrypter_level_ != NUM_ENCRYPTION_LEVELS) {
decrypter_[alternative_decrypter_level_] = nullptr;
}
@@ -4124,15 +4217,13 @@ void QuicFramer::SetAlternativeDecrypter(
void QuicFramer::InstallDecrypter(EncryptionLevel level,
std::unique_ptr<QuicDecrypter> decrypter) {
DCHECK(version_.KnowsWhichDecrypterToUse());
- QUIC_DVLOG(1) << ENDPOINT << "Installing decrypter at level "
- << EncryptionLevelToString(level);
+ QUIC_DVLOG(1) << ENDPOINT << "Installing decrypter at level " << level;
decrypter_[level] = std::move(decrypter);
}
void QuicFramer::RemoveDecrypter(EncryptionLevel level) {
DCHECK(version_.KnowsWhichDecrypterToUse());
- QUIC_DVLOG(1) << ENDPOINT << "Removing decrypter at level "
- << EncryptionLevelToString(level);
+ QUIC_DVLOG(1) << ENDPOINT << "Removing decrypter at level " << level;
decrypter_[level] = nullptr;
}
@@ -4156,14 +4247,12 @@ void QuicFramer::SetEncrypter(EncryptionLevel level,
std::unique_ptr<QuicEncrypter> encrypter) {
DCHECK_GE(level, 0);
DCHECK_LT(level, NUM_ENCRYPTION_LEVELS);
- QUIC_DVLOG(1) << ENDPOINT << "Setting encrypter at level "
- << EncryptionLevelToString(level);
+ QUIC_DVLOG(1) << ENDPOINT << "Setting encrypter at level " << level;
encrypter_[level] = std::move(encrypter);
}
void QuicFramer::RemoveEncrypter(EncryptionLevel level) {
- QUIC_DVLOG(1) << ENDPOINT << "Removing encrypter of "
- << EncryptionLevelToString(level);
+ QUIC_DVLOG(1) << ENDPOINT << "Removing encrypter of " << level;
encrypter_[level] = nullptr;
}
@@ -4185,7 +4274,7 @@ size_t QuicFramer::EncryptInPlace(EncryptionLevel level,
if (encrypter_[level] == nullptr) {
QUIC_BUG << ENDPOINT
<< "Attempted to encrypt in place without encrypter at level "
- << EncryptionLevelToString(level);
+ << level;
RaiseError(QUIC_ENCRYPTION_FAILURE);
return 0;
}
@@ -4248,7 +4337,7 @@ bool QuicFramer::ApplyHeaderProtection(EncryptionLevel level,
QUIC_BUG
<< ENDPOINT
<< "Attempted to apply header protection without encrypter at level "
- << EncryptionLevelToString(level) << " using " << version_;
+ << level << " using " << version_;
return false;
}
@@ -4318,7 +4407,7 @@ bool QuicFramer::RemoveHeaderProtection(QuicDataReader* reader,
QUIC_DVLOG(1)
<< ENDPOINT
<< "No decrypter available for removing header protection at level "
- << EncryptionLevelToString(expected_decryption_level);
+ << expected_decryption_level;
return false;
}
@@ -4439,7 +4528,7 @@ size_t QuicFramer::EncryptPayload(EncryptionLevel level,
DCHECK(packet_number.IsInitialized());
if (encrypter_[level] == nullptr) {
QUIC_BUG << ENDPOINT << "Attempted to encrypt without encrypter at level "
- << EncryptionLevelToString(level);
+ << level;
RaiseError(QUIC_ENCRYPTION_FAILURE);
return 0;
}
@@ -4449,6 +4538,14 @@ size_t QuicFramer::EncryptPayload(EncryptionLevel level,
// Copy in the header, because the encrypter only populates the encrypted
// plaintext content.
const size_t ad_len = associated_data.length();
+ if (packet.length() < ad_len) {
+ QUIC_BUG << ENDPOINT
+ << "packet is shorter than associated data length. version:"
+ << version() << ", packet length:" << packet.length()
+ << ", associated data length:" << ad_len;
+ RaiseError(QUIC_ENCRYPTION_FAILURE);
+ return 0;
+ }
memmove(buffer, associated_data.data(), ad_len);
// Encrypt the plaintext into the buffer.
size_t output_length = 0;
@@ -4474,7 +4571,7 @@ size_t QuicFramer::GetCiphertextSize(EncryptionLevel level,
if (encrypter_[level] == nullptr) {
QUIC_BUG << ENDPOINT
<< "Attempted to get ciphertext size without encrypter at level "
- << EncryptionLevelToString(level) << " using " << version_;
+ << level << " using " << version_;
return plaintext_size;
}
return encrypter_[level]->GetCiphertextSize(plaintext_size);
@@ -4729,7 +4826,7 @@ bool QuicFramer::AppendTypeByte(const QuicFrame& frame,
bool last_frame_in_packet,
QuicDataWriter* writer) {
if (VersionHasIetfQuicFrames(version_.transport_version)) {
- return AppendIetfTypeByte(frame, last_frame_in_packet, writer);
+ return AppendIetfFrameType(frame, last_frame_in_packet, writer);
}
uint8_t type_byte = 0;
switch (frame.type) {
@@ -4785,9 +4882,9 @@ bool QuicFramer::AppendTypeByte(const QuicFrame& frame,
return writer->WriteUInt8(type_byte);
}
-bool QuicFramer::AppendIetfTypeByte(const QuicFrame& frame,
- bool last_frame_in_packet,
- QuicDataWriter* writer) {
+bool QuicFramer::AppendIetfFrameType(const QuicFrame& frame,
+ bool last_frame_in_packet,
+ QuicDataWriter* writer) {
uint8_t type_byte = 0;
switch (frame.type) {
case PADDING_FRAME:
@@ -4805,7 +4902,9 @@ bool QuicFramer::AppendIetfTypeByte(const QuicFrame& frame,
type_byte = IETF_CONNECTION_CLOSE;
break;
default:
- set_detailed_error("Invalid QuicConnectionCloseFrame type.");
+ set_detailed_error(quiche::QuicheStrCat(
+ "Invalid QuicConnectionCloseFrame type: ",
+ static_cast<int>(frame.connection_close_frame->close_type)));
return RaiseError(QUIC_INTERNAL_ERROR);
}
break;
@@ -4890,12 +4989,15 @@ bool QuicFramer::AppendIetfTypeByte(const QuicFrame& frame,
case HANDSHAKE_DONE_FRAME:
type_byte = IETF_HANDSHAKE_DONE;
break;
+ case ACK_FREQUENCY_FRAME:
+ type_byte = IETF_ACK_FREQUENCY;
+ break;
default:
QUIC_BUG << "Attempt to generate a frame type for an unsupported value: "
<< frame.type;
return false;
}
- return writer->WriteUInt8(type_byte);
+ return writer->WriteVarInt62(type_byte);
}
// static
@@ -5107,6 +5209,29 @@ bool QuicFramer::AppendCryptoFrame(const QuicCryptoFrame& frame,
return true;
}
+bool QuicFramer::AppendAckFrequencyFrame(const QuicAckFrequencyFrame& frame,
+ QuicDataWriter* writer) {
+ if (!writer->WriteVarInt62(frame.sequence_number)) {
+ set_detailed_error("Writing sequence number failed.");
+ return false;
+ }
+ if (!writer->WriteVarInt62(frame.packet_tolerance)) {
+ set_detailed_error("Writing packet tolerance failed.");
+ return false;
+ }
+ if (!writer->WriteVarInt62(
+ static_cast<uint64_t>(frame.max_ack_delay.ToMicroseconds()))) {
+ set_detailed_error("Writing max_ack_delay_us failed.");
+ return false;
+ }
+ if (!writer->WriteUInt8(static_cast<uint8_t>(frame.ignore_order))) {
+ set_detailed_error("Writing ignore_order failed.");
+ return false;
+ }
+
+ return true;
+}
+
void QuicFramer::set_version(const ParsedQuicVersion version) {
DCHECK(IsSupportedVersion(version)) << ParsedQuicVersionToString(version);
version_ = version;
@@ -5365,7 +5490,7 @@ bool QuicFramer::AppendIetfAckFrameAndTypeByte(const QuicAckFrame& frame,
QuicDataWriter::GetVarInt62Len(frame.ecn_ce_count));
}
- if (!writer->WriteUInt8(type)) {
+ if (!writer->WriteVarInt62(type)) {
set_detailed_error("No room for frame-type");
return false;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer.h b/chromium/net/third_party/quiche/src/quic/core/quic_framer.h
index 8ace715d285..8e63fc25722 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_framer.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_framer.h
@@ -218,6 +218,9 @@ class QUIC_EXPORT_PRIVATE QuicFramerVisitorInterface {
// Called when a handshake done frame has been parsed.
virtual bool OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& frame) = 0;
+ // Called when an AckFrequencyFrame has been parsed.
+ virtual bool OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame) = 0;
+
// Called when a packet has been completely processed.
virtual void OnPacketComplete() = 0;
@@ -321,6 +324,8 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
// Size in bytes of all reset stream frame fields.
static size_t GetRstStreamFrameSize(QuicTransportVersion version,
const QuicRstStreamFrame& frame);
+ // Size in bytes of all ack frenquency frame fields.
+ static size_t GetAckFrequencyFrameSize(const QuicAckFrequencyFrame& frame);
// Size in bytes of all connection close frame fields, including the error
// details.
static size_t GetConnectionCloseFrameSize(
@@ -481,14 +486,16 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
bool AppendTypeByte(const QuicFrame& frame,
bool last_frame_in_packet,
QuicDataWriter* writer);
- bool AppendIetfTypeByte(const QuicFrame& frame,
- bool last_frame_in_packet,
- QuicDataWriter* writer);
+ bool AppendIetfFrameType(const QuicFrame& frame,
+ bool last_frame_in_packet,
+ QuicDataWriter* writer);
size_t AppendIetfFrames(const QuicFrames& frames, QuicDataWriter* writer);
bool AppendStreamFrame(const QuicStreamFrame& frame,
bool last_frame_in_packet,
QuicDataWriter* writer);
bool AppendCryptoFrame(const QuicCryptoFrame& frame, QuicDataWriter* writer);
+ bool AppendAckFrequencyFrame(const QuicAckFrequencyFrame& frame,
+ QuicDataWriter* writer);
// SetDecrypter sets the primary decrypter, replacing any that already exists.
// If an alternative decrypter is in place then the function DCHECKs. This is
@@ -571,6 +578,8 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
// Returns true if encrypter of |level| is available.
bool HasEncrypterOfEncryptionLevel(EncryptionLevel level) const;
+ // Returns true if decrypter of |level| is available.
+ bool HasDecrypterOfEncryptionLevel(EncryptionLevel level) const;
void set_validate_flags(bool value) { validate_flags_ = value; }
@@ -915,7 +924,8 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
bool ProcessCryptoFrame(QuicDataReader* reader,
EncryptionLevel encryption_level,
QuicCryptoFrame* frame);
-
+ bool ProcessAckFrequencyFrame(QuicDataReader* reader,
+ QuicAckFrequencyFrame* frame);
// IETF frame appending methods. All methods append the type byte as well.
bool AppendIetfStreamFrame(const QuicStreamFrame& frame,
bool last_frame_in_packet,
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc
index fb9c2eb87bc..5a5a8fa1a8a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc
@@ -406,6 +406,15 @@ class TestQuicVisitor : public QuicFramerVisitorInterface {
return true;
}
+ bool OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame) override {
+ ++frame_count_;
+ ack_frequency_frames_.emplace_back(
+ std::make_unique<QuicAckFrequencyFrame>(frame));
+ DCHECK(VersionHasIetfQuicFrames(transport_version_));
+ EXPECT_EQ(IETF_ACK_FREQUENCY, framer_->current_received_frame_type());
+ return true;
+ }
+
void OnPacketComplete() override { ++complete_packets_; }
bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override {
@@ -574,6 +583,7 @@ class TestQuicVisitor : public QuicFramerVisitorInterface {
std::vector<std::unique_ptr<QuicPingFrame>> ping_frames_;
std::vector<std::unique_ptr<QuicMessageFrame>> message_frames_;
std::vector<std::unique_ptr<QuicHandshakeDoneFrame>> handshake_done_frames_;
+ std::vector<std::unique_ptr<QuicAckFrequencyFrame>> ack_frequency_frames_;
std::vector<std::unique_ptr<QuicEncryptedPacket>> coalesced_packets_;
std::vector<std::unique_ptr<QuicEncryptedPacket>> undecryptable_packets_;
std::vector<EncryptionLevel> undecryptable_decryption_levels_;
@@ -5159,6 +5169,52 @@ TEST_P(QuicFramerTest, HandshakeDoneFrame) {
EXPECT_EQ(1u, visitor_.handshake_done_frames_.size());
}
+TEST_P(QuicFramerTest, ParseAckFrequencyFrame) {
+ SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
+ // clang-format off
+ unsigned char packet[] = {
+ // type (short header, 4 byte packet number)
+ 0x43,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+
+ // ack frequency frame type (which needs two bytes as it is > 0x3F)
+ 0x40, 0xAF,
+ // sequence_number
+ 0x11,
+ // packet_tolerance
+ 0x02,
+ // max_ack_delay_us = 2'5000 us
+ 0x80, 0x00, 0x61, 0xA8,
+ // ignore_order
+ 0x01
+ };
+ // clang-format on
+
+ if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
+ return;
+ }
+
+ QuicEncryptedPacket encrypted(AsChars(packet), QUICHE_ARRAYSIZE(packet),
+ false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_THAT(framer_.error(), IsQuicNoError());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(
+ encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
+ PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
+
+ ASSERT_EQ(1u, visitor_.ack_frequency_frames_.size());
+ const auto& frame = visitor_.ack_frequency_frames_.front();
+ EXPECT_EQ(17u, frame->sequence_number);
+ EXPECT_EQ(2u, frame->packet_tolerance);
+ EXPECT_EQ(2'5000u, frame->max_ack_delay.ToMicroseconds());
+ EXPECT_EQ(true, frame->ignore_order);
+}
+
TEST_P(QuicFramerTest, MessageFrame) {
if (!VersionSupportsMessageFrames(framer_.transport_version())) {
return;
@@ -8607,6 +8663,53 @@ TEST_P(QuicFramerTest, BuildHandshakeDonePacket) {
QUICHE_ARRAYSIZE(packet));
}
+TEST_P(QuicFramerTest, BuildAckFrequencyPacket) {
+ QuicPacketHeader header;
+ header.destination_connection_id = FramerTestConnectionId();
+ header.reset_flag = false;
+ header.version_flag = false;
+ header.packet_number = kPacketNumber;
+
+ QuicAckFrequencyFrame ack_frequency_frame;
+ ack_frequency_frame.sequence_number = 3;
+ ack_frequency_frame.packet_tolerance = 5;
+ ack_frequency_frame.max_ack_delay = QuicTime::Delta::FromMicroseconds(0x3fff);
+ ack_frequency_frame.ignore_order = false;
+ QuicFrames frames = {QuicFrame(&ack_frequency_frame)};
+
+ // clang-format off
+ unsigned char packet[] = {
+ // type (short header, 4 byte packet number)
+ 0x43,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+
+ // frame type (Ack Frequency frame)
+ 0x40, 0xaf,
+ // sequence number
+ 0x03,
+ // packet tolerance
+ 0x05,
+ // max_ack_delay_us
+ 0x7f, 0xff,
+ // ignore_oder
+ 0x00
+ };
+ // clang-format on
+ if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
+ return;
+ }
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ quiche::test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(), AsChars(packet),
+ QUICHE_ARRAYSIZE(packet));
+}
+
TEST_P(QuicFramerTest, BuildMessagePacket) {
if (!VersionSupportsMessageFrames(framer_.transport_version())) {
return;
@@ -9013,6 +9116,24 @@ TEST_P(QuicFramerTest, EncryptPacket) {
EXPECT_TRUE(CheckEncryption(packet_number, raw.get()));
}
+// Regression test for b/158014497.
+TEST_P(QuicFramerTest, EncryptEmptyPacket) {
+ auto packet = std::make_unique<QuicPacket>(
+ new char[100], 0, true, PACKET_8BYTE_CONNECTION_ID,
+ PACKET_0BYTE_CONNECTION_ID,
+ /*includes_version=*/true,
+ /*includes_diversification_nonce=*/true, PACKET_1BYTE_PACKET_NUMBER,
+ VARIABLE_LENGTH_INTEGER_LENGTH_0,
+ /*retry_token_length=*/0, VARIABLE_LENGTH_INTEGER_LENGTH_0);
+ char buffer[kMaxOutgoingPacketSize];
+ size_t encrypted_length = 1;
+ EXPECT_QUIC_BUG(encrypted_length = framer_.EncryptPayload(
+ ENCRYPTION_INITIAL, kPacketNumber, *packet, buffer,
+ kMaxOutgoingPacketSize),
+ "packet is shorter than associated data length");
+ EXPECT_EQ(0u, encrypted_length);
+}
+
TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) {
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
QuicPacketNumber packet_number = kPacketNumber;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.cc b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.cc
new file mode 100644
index 00000000000..816b8c79c50
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.cc
@@ -0,0 +1,145 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
+
+namespace quic {
+
+QuicLegacyVersionEncapsulator::QuicLegacyVersionEncapsulator(
+ QuicPacketBuffer packet_buffer)
+ : packet_buffer_(packet_buffer) {}
+
+QuicLegacyVersionEncapsulator::~QuicLegacyVersionEncapsulator() {}
+
+// static
+QuicByteCount QuicLegacyVersionEncapsulator::GetMinimumOverhead(
+ quiche::QuicheStringPiece sni) {
+ // The number 52 is the sum of:
+ // - Flags (1 byte)
+ // - Server Connection ID (8 bytes)
+ // - Version (4 bytes)
+ // - Packet Number (1 byte)
+ // - Message Authentication Hash (12 bytes)
+ // - Frame Type (1 byte)
+ // - Stream ID (1 byte)
+ // - ClientHello tag (4 bytes)
+ // - ClientHello num tags (2 bytes)
+ // - Padding (2 bytes)
+ // - SNI tag (4 bytes)
+ // - SNI end offset (4 bytes)
+ // - QLVE tag (4 bytes)
+ // - QLVE end offset (4 bytes)
+ return 52 + sni.length();
+}
+
+QuicPacketBuffer QuicLegacyVersionEncapsulator::GetPacketBuffer() {
+ return packet_buffer_;
+}
+
+void QuicLegacyVersionEncapsulator::OnSerializedPacket(
+ SerializedPacket serialized_packet) {
+ if (encrypted_length_ != 0) {
+ unrecoverable_failure_encountered_ = true;
+ QUIC_BUG << "OnSerializedPacket called twice";
+ return;
+ }
+ if (serialized_packet.encrypted_length == 0) {
+ unrecoverable_failure_encountered_ = true;
+ QUIC_BUG << "OnSerializedPacket called with empty packet";
+ return;
+ }
+ encrypted_length_ = serialized_packet.encrypted_length;
+}
+
+void QuicLegacyVersionEncapsulator::OnUnrecoverableError(
+ QuicErrorCode error,
+ const std::string& error_details) {
+ unrecoverable_failure_encountered_ = true;
+ QUIC_BUG << "QuicLegacyVersionEncapsulator received error " << error << ": "
+ << error_details;
+}
+
+bool QuicLegacyVersionEncapsulator::ShouldGeneratePacket(
+ HasRetransmittableData /*retransmittable*/,
+ IsHandshake /*handshake*/) {
+ return true;
+}
+
+const QuicFrames
+QuicLegacyVersionEncapsulator::MaybeBundleAckOpportunistically() {
+ // We do not want to ever include any ACKs here, return an empty array.
+ return QuicFrames();
+}
+
+// static
+QuicPacketLength QuicLegacyVersionEncapsulator::Encapsulate(
+ quiche::QuicheStringPiece sni,
+ quiche::QuicheStringPiece inner_packet,
+ const QuicConnectionId& server_connection_id,
+ QuicTime creation_time,
+ QuicByteCount outer_max_packet_length,
+ char* out) {
+ if (outer_max_packet_length > kMaxOutgoingPacketSize) {
+ outer_max_packet_length = kMaxOutgoingPacketSize;
+ }
+ CryptoHandshakeMessage outer_chlo;
+ outer_chlo.set_tag(kCHLO);
+ outer_chlo.SetStringPiece(kSNI, sni);
+ outer_chlo.SetStringPiece(kQLVE, inner_packet);
+ const QuicData& serialized_outer_chlo = outer_chlo.GetSerialized();
+ DCHECK(!LegacyVersionForEncapsulation().UsesCryptoFrames());
+ DCHECK(LegacyVersionForEncapsulation().UsesQuicCrypto());
+ QuicStreamFrame outer_stream_frame(
+ QuicUtils::GetCryptoStreamId(
+ LegacyVersionForEncapsulation().transport_version),
+ /*fin=*/false,
+ /*offset=*/0, serialized_outer_chlo.AsStringPiece());
+ QuicFramer outer_framer(
+ ParsedQuicVersionVector{LegacyVersionForEncapsulation()}, creation_time,
+ Perspective::IS_CLIENT, kQuicDefaultConnectionIdLength);
+ outer_framer.SetInitialObfuscators(server_connection_id);
+ char outer_encrypted_packet[kMaxOutgoingPacketSize];
+ QuicPacketBuffer outer_packet_buffer(outer_encrypted_packet, nullptr);
+ QuicLegacyVersionEncapsulator creator_delegate(outer_packet_buffer);
+ QuicPacketCreator outer_creator(server_connection_id, &outer_framer,
+ &creator_delegate);
+ outer_creator.SetMaxPacketLength(outer_max_packet_length);
+ outer_creator.set_encryption_level(ENCRYPTION_INITIAL);
+ outer_creator.SetTransmissionType(NOT_RETRANSMISSION);
+ if (!outer_creator.AddPaddedSavedFrame(QuicFrame(outer_stream_frame),
+ NOT_RETRANSMISSION)) {
+ QUIC_BUG << "Failed to add Legacy Version Encapsulation stream frame "
+ "(max packet length is "
+ << outer_creator.max_packet_length() << ") " << outer_stream_frame;
+ return 0;
+ }
+ outer_creator.FlushCurrentPacket();
+ const QuicPacketLength encrypted_length = creator_delegate.encrypted_length_;
+ if (creator_delegate.unrecoverable_failure_encountered_ ||
+ encrypted_length == 0) {
+ QUIC_BUG << "Failed to perform Legacy Version Encapsulation of "
+ << inner_packet.length() << " bytes";
+ return 0;
+ }
+ if (encrypted_length > kMaxOutgoingPacketSize) {
+ QUIC_BUG << "Legacy Version Encapsulation outer creator generated a "
+ "packet with unexpected length "
+ << encrypted_length;
+ return 0;
+ }
+
+ QUIC_DLOG(INFO) << "Successfully performed Legacy Version Encapsulation from "
+ << inner_packet.length() << " bytes to " << encrypted_length;
+
+ // Replace our current packet with the encapsulated one.
+ memcpy(out, outer_encrypted_packet, encrypted_length);
+ return encrypted_length;
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.h b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.h
new file mode 100644
index 00000000000..3d9c1564506
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_QUIC_LEGACY_VERSION_ENCAPSULATOR_H_
+#define QUICHE_QUIC_CORE_QUIC_LEGACY_VERSION_ENCAPSULATOR_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_packet_creator.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
+
+namespace quic {
+
+// QuicLegacyVersionEncapsulator is responsible for encapsulation of packets
+// using Legacy Version Encapsulation.
+
+class QUIC_EXPORT_PRIVATE QuicLegacyVersionEncapsulator
+ : public QuicPacketCreator::DelegateInterface {
+ public:
+ // Encapsulates |inner_packet| into a new encapsulated packet that uses a
+ // CHLO of version LegacyVersionForEncapsulation() with server name |sni|
+ // exposed and using |server_connection_id|. The packet will be padded up to
+ // |outer_max_packet_length| bytes if necessary. On failure, returns 0. On
+ // success, returns the length of the outer encapsulated packet, and copies
+ // the contents of the encapsulated packet to |out|. |out| must point to a
+ // valid memory buffer capable of holding kMaxOutgoingPacketSize bytes.
+ static QuicPacketLength Encapsulate(
+ quiche::QuicheStringPiece sni,
+ quiche::QuicheStringPiece inner_packet,
+ const QuicConnectionId& server_connection_id,
+ QuicTime creation_time,
+ QuicByteCount outer_max_packet_length,
+ char* out);
+
+ // Returns the number of bytes of minimum overhead caused by Legacy Version
+ // Encapsulation, based on the length of the provided server name |sni|.
+ // The overhead may be higher due to extra padding added.
+ static QuicByteCount GetMinimumOverhead(quiche::QuicheStringPiece sni);
+
+ // Overrides for QuicPacketCreator::DelegateInterface.
+ QuicPacketBuffer GetPacketBuffer() override;
+ void OnSerializedPacket(SerializedPacket serialized_packet) override;
+ void OnUnrecoverableError(QuicErrorCode error,
+ const std::string& error_details) override;
+ bool ShouldGeneratePacket(HasRetransmittableData retransmittable,
+ IsHandshake handshake) override;
+ const QuicFrames MaybeBundleAckOpportunistically() override;
+
+ ~QuicLegacyVersionEncapsulator() override;
+
+ private:
+ explicit QuicLegacyVersionEncapsulator(QuicPacketBuffer packet_buffer);
+
+ // Disallow copy, move and assignment.
+ QuicLegacyVersionEncapsulator(const QuicLegacyVersionEncapsulator&) = delete;
+ QuicLegacyVersionEncapsulator(QuicLegacyVersionEncapsulator&&) = delete;
+ QuicLegacyVersionEncapsulator& operator=(
+ const QuicLegacyVersionEncapsulator&) = delete;
+ QuicLegacyVersionEncapsulator& operator=(QuicLegacyVersionEncapsulator&&) =
+ delete;
+
+ QuicPacketBuffer packet_buffer_;
+ QuicPacketLength encrypted_length_ = 0;
+ bool unrecoverable_failure_encountered_ = false;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_CORE_QUIC_LEGACY_VERSION_ENCAPSULATOR_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator_test.cc
new file mode 100644
index 00000000000..a71b2f44eb5
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator_test.cc
@@ -0,0 +1,109 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
+
+namespace quic {
+namespace test {
+namespace {
+
+class QuicLegacyVersionEncapsulatorTest
+ : public QuicTestWithParam<ParsedQuicVersion> {
+ protected:
+ QuicLegacyVersionEncapsulatorTest()
+ : version_(GetParam()),
+ sni_("test.example.org"),
+ server_connection_id_(TestConnectionId()),
+ outer_max_packet_length_(kMaxOutgoingPacketSize),
+ encapsulated_length_(0) {}
+
+ void Encapsulate(const std::string& inner_packet) {
+ encapsulated_length_ = QuicLegacyVersionEncapsulator::Encapsulate(
+ sni_, inner_packet, server_connection_id_, QuicTime::Zero(),
+ outer_max_packet_length_, outer_buffer_);
+ }
+
+ void CheckEncapsulation() {
+ ASSERT_NE(encapsulated_length_, 0u);
+ ASSERT_EQ(encapsulated_length_, outer_max_packet_length_);
+ // Verify that the encapsulated packet parses as encapsulated.
+ PacketHeaderFormat format = IETF_QUIC_LONG_HEADER_PACKET;
+ QuicLongHeaderType long_packet_type;
+ bool version_present;
+ bool has_length_prefix;
+ QuicVersionLabel version_label;
+ ParsedQuicVersion parsed_version = ParsedQuicVersion::Unsupported();
+ QuicConnectionId destination_connection_id, source_connection_id;
+ bool retry_token_present;
+ quiche::QuicheStringPiece retry_token;
+ std::string detailed_error;
+ const QuicErrorCode error = QuicFramer::ParsePublicHeaderDispatcher(
+ QuicEncryptedPacket(outer_buffer_, encapsulated_length_),
+ kQuicDefaultConnectionIdLength, &format, &long_packet_type,
+ &version_present, &has_length_prefix, &version_label, &parsed_version,
+ &destination_connection_id, &source_connection_id, &retry_token_present,
+ &retry_token, &detailed_error);
+ ASSERT_THAT(error, IsQuicNoError()) << detailed_error;
+ EXPECT_EQ(format, GOOGLE_QUIC_PACKET);
+ EXPECT_TRUE(version_present);
+ EXPECT_FALSE(has_length_prefix);
+ EXPECT_EQ(parsed_version, LegacyVersionForEncapsulation());
+ EXPECT_EQ(destination_connection_id, server_connection_id_);
+ EXPECT_EQ(source_connection_id, EmptyQuicConnectionId());
+ EXPECT_FALSE(retry_token_present);
+ EXPECT_TRUE(detailed_error.empty());
+ }
+
+ QuicByteCount Overhead() {
+ return QuicLegacyVersionEncapsulator::GetMinimumOverhead(sni_);
+ }
+
+ ParsedQuicVersion version_;
+ std::string sni_;
+ QuicConnectionId server_connection_id_;
+ QuicByteCount outer_max_packet_length_;
+ char outer_buffer_[kMaxOutgoingPacketSize];
+ QuicPacketLength encapsulated_length_;
+};
+
+INSTANTIATE_TEST_SUITE_P(QuicLegacyVersionEncapsulatorTests,
+ QuicLegacyVersionEncapsulatorTest,
+ ::testing::ValuesIn(AllSupportedVersions()),
+ ::testing::PrintToStringParamName());
+
+TEST_P(QuicLegacyVersionEncapsulatorTest, Simple) {
+ Encapsulate("TEST_INNER_PACKET");
+ CheckEncapsulation();
+}
+
+TEST_P(QuicLegacyVersionEncapsulatorTest, TooBig) {
+ std::string inner_packet(kMaxOutgoingPacketSize, '?');
+ EXPECT_QUIC_BUG(Encapsulate(inner_packet), "Legacy Version Encapsulation");
+ ASSERT_EQ(encapsulated_length_, 0u);
+}
+
+TEST_P(QuicLegacyVersionEncapsulatorTest, BarelyFits) {
+ QuicByteCount inner_size = kMaxOutgoingPacketSize - Overhead();
+ std::string inner_packet(inner_size, '?');
+ Encapsulate(inner_packet);
+ CheckEncapsulation();
+}
+
+TEST_P(QuicLegacyVersionEncapsulatorTest, DoesNotQuiteFit) {
+ QuicByteCount inner_size = 1 + kMaxOutgoingPacketSize - Overhead();
+ std::string inner_packet(inner_size, '?');
+ EXPECT_QUIC_BUG(Encapsulate(inner_packet), "Legacy Version Encapsulation");
+ ASSERT_EQ(encapsulated_length_, 0u);
+}
+
+} // namespace
+} // namespace test
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.cc b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.cc
new file mode 100644
index 00000000000..6dd74c3b19c
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.cc
@@ -0,0 +1,314 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h"
+
+#include <linux/net_tstamp.h>
+#include <netinet/in.h>
+#include <cstdint>
+
+#include "net/third_party/quiche/src/quic/core/quic_syscall_wrapper.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+
+namespace quic {
+
+QuicMsgHdr::QuicMsgHdr(const char* buffer,
+ size_t buf_len,
+ const QuicSocketAddress& peer_address,
+ char* cbuf,
+ size_t cbuf_size)
+ : iov_{const_cast<char*>(buffer), buf_len},
+ cbuf_(cbuf),
+ cbuf_size_(cbuf_size),
+ cmsg_(nullptr) {
+ // Only support unconnected sockets.
+ DCHECK(peer_address.IsInitialized());
+
+ raw_peer_address_ = peer_address.generic_address();
+ hdr_.msg_name = &raw_peer_address_;
+ hdr_.msg_namelen = raw_peer_address_.ss_family == AF_INET
+ ? sizeof(sockaddr_in)
+ : sizeof(sockaddr_in6);
+
+ hdr_.msg_iov = &iov_;
+ hdr_.msg_iovlen = 1;
+ hdr_.msg_flags = 0;
+
+ hdr_.msg_control = nullptr;
+ hdr_.msg_controllen = 0;
+}
+
+void QuicMsgHdr::SetIpInNextCmsg(const QuicIpAddress& self_address) {
+ if (!self_address.IsInitialized()) {
+ return;
+ }
+
+ if (self_address.IsIPv4()) {
+ QuicLinuxSocketUtils::SetIpInfoInCmsgData(
+ self_address, GetNextCmsgData<in_pktinfo>(IPPROTO_IP, IP_PKTINFO));
+ } else {
+ QuicLinuxSocketUtils::SetIpInfoInCmsgData(
+ self_address, GetNextCmsgData<in6_pktinfo>(IPPROTO_IPV6, IPV6_PKTINFO));
+ }
+}
+
+void* QuicMsgHdr::GetNextCmsgDataInternal(int cmsg_level,
+ int cmsg_type,
+ size_t data_size) {
+ // msg_controllen needs to be increased first, otherwise CMSG_NXTHDR will
+ // return nullptr.
+ hdr_.msg_controllen += CMSG_SPACE(data_size);
+ DCHECK_LE(hdr_.msg_controllen, cbuf_size_);
+
+ if (cmsg_ == nullptr) {
+ DCHECK_EQ(nullptr, hdr_.msg_control);
+ memset(cbuf_, 0, cbuf_size_);
+ hdr_.msg_control = cbuf_;
+ cmsg_ = CMSG_FIRSTHDR(&hdr_);
+ } else {
+ DCHECK_NE(nullptr, hdr_.msg_control);
+ cmsg_ = CMSG_NXTHDR(&hdr_, cmsg_);
+ }
+
+ DCHECK_NE(nullptr, cmsg_) << "Insufficient control buffer space";
+
+ cmsg_->cmsg_len = CMSG_LEN(data_size);
+ cmsg_->cmsg_level = cmsg_level;
+ cmsg_->cmsg_type = cmsg_type;
+
+ return CMSG_DATA(cmsg_);
+}
+
+void QuicMMsgHdr::InitOneHeader(int i, const BufferedWrite& buffered_write) {
+ mmsghdr* mhdr = GetMMsgHdr(i);
+ msghdr* hdr = &mhdr->msg_hdr;
+ iovec* iov = GetIov(i);
+
+ iov->iov_base = const_cast<char*>(buffered_write.buffer);
+ iov->iov_len = buffered_write.buf_len;
+ hdr->msg_iov = iov;
+ hdr->msg_iovlen = 1;
+ hdr->msg_control = nullptr;
+ hdr->msg_controllen = 0;
+
+ // Only support unconnected sockets.
+ DCHECK(buffered_write.peer_address.IsInitialized());
+
+ sockaddr_storage* peer_address_storage = GetPeerAddressStorage(i);
+ *peer_address_storage = buffered_write.peer_address.generic_address();
+ hdr->msg_name = peer_address_storage;
+ hdr->msg_namelen = peer_address_storage->ss_family == AF_INET
+ ? sizeof(sockaddr_in)
+ : sizeof(sockaddr_in6);
+}
+
+void QuicMMsgHdr::SetIpInNextCmsg(int i, const QuicIpAddress& self_address) {
+ if (!self_address.IsInitialized()) {
+ return;
+ }
+
+ if (self_address.IsIPv4()) {
+ QuicLinuxSocketUtils::SetIpInfoInCmsgData(
+ self_address, GetNextCmsgData<in_pktinfo>(i, IPPROTO_IP, IP_PKTINFO));
+ } else {
+ QuicLinuxSocketUtils::SetIpInfoInCmsgData(
+ self_address,
+ GetNextCmsgData<in6_pktinfo>(i, IPPROTO_IPV6, IPV6_PKTINFO));
+ }
+}
+
+void* QuicMMsgHdr::GetNextCmsgDataInternal(int i,
+ int cmsg_level,
+ int cmsg_type,
+ size_t data_size) {
+ mmsghdr* mhdr = GetMMsgHdr(i);
+ msghdr* hdr = &mhdr->msg_hdr;
+ cmsghdr*& cmsg = *GetCmsgHdr(i);
+
+ // msg_controllen needs to be increased first, otherwise CMSG_NXTHDR will
+ // return nullptr.
+ hdr->msg_controllen += CMSG_SPACE(data_size);
+ DCHECK_LE(hdr->msg_controllen, cbuf_size_);
+
+ if (cmsg == nullptr) {
+ DCHECK_EQ(nullptr, hdr->msg_control);
+ hdr->msg_control = GetCbuf(i);
+ cmsg = CMSG_FIRSTHDR(hdr);
+ } else {
+ DCHECK_NE(nullptr, hdr->msg_control);
+ cmsg = CMSG_NXTHDR(hdr, cmsg);
+ }
+
+ DCHECK_NE(nullptr, cmsg) << "Insufficient control buffer space";
+
+ cmsg->cmsg_len = CMSG_LEN(data_size);
+ cmsg->cmsg_level = cmsg_level;
+ cmsg->cmsg_type = cmsg_type;
+
+ return CMSG_DATA(cmsg);
+}
+
+int QuicMMsgHdr::num_bytes_sent(int num_packets_sent) {
+ DCHECK_LE(0, num_packets_sent);
+ DCHECK_LE(num_packets_sent, num_msgs_);
+
+ int bytes_sent = 0;
+ iovec* iov = GetIov(0);
+ for (int i = 0; i < num_packets_sent; ++i) {
+ bytes_sent += iov[i].iov_len;
+ }
+ return bytes_sent;
+}
+
+// static
+int QuicLinuxSocketUtils::GetUDPSegmentSize(int fd) {
+ int optval;
+ socklen_t optlen = sizeof(optval);
+ int rc = getsockopt(fd, SOL_UDP, UDP_SEGMENT, &optval, &optlen);
+ if (rc < 0) {
+ QUIC_LOG_EVERY_N_SEC(INFO, 10)
+ << "getsockopt(UDP_SEGMENT) failed: " << strerror(errno);
+ return -1;
+ }
+ QUIC_LOG_EVERY_N_SEC(INFO, 10)
+ << "getsockopt(UDP_SEGMENT) returned segment size: " << optval;
+ return optval;
+}
+
+// static
+bool QuicLinuxSocketUtils::EnableReleaseTime(int fd, clockid_t clockid) {
+ // TODO(wub): Change to sock_txtime once it is available in linux/net_tstamp.h
+ struct LinuxSockTxTime {
+ clockid_t clockid; /* reference clockid */
+ uint32_t flags; /* flags defined by enum txtime_flags */
+ };
+
+ LinuxSockTxTime so_txtime_val{clockid, 0};
+
+ if (setsockopt(fd, SOL_SOCKET, SO_TXTIME, &so_txtime_val,
+ sizeof(so_txtime_val)) != 0) {
+ QUIC_LOG_EVERY_N_SEC(INFO, 10)
+ << "setsockopt(SOL_SOCKET,SO_TXTIME) failed: " << strerror(errno);
+ return false;
+ }
+
+ return true;
+}
+
+// static
+bool QuicLinuxSocketUtils::GetTtlFromMsghdr(struct msghdr* hdr, int* ttl) {
+ if (hdr->msg_controllen > 0) {
+ struct cmsghdr* cmsg;
+ for (cmsg = CMSG_FIRSTHDR(hdr); cmsg != nullptr;
+ cmsg = CMSG_NXTHDR(hdr, cmsg)) {
+ if ((cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TTL) ||
+ (cmsg->cmsg_level == IPPROTO_IPV6 &&
+ cmsg->cmsg_type == IPV6_HOPLIMIT)) {
+ *ttl = *(reinterpret_cast<int*>(CMSG_DATA(cmsg)));
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// static
+void QuicLinuxSocketUtils::SetIpInfoInCmsgData(
+ const QuicIpAddress& self_address,
+ void* cmsg_data) {
+ DCHECK(self_address.IsInitialized());
+ const std::string& address_str = self_address.ToPackedString();
+ if (self_address.IsIPv4()) {
+ in_pktinfo* pktinfo = static_cast<in_pktinfo*>(cmsg_data);
+ pktinfo->ipi_ifindex = 0;
+ memcpy(&pktinfo->ipi_spec_dst, address_str.c_str(), address_str.length());
+ } else if (self_address.IsIPv6()) {
+ in6_pktinfo* pktinfo = static_cast<in6_pktinfo*>(cmsg_data);
+ memcpy(&pktinfo->ipi6_addr, address_str.c_str(), address_str.length());
+ } else {
+ QUIC_BUG << "Unrecognized IPAddress";
+ }
+}
+
+// static
+size_t QuicLinuxSocketUtils::SetIpInfoInCmsg(const QuicIpAddress& self_address,
+ cmsghdr* cmsg) {
+ std::string address_string;
+ if (self_address.IsIPv4()) {
+ cmsg->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
+ cmsg->cmsg_level = IPPROTO_IP;
+ cmsg->cmsg_type = IP_PKTINFO;
+ in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
+ memset(pktinfo, 0, sizeof(in_pktinfo));
+ pktinfo->ipi_ifindex = 0;
+ address_string = self_address.ToPackedString();
+ memcpy(&pktinfo->ipi_spec_dst, address_string.c_str(),
+ address_string.length());
+ return sizeof(in_pktinfo);
+ } else if (self_address.IsIPv6()) {
+ cmsg->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
+ cmsg->cmsg_level = IPPROTO_IPV6;
+ cmsg->cmsg_type = IPV6_PKTINFO;
+ in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
+ memset(pktinfo, 0, sizeof(in6_pktinfo));
+ address_string = self_address.ToPackedString();
+ memcpy(&pktinfo->ipi6_addr, address_string.c_str(),
+ address_string.length());
+ return sizeof(in6_pktinfo);
+ } else {
+ QUIC_BUG << "Unrecognized IPAddress";
+ return 0;
+ }
+}
+
+// static
+WriteResult QuicLinuxSocketUtils::WritePacket(int fd, const QuicMsgHdr& hdr) {
+ int rc;
+ do {
+ rc = GetGlobalSyscallWrapper()->Sendmsg(fd, hdr.hdr(), 0);
+ } while (rc < 0 && errno == EINTR);
+ if (rc >= 0) {
+ return WriteResult(WRITE_STATUS_OK, rc);
+ }
+ return WriteResult((errno == EAGAIN || errno == EWOULDBLOCK)
+ ? WRITE_STATUS_BLOCKED
+ : WRITE_STATUS_ERROR,
+ errno);
+}
+
+// static
+WriteResult QuicLinuxSocketUtils::WriteMultiplePackets(int fd,
+ QuicMMsgHdr* mhdr,
+ int* num_packets_sent) {
+ *num_packets_sent = 0;
+
+ if (mhdr->num_msgs() <= 0) {
+ return WriteResult(WRITE_STATUS_ERROR, EINVAL);
+ }
+
+ int rc;
+ do {
+ rc = GetGlobalSyscallWrapper()->Sendmmsg(fd, mhdr->mhdr(), mhdr->num_msgs(),
+ 0);
+ } while (rc < 0 && errno == EINTR);
+
+ if (rc > 0) {
+ *num_packets_sent = rc;
+
+ return WriteResult(WRITE_STATUS_OK, mhdr->num_bytes_sent(rc));
+ } else if (rc == 0) {
+ QUIC_BUG << "sendmmsg returned 0, returning WRITE_STATUS_ERROR. errno: "
+ << errno;
+ errno = EIO;
+ }
+
+ return WriteResult((errno == EAGAIN || errno == EWOULDBLOCK)
+ ? WRITE_STATUS_BLOCKED
+ : WRITE_STATUS_ERROR,
+ errno);
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h
new file mode 100644
index 00000000000..40916579fad
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h
@@ -0,0 +1,298 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_PLATFORM_IMPL_QUIC_LINUX_SOCKET_UTILS_H_
+#define QUICHE_QUIC_PLATFORM_IMPL_QUIC_LINUX_SOCKET_UTILS_H_
+
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <deque>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+
+#ifndef SOL_UDP
+#define SOL_UDP 17
+#endif
+
+#ifndef UDP_SEGMENT
+#define UDP_SEGMENT 103
+#endif
+
+#ifndef UDP_MAX_SEGMENTS
+#define UDP_MAX_SEGMENTS (1 << 6UL)
+#endif
+
+#ifndef SO_TXTIME
+#define SO_TXTIME 61
+#endif
+
+namespace quic {
+
+const int kCmsgSpaceForIpv4 = CMSG_SPACE(sizeof(in_pktinfo));
+const int kCmsgSpaceForIpv6 = CMSG_SPACE(sizeof(in6_pktinfo));
+// kCmsgSpaceForIp should be big enough to hold both IPv4 and IPv6 packet info.
+const int kCmsgSpaceForIp = (kCmsgSpaceForIpv4 < kCmsgSpaceForIpv6)
+ ? kCmsgSpaceForIpv6
+ : kCmsgSpaceForIpv4;
+
+const int kCmsgSpaceForSegmentSize = CMSG_SPACE(sizeof(uint16_t));
+
+const int kCmsgSpaceForTxTime = CMSG_SPACE(sizeof(uint64_t));
+
+const int kCmsgSpaceForTTL = CMSG_SPACE(sizeof(int));
+
+// QuicMsgHdr is used to build msghdr objects that can be used send packets via
+// ::sendmsg.
+//
+// Example:
+// // cbuf holds control messages(cmsgs). The size is determined from what
+// // cmsgs will be set for this msghdr.
+// char cbuf[kCmsgSpaceForIp + kCmsgSpaceForSegmentSize];
+// QuicMsgHdr hdr(packet_buf, packet_buf_len, peer_addr, cbuf, sizeof(cbuf));
+//
+// // Set IP in cmsgs.
+// hdr.SetIpInNextCmsg(self_addr);
+//
+// // Set GSO size in cmsgs.
+// *hdr.GetNextCmsgData<uint16_t>(SOL_UDP, UDP_SEGMENT) = 1200;
+//
+// QuicLinuxSocketUtils::WritePacket(fd, hdr);
+class QUIC_EXPORT_PRIVATE QuicMsgHdr {
+ public:
+ QuicMsgHdr(const char* buffer,
+ size_t buf_len,
+ const QuicSocketAddress& peer_address,
+ char* cbuf,
+ size_t cbuf_size);
+
+ // Set IP info in the next cmsg. Both IPv4 and IPv6 are supported.
+ void SetIpInNextCmsg(const QuicIpAddress& self_address);
+
+ template <typename DataType>
+ DataType* GetNextCmsgData(int cmsg_level, int cmsg_type) {
+ return reinterpret_cast<DataType*>(
+ GetNextCmsgDataInternal(cmsg_level, cmsg_type, sizeof(DataType)));
+ }
+
+ const msghdr* hdr() const { return &hdr_; }
+
+ protected:
+ void* GetNextCmsgDataInternal(int cmsg_level,
+ int cmsg_type,
+ size_t data_size);
+
+ msghdr hdr_;
+ iovec iov_;
+ sockaddr_storage raw_peer_address_;
+ char* cbuf_;
+ const size_t cbuf_size_;
+ // The last cmsg populated so far. nullptr means nothing has been populated.
+ cmsghdr* cmsg_;
+};
+
+// BufferedWrite holds all information needed to send a packet.
+struct QUIC_EXPORT_PRIVATE BufferedWrite {
+ BufferedWrite(const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address)
+ : BufferedWrite(buffer,
+ buf_len,
+ self_address,
+ peer_address,
+ std::unique_ptr<PerPacketOptions>(),
+ /*release_time=*/0) {}
+
+ BufferedWrite(const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ std::unique_ptr<PerPacketOptions> options,
+ uint64_t release_time)
+ : buffer(buffer),
+ buf_len(buf_len),
+ self_address(self_address),
+ peer_address(peer_address),
+ options(std::move(options)),
+ release_time(release_time) {}
+
+ const char* buffer; // Not owned.
+ size_t buf_len;
+ QuicIpAddress self_address;
+ QuicSocketAddress peer_address;
+ std::unique_ptr<PerPacketOptions> options;
+
+ // The release time according to the owning packet writer's clock, which is
+ // often not a QuicClock. Calculated from packet writer's Now() and the
+ // release time delay in |options|.
+ // 0 means it can be sent at the same time as the previous packet in a batch,
+ // or can be sent Now() if this is the first packet of a batch.
+ uint64_t release_time;
+};
+
+// QuicMMsgHdr is used to build mmsghdr objects that can be used to send
+// multiple packets at once via ::sendmmsg.
+//
+// Example:
+// QuicCircularDeque<BufferedWrite> buffered_writes;
+// ... (Populate buffered_writes) ...
+//
+// QuicMMsgHdr mhdr(
+// buffered_writes.begin(), buffered_writes.end(), kCmsgSpaceForIp,
+// [](QuicMMsgHdr* mhdr, int i, const BufferedWrite& buffered_write) {
+// mhdr->SetIpInNextCmsg(i, buffered_write.self_address);
+// });
+//
+// int num_packets_sent;
+// QuicSocketUtils::WriteMultiplePackets(fd, &mhdr, &num_packets_sent);
+class QUIC_EXPORT_PRIVATE QuicMMsgHdr {
+ public:
+ typedef std::function<
+ void(QuicMMsgHdr* mhdr, int i, const BufferedWrite& buffered_write)>
+ ControlBufferInitializer;
+ template <typename IteratorT>
+ QuicMMsgHdr(const IteratorT& first,
+ const IteratorT& last,
+ size_t cbuf_size,
+ ControlBufferInitializer cbuf_initializer)
+ : num_msgs_(std::distance(first, last)), cbuf_size_(cbuf_size) {
+ static_assert(
+ std::is_same<typename std::iterator_traits<IteratorT>::value_type,
+ BufferedWrite>::value,
+ "Must iterate over a collection of BufferedWrite.");
+
+ DCHECK_LE(0, num_msgs_);
+ if (num_msgs_ == 0) {
+ return;
+ }
+
+ storage_.reset(new char[StorageSize()]);
+ memset(&storage_[0], 0, StorageSize());
+
+ int i = -1;
+ for (auto it = first; it != last; ++it) {
+ ++i;
+
+ InitOneHeader(i, *it);
+ if (cbuf_initializer) {
+ cbuf_initializer(this, i, *it);
+ }
+ }
+ }
+
+ void SetIpInNextCmsg(int i, const QuicIpAddress& self_address);
+
+ template <typename DataType>
+ DataType* GetNextCmsgData(int i, int cmsg_level, int cmsg_type) {
+ return reinterpret_cast<DataType*>(
+ GetNextCmsgDataInternal(i, cmsg_level, cmsg_type, sizeof(DataType)));
+ }
+
+ mmsghdr* mhdr() { return GetMMsgHdr(0); }
+
+ int num_msgs() const { return num_msgs_; }
+
+ // Get the total number of bytes in the first |num_packets_sent| packets.
+ int num_bytes_sent(int num_packets_sent);
+
+ protected:
+ void InitOneHeader(int i, const BufferedWrite& buffered_write);
+
+ void* GetNextCmsgDataInternal(int i,
+ int cmsg_level,
+ int cmsg_type,
+ size_t data_size);
+
+ size_t StorageSize() const {
+ return num_msgs_ *
+ (sizeof(mmsghdr) + sizeof(iovec) + sizeof(sockaddr_storage) +
+ sizeof(cmsghdr*) + cbuf_size_);
+ }
+
+ mmsghdr* GetMMsgHdr(int i) {
+ auto* first = reinterpret_cast<mmsghdr*>(&storage_[0]);
+ return &first[i];
+ }
+
+ iovec* GetIov(int i) {
+ auto* first = reinterpret_cast<iovec*>(GetMMsgHdr(num_msgs_));
+ return &first[i];
+ }
+
+ sockaddr_storage* GetPeerAddressStorage(int i) {
+ auto* first = reinterpret_cast<sockaddr_storage*>(GetIov(num_msgs_));
+ return &first[i];
+ }
+
+ cmsghdr** GetCmsgHdr(int i) {
+ auto* first = reinterpret_cast<cmsghdr**>(GetPeerAddressStorage(num_msgs_));
+ return &first[i];
+ }
+
+ char* GetCbuf(int i) {
+ auto* first = reinterpret_cast<char*>(GetCmsgHdr(num_msgs_));
+ return &first[i * cbuf_size_];
+ }
+
+ const int num_msgs_;
+ // Size of cmsg buffer for each message.
+ const size_t cbuf_size_;
+ // storage_ holds the memory of
+ // |num_msgs_| mmsghdr
+ // |num_msgs_| iovec
+ // |num_msgs_| sockaddr_storage, for peer addresses
+ // |num_msgs_| cmsghdr*
+ // |num_msgs_| cbuf, each of size cbuf_size
+ std::unique_ptr<char[]> storage_;
+};
+
+class QUIC_EXPORT_PRIVATE QuicLinuxSocketUtils {
+ public:
+ // Return the UDP segment size of |fd|, 0 means segment size has not been set
+ // on this socket. If GSO is not supported, return -1.
+ static int GetUDPSegmentSize(int fd);
+
+ // Enable release time on |fd|.
+ static bool EnableReleaseTime(int fd, clockid_t clockid);
+
+ // If the msghdr contains an IP_TTL entry, this will set ttl to the correct
+ // value and return true. Otherwise it will return false.
+ static bool GetTtlFromMsghdr(struct msghdr* hdr, int* ttl);
+
+ // Set IP(self_address) in |cmsg_data|. Does not touch other fields in the
+ // containing cmsghdr.
+ static void SetIpInfoInCmsgData(const QuicIpAddress& self_address,
+ void* cmsg_data);
+
+ // A helper for WritePacket which fills in the cmsg with the supplied self
+ // address.
+ // Returns the length of the packet info structure used.
+ static size_t SetIpInfoInCmsg(const QuicIpAddress& self_address,
+ cmsghdr* cmsg);
+
+ // Writes the packet in |hdr| to the socket, using ::sendmsg.
+ static WriteResult WritePacket(int fd, const QuicMsgHdr& hdr);
+
+ // Writes the packets in |mhdr| to the socket, using ::sendmmsg if available.
+ static WriteResult WriteMultiplePackets(int fd,
+ QuicMMsgHdr* mhdr,
+ int* num_packets_sent);
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_PLATFORM_IMPL_QUIC_LINUX_SOCKET_UTILS_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils_test.cc
new file mode 100644
index 00000000000..32ad12f1473
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils_test.cc
@@ -0,0 +1,329 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h"
+
+#include <netinet/in.h>
+#include <stdint.h>
+#include <cstddef>
+#include <sstream>
+#include <vector>
+
+#include <string>
+
+#include "net/third_party/quiche/src/quic/core/quic_circular_deque.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.h"
+
+using testing::_;
+using testing::InSequence;
+using testing::Invoke;
+
+namespace quic {
+namespace test {
+namespace {
+
+class QuicLinuxSocketUtilsTest : public QuicTest {
+ protected:
+ WriteResult TestWriteMultiplePackets(
+ int fd,
+ const QuicCircularDeque<BufferedWrite>::const_iterator& first,
+ const QuicCircularDeque<BufferedWrite>::const_iterator& last,
+ int* num_packets_sent) {
+ QuicMMsgHdr mhdr(
+ first, last, kCmsgSpaceForIp,
+ [](QuicMMsgHdr* mhdr, int i, const BufferedWrite& buffered_write) {
+ mhdr->SetIpInNextCmsg(i, buffered_write.self_address);
+ });
+
+ WriteResult res =
+ QuicLinuxSocketUtils::WriteMultiplePackets(fd, &mhdr, num_packets_sent);
+ return res;
+ }
+
+ MockQuicSyscallWrapper mock_syscalls_;
+ ScopedGlobalSyscallWrapperOverride syscall_override_{&mock_syscalls_};
+};
+
+void CheckIpAndTtlInCbuf(msghdr* hdr,
+ const void* cbuf,
+ const QuicIpAddress& self_addr,
+ int ttl) {
+ const bool is_ipv4 = self_addr.IsIPv4();
+ const size_t ip_cmsg_space = is_ipv4 ? kCmsgSpaceForIpv4 : kCmsgSpaceForIpv6;
+
+ EXPECT_EQ(cbuf, hdr->msg_control);
+ EXPECT_EQ(ip_cmsg_space + CMSG_SPACE(sizeof(uint16_t)), hdr->msg_controllen);
+
+ cmsghdr* cmsg = CMSG_FIRSTHDR(hdr);
+ EXPECT_EQ(cmsg->cmsg_len, is_ipv4 ? CMSG_LEN(sizeof(in_pktinfo))
+ : CMSG_LEN(sizeof(in6_pktinfo)));
+ EXPECT_EQ(cmsg->cmsg_level, is_ipv4 ? IPPROTO_IP : IPPROTO_IPV6);
+ EXPECT_EQ(cmsg->cmsg_type, is_ipv4 ? IP_PKTINFO : IPV6_PKTINFO);
+
+ const std::string& self_addr_str = self_addr.ToPackedString();
+ if (is_ipv4) {
+ in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
+ EXPECT_EQ(0, memcmp(&pktinfo->ipi_spec_dst, self_addr_str.c_str(),
+ self_addr_str.length()));
+ } else {
+ in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
+ EXPECT_EQ(0, memcmp(&pktinfo->ipi6_addr, self_addr_str.c_str(),
+ self_addr_str.length()));
+ }
+
+ cmsg = CMSG_NXTHDR(hdr, cmsg);
+ EXPECT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(int)));
+ EXPECT_EQ(cmsg->cmsg_level, is_ipv4 ? IPPROTO_IP : IPPROTO_IPV6);
+ EXPECT_EQ(cmsg->cmsg_type, is_ipv4 ? IP_TTL : IPV6_HOPLIMIT);
+ EXPECT_EQ(ttl, *reinterpret_cast<int*>(CMSG_DATA(cmsg)));
+
+ EXPECT_EQ(nullptr, CMSG_NXTHDR(hdr, cmsg));
+}
+
+void CheckMsghdrWithoutCbuf(const msghdr* hdr,
+ const void* buffer,
+ size_t buf_len,
+ const QuicSocketAddress& peer_addr) {
+ EXPECT_EQ(
+ peer_addr.host().IsIPv4() ? sizeof(sockaddr_in) : sizeof(sockaddr_in6),
+ hdr->msg_namelen);
+ sockaddr_storage peer_generic_addr = peer_addr.generic_address();
+ EXPECT_EQ(0, memcmp(hdr->msg_name, &peer_generic_addr, hdr->msg_namelen));
+ EXPECT_EQ(1u, hdr->msg_iovlen);
+ EXPECT_EQ(buffer, hdr->msg_iov->iov_base);
+ EXPECT_EQ(buf_len, hdr->msg_iov->iov_len);
+ EXPECT_EQ(0, hdr->msg_flags);
+ EXPECT_EQ(nullptr, hdr->msg_control);
+ EXPECT_EQ(0u, hdr->msg_controllen);
+}
+
+void CheckIpAndGsoSizeInCbuf(msghdr* hdr,
+ const void* cbuf,
+ const QuicIpAddress& self_addr,
+ uint16_t gso_size) {
+ const bool is_ipv4 = self_addr.IsIPv4();
+ const size_t ip_cmsg_space = is_ipv4 ? kCmsgSpaceForIpv4 : kCmsgSpaceForIpv6;
+
+ EXPECT_EQ(cbuf, hdr->msg_control);
+ EXPECT_EQ(ip_cmsg_space + CMSG_SPACE(sizeof(uint16_t)), hdr->msg_controllen);
+
+ cmsghdr* cmsg = CMSG_FIRSTHDR(hdr);
+ EXPECT_EQ(cmsg->cmsg_len, is_ipv4 ? CMSG_LEN(sizeof(in_pktinfo))
+ : CMSG_LEN(sizeof(in6_pktinfo)));
+ EXPECT_EQ(cmsg->cmsg_level, is_ipv4 ? IPPROTO_IP : IPPROTO_IPV6);
+ EXPECT_EQ(cmsg->cmsg_type, is_ipv4 ? IP_PKTINFO : IPV6_PKTINFO);
+
+ const std::string& self_addr_str = self_addr.ToPackedString();
+ if (is_ipv4) {
+ in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
+ EXPECT_EQ(0, memcmp(&pktinfo->ipi_spec_dst, self_addr_str.c_str(),
+ self_addr_str.length()));
+ } else {
+ in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
+ EXPECT_EQ(0, memcmp(&pktinfo->ipi6_addr, self_addr_str.c_str(),
+ self_addr_str.length()));
+ }
+
+ cmsg = CMSG_NXTHDR(hdr, cmsg);
+ EXPECT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(uint16_t)));
+ EXPECT_EQ(cmsg->cmsg_level, SOL_UDP);
+ EXPECT_EQ(cmsg->cmsg_type, UDP_SEGMENT);
+ EXPECT_EQ(gso_size, *reinterpret_cast<uint16_t*>(CMSG_DATA(cmsg)));
+
+ EXPECT_EQ(nullptr, CMSG_NXTHDR(hdr, cmsg));
+}
+
+TEST_F(QuicLinuxSocketUtilsTest, QuicMsgHdr) {
+ QuicSocketAddress peer_addr(QuicIpAddress::Loopback4(), 1234);
+ char packet_buf[1024];
+
+ QuicMsgHdr quic_hdr(packet_buf, sizeof(packet_buf), peer_addr, nullptr, 0);
+ CheckMsghdrWithoutCbuf(quic_hdr.hdr(), packet_buf, sizeof(packet_buf),
+ peer_addr);
+
+ for (bool is_ipv4 : {true, false}) {
+ QuicIpAddress self_addr =
+ is_ipv4 ? QuicIpAddress::Loopback4() : QuicIpAddress::Loopback6();
+ char cbuf[kCmsgSpaceForIp + kCmsgSpaceForTTL];
+ QuicMsgHdr quic_hdr(packet_buf, sizeof(packet_buf), peer_addr, cbuf,
+ sizeof(cbuf));
+ msghdr* hdr = const_cast<msghdr*>(quic_hdr.hdr());
+
+ EXPECT_EQ(nullptr, hdr->msg_control);
+ EXPECT_EQ(0u, hdr->msg_controllen);
+
+ quic_hdr.SetIpInNextCmsg(self_addr);
+ EXPECT_EQ(cbuf, hdr->msg_control);
+ const size_t ip_cmsg_space =
+ is_ipv4 ? kCmsgSpaceForIpv4 : kCmsgSpaceForIpv6;
+ EXPECT_EQ(ip_cmsg_space, hdr->msg_controllen);
+
+ if (is_ipv4) {
+ *quic_hdr.GetNextCmsgData<int>(IPPROTO_IP, IP_TTL) = 32;
+ } else {
+ *quic_hdr.GetNextCmsgData<int>(IPPROTO_IPV6, IPV6_HOPLIMIT) = 32;
+ }
+
+ CheckIpAndTtlInCbuf(hdr, cbuf, self_addr, 32);
+ }
+}
+
+TEST_F(QuicLinuxSocketUtilsTest, QuicMMsgHdr) {
+ QuicCircularDeque<BufferedWrite> buffered_writes;
+ char packet_buf1[1024];
+ char packet_buf2[512];
+ buffered_writes.emplace_back(
+ packet_buf1, sizeof(packet_buf1), QuicIpAddress::Loopback4(),
+ QuicSocketAddress(QuicIpAddress::Loopback4(), 4));
+ buffered_writes.emplace_back(
+ packet_buf2, sizeof(packet_buf2), QuicIpAddress::Loopback6(),
+ QuicSocketAddress(QuicIpAddress::Loopback6(), 6));
+
+ QuicMMsgHdr quic_mhdr_without_cbuf(buffered_writes.begin(),
+ buffered_writes.end(), 0, nullptr);
+ for (size_t i = 0; i < buffered_writes.size(); ++i) {
+ const BufferedWrite& bw = buffered_writes[i];
+ CheckMsghdrWithoutCbuf(&quic_mhdr_without_cbuf.mhdr()[i].msg_hdr, bw.buffer,
+ bw.buf_len, bw.peer_address);
+ }
+
+ QuicMMsgHdr quic_mhdr_with_cbuf(
+ buffered_writes.begin(), buffered_writes.end(),
+ kCmsgSpaceForIp + kCmsgSpaceForSegmentSize,
+ [](QuicMMsgHdr* mhdr, int i, const BufferedWrite& buffered_write) {
+ mhdr->SetIpInNextCmsg(i, buffered_write.self_address);
+ *mhdr->GetNextCmsgData<uint16_t>(i, SOL_UDP, UDP_SEGMENT) = 1300;
+ });
+ for (size_t i = 0; i < buffered_writes.size(); ++i) {
+ const BufferedWrite& bw = buffered_writes[i];
+ msghdr* hdr = &quic_mhdr_with_cbuf.mhdr()[i].msg_hdr;
+ CheckIpAndGsoSizeInCbuf(hdr, hdr->msg_control, bw.self_address, 1300);
+ }
+}
+
+TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_NoPacketsToSend) {
+ int num_packets_sent;
+ QuicCircularDeque<BufferedWrite> buffered_writes;
+
+ EXPECT_CALL(mock_syscalls_, Sendmmsg(_, _, _, _)).Times(0);
+
+ EXPECT_EQ(WriteResult(WRITE_STATUS_ERROR, EINVAL),
+ TestWriteMultiplePackets(1, buffered_writes.begin(),
+ buffered_writes.end(), &num_packets_sent));
+}
+
+TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_WriteBlocked) {
+ int num_packets_sent;
+ QuicCircularDeque<BufferedWrite> buffered_writes;
+ buffered_writes.emplace_back(nullptr, 0, QuicIpAddress(),
+ QuicSocketAddress(QuicIpAddress::Any4(), 0));
+
+ EXPECT_CALL(mock_syscalls_, Sendmmsg(_, _, _, _))
+ .WillOnce(Invoke([](int /*fd*/, mmsghdr* /*msgvec*/,
+ unsigned int /*vlen*/, int /*flags*/) {
+ errno = EWOULDBLOCK;
+ return -1;
+ }));
+
+ EXPECT_EQ(WriteResult(WRITE_STATUS_BLOCKED, EWOULDBLOCK),
+ TestWriteMultiplePackets(1, buffered_writes.begin(),
+ buffered_writes.end(), &num_packets_sent));
+ EXPECT_EQ(0, num_packets_sent);
+}
+
+TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_WriteError) {
+ int num_packets_sent;
+ QuicCircularDeque<BufferedWrite> buffered_writes;
+ buffered_writes.emplace_back(nullptr, 0, QuicIpAddress(),
+ QuicSocketAddress(QuicIpAddress::Any4(), 0));
+
+ EXPECT_CALL(mock_syscalls_, Sendmmsg(_, _, _, _))
+ .WillOnce(Invoke([](int /*fd*/, mmsghdr* /*msgvec*/,
+ unsigned int /*vlen*/, int /*flags*/) {
+ errno = EPERM;
+ return -1;
+ }));
+
+ EXPECT_EQ(WriteResult(WRITE_STATUS_ERROR, EPERM),
+ TestWriteMultiplePackets(1, buffered_writes.begin(),
+ buffered_writes.end(), &num_packets_sent));
+ EXPECT_EQ(0, num_packets_sent);
+}
+
+TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_WriteSuccess) {
+ int num_packets_sent;
+ QuicCircularDeque<BufferedWrite> buffered_writes;
+ const int kNumBufferedWrites = 10;
+ static_assert(kNumBufferedWrites < 256, "Must be less than 256");
+ std::vector<std::string> buffer_holder;
+ for (int i = 0; i < kNumBufferedWrites; ++i) {
+ size_t buf_len = (i + 1) * 2;
+ std::ostringstream buffer_ostream;
+ while (buffer_ostream.str().length() < buf_len) {
+ buffer_ostream << i;
+ }
+ buffer_holder.push_back(buffer_ostream.str().substr(0, buf_len - 1) + '$');
+
+ buffered_writes.emplace_back(buffer_holder.back().data(), buf_len,
+ QuicIpAddress(),
+ QuicSocketAddress(QuicIpAddress::Any4(), 0));
+
+ // Leave the first self_address uninitialized.
+ if (i != 0) {
+ ASSERT_TRUE(buffered_writes.back().self_address.FromString("127.0.0.1"));
+ }
+
+ std::ostringstream peer_ip_ostream;
+ QuicIpAddress peer_ip_address;
+ peer_ip_ostream << "127.0.1." << i + 1;
+ ASSERT_TRUE(peer_ip_address.FromString(peer_ip_ostream.str()));
+ buffered_writes.back().peer_address =
+ QuicSocketAddress(peer_ip_address, i + 1);
+ }
+
+ InSequence s;
+
+ for (int expected_num_packets_sent : {1, 2, 3, 10}) {
+ SCOPED_TRACE(testing::Message()
+ << "expected_num_packets_sent=" << expected_num_packets_sent);
+ EXPECT_CALL(mock_syscalls_, Sendmmsg(_, _, _, _))
+ .WillOnce(Invoke(
+ [&](int /*fd*/, mmsghdr* msgvec, unsigned int vlen, int /*flags*/) {
+ EXPECT_LE(static_cast<unsigned int>(expected_num_packets_sent),
+ vlen);
+ for (unsigned int i = 0; i < vlen; ++i) {
+ const BufferedWrite& buffered_write = buffered_writes[i];
+ const msghdr& hdr = msgvec[i].msg_hdr;
+ EXPECT_EQ(1u, hdr.msg_iovlen);
+ EXPECT_EQ(buffered_write.buffer, hdr.msg_iov->iov_base);
+ EXPECT_EQ(buffered_write.buf_len, hdr.msg_iov->iov_len);
+ sockaddr_storage expected_peer_address =
+ buffered_write.peer_address.generic_address();
+ EXPECT_EQ(0, memcmp(&expected_peer_address, hdr.msg_name,
+ sizeof(sockaddr_storage)));
+ EXPECT_EQ(buffered_write.self_address.IsInitialized(),
+ hdr.msg_control != nullptr);
+ }
+ return expected_num_packets_sent;
+ }))
+ .RetiresOnSaturation();
+
+ int expected_bytes_written = 0;
+ for (auto it = buffered_writes.cbegin();
+ it != buffered_writes.cbegin() + expected_num_packets_sent; ++it) {
+ expected_bytes_written += it->buf_len;
+ }
+
+ EXPECT_EQ(
+ WriteResult(WRITE_STATUS_OK, expected_bytes_written),
+ TestWriteMultiplePackets(1, buffered_writes.cbegin(),
+ buffered_writes.cend(), &num_packets_sent));
+ EXPECT_EQ(expected_num_packets_sent, num_packets_sent);
+ }
+}
+
+} // namespace
+} // namespace test
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc
index 0ae78d22fa6..c1f8982f705 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc
@@ -47,10 +47,10 @@ QuicLongHeaderType EncryptionlevelToLongHeaderType(EncryptionLevel level) {
case ENCRYPTION_FORWARD_SECURE:
QUIC_BUG
<< "Try to derive long header type for packet with encryption level: "
- << EncryptionLevelToString(level);
+ << level;
return INVALID_PACKET_TYPE;
default:
- QUIC_BUG << EncryptionLevelToString(level);
+ QUIC_BUG << level;
return INVALID_PACKET_TYPE;
}
}
@@ -165,6 +165,8 @@ void QuicPacketCreator::SetMaxPacketLength(QuicByteCount length) {
if (length == max_packet_length_) {
return;
}
+ QUIC_DVLOG(1) << "Updating packet creator max packet length from "
+ << max_packet_length_ << " to " << length;
max_packet_length_ = length;
max_plaintext_size_ = framer_->GetMaxPlaintextSize(max_packet_length_);
@@ -198,6 +200,8 @@ void QuicPacketCreator::SetSoftMaxPacketLength(QuicByteCount length) {
}
if (framer_->GetMaxPlaintextSize(length) <
PacketHeaderSize() + MinPlaintextPacketSize(framer_->version())) {
+ // Please note: this would not guarantee to fit next packet if the size of
+ // packet header increases (e.g., encryption level changes).
QUIC_DLOG(INFO) << length << " is too small to fit packet header";
return;
}
@@ -281,6 +285,10 @@ bool QuicPacketCreator::ConsumeCryptoDataToFillCurrentPacket(
bool needs_full_padding,
TransmissionType transmission_type,
QuicFrame* frame) {
+ QUIC_DVLOG(2) << "ConsumeCryptoDataToFillCurrentPacket " << level
+ << " write_length " << write_length << " offset " << offset
+ << (needs_full_padding ? " needs_full_padding" : "") << " "
+ << transmission_type;
if (!CreateCryptoFrame(level, write_length, offset, frame)) {
return false;
}
@@ -423,8 +431,17 @@ bool QuicPacketCreator::CreateCryptoFrame(EncryptionLevel level,
QuicFrame* frame) {
size_t min_frame_size =
QuicFramer::GetMinCryptoFrameSize(write_length, offset);
- if (BytesFree() <= min_frame_size &&
- (!RemoveSoftMaxPacketLength() || BytesFree() <= min_frame_size)) {
+ size_t min_plaintext_bytes = min_frame_size;
+ if (fix_min_crypto_frame_size_ && queued_frames_.empty()) {
+ // TODO(fayang): to make this more general, we need to move the checking
+ // when trying to add a frame when GetSerializedFrameLength. Remove soft
+ // limit if current packet needs extra padding and the space is too small.
+ QUIC_RELOADABLE_FLAG_COUNT(quic_fix_min_crypto_frame_size);
+ min_plaintext_bytes =
+ std::max(min_frame_size, MinPlaintextPacketSize(framer_->version()));
+ }
+ if (BytesFree() <= min_plaintext_bytes &&
+ (!RemoveSoftMaxPacketLength() || BytesFree() <= min_plaintext_bytes)) {
return false;
}
size_t max_write_length = BytesFree() - min_frame_size;
@@ -439,12 +456,23 @@ void QuicPacketCreator::FlushCurrentPacket() {
}
QUIC_CACHELINE_ALIGNED char stack_buffer[kMaxOutgoingPacketSize];
- char* serialized_packet_buffer = delegate_->GetPacketBuffer();
- if (serialized_packet_buffer == nullptr) {
- serialized_packet_buffer = stack_buffer;
+ QuicOwnedPacketBuffer external_buffer(delegate_->GetPacketBuffer());
+
+ if (!avoid_leak_writer_buffer_ && external_buffer.release_buffer != nullptr) {
+ // This is not a flag count because it is incremented when flag is false.
+ QUIC_CODE_COUNT(quic_avoid_leak_writer_buffer_flag_false_noop_1);
+
+ // Setting it to nullptr to keep the behavior unchanged when flag is false.
+ external_buffer.release_buffer = nullptr;
+ }
+
+ if (external_buffer.buffer == nullptr) {
+ external_buffer.buffer = stack_buffer;
+ external_buffer.release_buffer = nullptr;
}
- SerializePacket(serialized_packet_buffer, kMaxOutgoingPacketSize);
+ DCHECK_EQ(nullptr, packet_.encrypted_buffer);
+ SerializePacket(std::move(external_buffer), kMaxOutgoingPacketSize);
OnSerializedPacket();
}
@@ -471,6 +499,12 @@ void QuicPacketCreator::ClearPacket() {
packet_.transmission_type = NOT_RETRANSMISSION;
packet_.encrypted_buffer = nullptr;
packet_.encrypted_length = 0;
+ if (avoid_leak_writer_buffer_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_avoid_leak_writer_buffer, 2, 3);
+ QUIC_BUG_IF(packet_.release_encrypted_buffer != nullptr)
+ << "packet_.release_encrypted_buffer should be empty";
+ packet_.release_encrypted_buffer = nullptr;
+ }
DCHECK(packet_.retransmittable_frames.empty());
DCHECK(packet_.nonretransmittable_frames.empty());
packet_.largest_acked.Clear();
@@ -514,7 +548,7 @@ size_t QuicPacketCreator::ReserializeInitialPacketInCoalescedPacket(
return 0;
}
}
- SerializePacket(buffer, buffer_len);
+ SerializePacket(QuicOwnedPacketBuffer(buffer, nullptr), buffer_len);
const size_t encrypted_length = packet_.encrypted_length;
// Clear frames in packet_. No need to DeleteFrames since frames are owned by
// initial_packet.
@@ -533,16 +567,29 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame(
TransmissionType transmission_type,
size_t* num_bytes_consumed) {
DCHECK(queued_frames_.empty());
+ DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id));
// Write out the packet header
QuicPacketHeader header;
FillPacketHeader(&header);
QUIC_CACHELINE_ALIGNED char stack_buffer[kMaxOutgoingPacketSize];
- char* encrypted_buffer = delegate_->GetPacketBuffer();
- if (encrypted_buffer == nullptr) {
- encrypted_buffer = stack_buffer;
+ QuicOwnedPacketBuffer packet_buffer(delegate_->GetPacketBuffer());
+
+ if (!avoid_leak_writer_buffer_ && packet_buffer.release_buffer != nullptr) {
+ // This is not a flag count because it is incremented when flag is false.
+ QUIC_CODE_COUNT(quic_avoid_leak_writer_buffer_flag_false_noop_2);
+
+ // Setting it to nullptr to keep the behavior unchanged when flag is false.
+ packet_buffer.release_buffer = nullptr;
}
+ if (packet_buffer.buffer == nullptr) {
+ packet_buffer.buffer = stack_buffer;
+ packet_buffer.release_buffer = nullptr;
+ }
+
+ char* encrypted_buffer = packet_buffer.buffer;
+
QuicDataWriter writer(kMaxOutgoingPacketSize, encrypted_buffer);
size_t length_field_offset = 0;
if (!framer_->AppendPacketHeader(header, &writer, &length_field_offset)) {
@@ -609,6 +656,9 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame(
packet_.transmission_type = transmission_type;
+ DCHECK(packet_.encryption_level == ENCRYPTION_FORWARD_SECURE ||
+ packet_.encryption_level == ENCRYPTION_ZERO_RTT)
+ << packet_.encryption_level;
size_t encrypted_length = framer_->EncryptInPlace(
packet_.encryption_level, packet_.packet_number,
GetStartOfEncryptedData(framer_->transport_version(), header),
@@ -623,6 +673,14 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame(
packet_size_ = 0;
packet_.encrypted_buffer = encrypted_buffer;
packet_.encrypted_length = encrypted_length;
+ if (avoid_leak_writer_buffer_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_avoid_leak_writer_buffer, 3, 3);
+ packet_.release_encrypted_buffer = std::move(packet_buffer).release_buffer;
+ } else {
+ // If flag --quic_avoid_leak_writer_buffer is false, the release function
+ // should be empty.
+ DCHECK(packet_buffer.release_buffer == nullptr);
+ }
packet_.retransmittable_frames.push_back(QuicFrame(frame));
OnSerializedPacket();
}
@@ -674,6 +732,9 @@ size_t QuicPacketCreator::BytesFree() {
}
size_t QuicPacketCreator::PacketSize() {
+ if (update_packet_size_) {
+ return queued_frames_.empty() ? PacketHeaderSize() : packet_size_;
+ }
if (!queued_frames_.empty()) {
return packet_size_;
}
@@ -691,7 +752,7 @@ bool QuicPacketCreator::AddPaddedSavedFrame(
return false;
}
-void QuicPacketCreator::SerializePacket(char* encrypted_buffer,
+void QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer,
size_t encrypted_buffer_len) {
DCHECK_LT(0u, encrypted_buffer_len);
QUIC_BUG_IF(queued_frames_.empty() && pending_padding_bytes_ == 0)
@@ -704,14 +765,13 @@ void QuicPacketCreator::SerializePacket(char* encrypted_buffer,
QUIC_DVLOG(2) << ENDPOINT << "Serializing packet " << header
<< QuicFramesToString(queued_frames_) << " at encryption_level "
- << EncryptionLevelToString(packet_.encryption_level);
+ << packet_.encryption_level;
if (!framer_->HasEncrypterOfEncryptionLevel(packet_.encryption_level)) {
QUIC_BUG << ENDPOINT << "Attempting to serialize " << header
<< QuicFramesToString(queued_frames_)
- << " at missing encryption_level "
- << EncryptionLevelToString(packet_.encryption_level) << " using "
- << framer_->version();
+ << " at missing encryption_level " << packet_.encryption_level
+ << " using " << framer_->version();
return;
}
@@ -719,10 +779,18 @@ void QuicPacketCreator::SerializePacket(char* encrypted_buffer,
// Use the packet_size_ instead of the buffer size to ensure smaller
// packet sizes are properly used.
size_t length =
- framer_->BuildDataPacket(header, queued_frames_, encrypted_buffer,
+ framer_->BuildDataPacket(header, queued_frames_, encrypted_buffer.buffer,
packet_size_, packet_.encryption_level);
if (length == 0) {
- QUIC_BUG << "Failed to serialize " << queued_frames_.size() << " frames.";
+ QUIC_BUG << "Failed to serialize " << QuicFramesToString(queued_frames_)
+ << " at encryption_level: " << packet_.encryption_level
+ << ", needs_full_padding_: " << needs_full_padding_
+ << ", packet_.num_padding_bytes: " << packet_.num_padding_bytes
+ << ", pending_padding_bytes_: " << pending_padding_bytes_
+ << ", latched_hard_max_packet_length_: "
+ << latched_hard_max_packet_length_
+ << ", max_packet_length_: " << max_packet_length_
+ << ", header: " << header;
return;
}
@@ -741,7 +809,7 @@ void QuicPacketCreator::SerializePacket(char* encrypted_buffer,
const size_t encrypted_length = framer_->EncryptInPlace(
packet_.encryption_level, packet_.packet_number,
GetStartOfEncryptedData(framer_->transport_version(), header), length,
- encrypted_buffer_len, encrypted_buffer);
+ encrypted_buffer_len, encrypted_buffer.buffer);
if (encrypted_length == 0) {
QUIC_BUG << "Failed to encrypt packet number " << packet_.packet_number;
return;
@@ -749,8 +817,17 @@ void QuicPacketCreator::SerializePacket(char* encrypted_buffer,
packet_size_ = 0;
queued_frames_.clear();
- packet_.encrypted_buffer = encrypted_buffer;
+ packet_.encrypted_buffer = encrypted_buffer.buffer;
packet_.encrypted_length = encrypted_length;
+ if (avoid_leak_writer_buffer_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_avoid_leak_writer_buffer, 1, 3);
+ packet_.release_encrypted_buffer =
+ std::move(encrypted_buffer).release_buffer;
+ } else {
+ // If flag --quic_avoid_leak_writer_buffer is false, the release function
+ // should be empty.
+ DCHECK(encrypted_buffer.release_buffer == nullptr);
+ }
}
std::unique_ptr<QuicEncryptedPacket>
@@ -785,6 +862,7 @@ QuicPacketCreator::SerializeConnectivityProbingPacket() {
header, buffer.get(), max_plaintext_size_, packet_.encryption_level);
DCHECK(length);
+ DCHECK_EQ(packet_.encryption_level, ENCRYPTION_FORWARD_SECURE);
const size_t encrypted_length = framer_->EncryptInPlace(
packet_.encryption_level, packet_.packet_number,
GetStartOfEncryptedData(framer_->transport_version(), header), length,
@@ -824,6 +902,7 @@ QuicPacketCreator::SerializePathChallengeConnectivityProbingPacket(
packet_.encryption_level);
DCHECK(length);
+ DCHECK_EQ(packet_.encryption_level, ENCRYPTION_FORWARD_SECURE);
const size_t encrypted_length = framer_->EncryptInPlace(
packet_.encryption_level, packet_.packet_number,
GetStartOfEncryptedData(framer_->transport_version(), header), length,
@@ -865,6 +944,7 @@ QuicPacketCreator::SerializePathResponseConnectivityProbingPacket(
payloads, is_padded, packet_.encryption_level);
DCHECK(length);
+ DCHECK_EQ(packet_.encryption_level, ENCRYPTION_FORWARD_SECURE);
const size_t encrypted_length = framer_->EncryptInPlace(
packet_.encryption_level, packet_.packet_number,
GetStartOfEncryptedData(framer_->transport_version(), header), length,
@@ -1180,9 +1260,9 @@ QuicConsumedData QuicPacketCreator::ConsumeData(QuicStreamId id,
write_length - total_bytes_consumed > kMaxOutgoingPacketSize &&
latched_hard_max_packet_length_ == 0;
- while (!run_fast_path && delegate_->ShouldGeneratePacket(
- HAS_RETRANSMITTABLE_DATA,
- has_handshake ? IS_HANDSHAKE : NOT_HANDSHAKE)) {
+ while (!run_fast_path &&
+ (has_handshake || delegate_->ShouldGeneratePacket(
+ HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE))) {
QuicFrame frame;
bool needs_full_padding =
has_handshake && fully_pad_crypto_handshake_packets_;
@@ -1268,6 +1348,8 @@ QuicConsumedData QuicPacketCreator::ConsumeDataFastPath(
size_t QuicPacketCreator::ConsumeCryptoData(EncryptionLevel level,
size_t write_length,
QuicStreamOffset offset) {
+ QUIC_DVLOG(2) << "ConsumeCryptoData " << level << " write_length "
+ << write_length << " offset " << offset;
QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when "
"generator tries to write crypto data.";
MaybeBundleAckOpportunistically();
@@ -1282,7 +1364,13 @@ size_t QuicPacketCreator::ConsumeCryptoData(EncryptionLevel level,
size_t total_bytes_consumed = 0;
- while (total_bytes_consumed < write_length) {
+ while (total_bytes_consumed < write_length &&
+ (!GetQuicReloadableFlag(quic_fix_checking_should_generate_packet) ||
+ delegate_->ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA,
+ IS_HANDSHAKE))) {
+ if (GetQuicReloadableFlag(quic_fix_checking_should_generate_packet)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_fix_checking_should_generate_packet);
+ }
QuicFrame frame;
if (!ConsumeCryptoDataToFillCurrentPacket(
level, write_length - total_bytes_consumed,
@@ -1484,7 +1572,7 @@ void QuicPacketCreator::FillPacketHeader(QuicPacketHeader* header) {
bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
TransmissionType transmission_type) {
QUIC_DVLOG(1) << ENDPOINT << "Adding frame with transmission type "
- << TransmissionTypeToString(transmission_type) << ": " << frame;
+ << transmission_type << ": " << frame;
if (frame.type == STREAM_FRAME &&
!QuicUtils::IsCryptoStreamId(framer_->transport_version(),
frame.stream_frame.stream_id) &&
@@ -1518,10 +1606,15 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
/* last_frame_in_packet= */ true, GetPacketNumberLength());
}
if (frame_len == 0) {
- // Current open packet is full.
+ QUIC_DVLOG(1) << "Flushing because current open packet is full when adding "
+ << frame;
FlushCurrentPacket();
return false;
}
+ if (update_packet_size_ && queued_frames_.empty()) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_update_packet_size);
+ packet_size_ = PacketHeaderSize();
+ }
DCHECK_LT(0u, packet_size_);
packet_size_ += ExpansionOnNewFrame() + frame_len;
@@ -1641,6 +1734,10 @@ void QuicPacketCreator::MaybeAddPadding() {
}
}
+ if (disable_padding_override_) {
+ needs_full_padding_ = false;
+ }
+
// Header protection requires a minimum plaintext packet size.
size_t extra_padding_bytes = 0;
if (framer_->version().HasHeaderProtection()) {
@@ -1675,8 +1772,7 @@ void QuicPacketCreator::MaybeAddPadding() {
bool success = AddFrame(QuicFrame(QuicPaddingFrame(padding_bytes)),
packet_.transmission_type);
QUIC_BUG_IF(!success) << "Failed to add padding_bytes: " << padding_bytes
- << " transmission_type: "
- << TransmissionTypeToString(packet_.transmission_type);
+ << " transmission_type: " << packet_.transmission_type;
}
bool QuicPacketCreator::IncludeNonceInPublicHeader() const {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h
index 7695587f9f5..76d65574e51 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h
@@ -41,9 +41,9 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
public:
virtual ~DelegateInterface() {}
// Get a buffer of kMaxOutgoingPacketSize bytes to serialize the next
- // packet. If return nullptr, QuicPacketCreator will serialize on a stack
- // buffer.
- virtual char* GetPacketBuffer() = 0;
+ // packet. If the return value's buffer is nullptr, QuicPacketCreator will
+ // serialize on a stack buffer.
+ virtual QuicPacketBuffer GetPacketBuffer() = 0;
// Called when a packet is serialized. Delegate take the ownership of
// |serialized_packet|.
virtual void OnSerializedPacket(SerializedPacket serialized_packet) = 0;
@@ -142,12 +142,14 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// Returns true if current open packet can accommodate more stream frames of
// stream |id| at |offset| and data length |data_size|, false otherwise.
+ // TODO(fayang): mark this const when deprecating quic_update_packet_size.
bool HasRoomForStreamFrame(QuicStreamId id,
QuicStreamOffset offset,
size_t data_size);
// Returns true if current open packet can accommodate a message frame of
// |length|.
+ // TODO(fayang): mark this const when deprecating quic_update_packet_size.
bool HasRoomForMessageFrame(QuicByteCount length);
// Serializes all added frames into a single packet and invokes the delegate_
@@ -179,6 +181,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// frames in the packet. Since stream frames are slightly smaller when they
// are the last frame in a packet, this method will return a different
// value than max_packet_size - PacketSize(), in this case.
+ // TODO(fayang): mark this const when deprecating quic_update_packet_size.
size_t BytesFree();
// Returns the number of bytes that the packet will expand by if a new frame
@@ -191,6 +194,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// if serialized with the current frames. Adding a frame to the packet
// may change the serialized length of existing frames, as per the comment
// in BytesFree.
+ // TODO(fayang): mark this const when deprecating quic_update_packet_size.
size_t PacketSize();
// Tries to add |frame| to the packet creator's list of frames to be
@@ -255,6 +259,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
void set_encryption_level(EncryptionLevel level) {
packet_.encryption_level = level;
}
+ EncryptionLevel encryption_level() { return packet_.encryption_level; }
// packet number of the last created packet, or 0 if no packets have been
// created.
@@ -429,6 +434,10 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
char* buffer,
size_t buffer_len);
+ void set_disable_padding_override(bool should_disable_padding) {
+ disable_padding_override_ = should_disable_padding;
+ }
+
private:
friend class test::QuicPacketCreatorPeer;
@@ -459,7 +468,8 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// retransmitted to packet_.retransmittable_frames. All frames must fit into
// a single packet.
// Fails if |encrypted_buffer_len| isn't long enough for the encrypted packet.
- void SerializePacket(char* encrypted_buffer, size_t encrypted_buffer_len);
+ void SerializePacket(QuicOwnedPacketBuffer encrypted_buffer,
+ size_t encrypted_buffer_len);
// Called after a new SerialiedPacket is created to call the delegate's
// OnSerializedPacket and reset state.
@@ -551,7 +561,8 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// Frames to be added to the next SerializedPacket
QuicFrames queued_frames_;
- // packet_size should never be read directly, use PacketSize() instead.
+ // Serialization size of header + frames. If there is no queued frames,
+ // packet_size_ is 0.
// TODO(ianswett): Move packet_size_ into SerializedPacket once
// QuicEncryptedPacket has been flattened into SerializedPacket.
size_t packet_size_;
@@ -597,6 +608,17 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// accept. There is no limit for QUIC_CRYPTO connections, but QUIC+TLS
// negotiates this during the handshake.
QuicByteCount max_datagram_frame_size_;
+
+ const bool avoid_leak_writer_buffer_ =
+ GetQuicReloadableFlag(quic_avoid_leak_writer_buffer);
+
+ const bool fix_min_crypto_frame_size_ =
+ GetQuicReloadableFlag(quic_fix_min_crypto_frame_size);
+
+ // When true, this will override the padding generation code to disable it.
+ bool disable_padding_override_ = false;
+
+ bool update_packet_size_ = GetQuicReloadableFlag(quic_update_packet_size);
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc
index d1beea7c01d..394b82ec364 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc
@@ -162,7 +162,8 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> {
connection_id_.length()),
data_("foo"),
creator_(connection_id_, &client_framer_, &delegate_, &producer_) {
- EXPECT_CALL(delegate_, GetPacketBuffer()).WillRepeatedly(Return(nullptr));
+ EXPECT_CALL(delegate_, GetPacketBuffer())
+ .WillRepeatedly(Return(QuicPacketBuffer()));
creator_.SetEncrypter(ENCRYPTION_INITIAL, std::make_unique<NullEncrypter>(
Perspective::IS_CLIENT));
creator_.SetEncrypter(ENCRYPTION_HANDSHAKE, std::make_unique<NullEncrypter>(
@@ -930,40 +931,36 @@ TEST_P(QuicPacketCreatorTest, BuildPathResponsePacket3ResponsesPadded) {
}
TEST_P(QuicPacketCreatorTest, SerializeConnectivityProbingPacket) {
- for (int i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) {
- EncryptionLevel level = static_cast<EncryptionLevel>(i);
-
- creator_.set_encryption_level(level);
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
- std::unique_ptr<SerializedPacket> encrypted;
+ std::unique_ptr<SerializedPacket> encrypted;
+ if (VersionHasIetfQuicFrames(creator_.transport_version())) {
+ QuicPathFrameBuffer payload = {
+ {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}};
+ encrypted =
+ creator_.SerializePathChallengeConnectivityProbingPacket(&payload);
+ } else {
+ encrypted = creator_.SerializeConnectivityProbingPacket();
+ }
+ {
+ InSequence s;
+ EXPECT_CALL(framer_visitor_, OnPacket());
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+ EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+ EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
if (VersionHasIetfQuicFrames(creator_.transport_version())) {
- QuicPathFrameBuffer payload = {
- {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}};
- encrypted =
- creator_.SerializePathChallengeConnectivityProbingPacket(&payload);
+ EXPECT_CALL(framer_visitor_, OnPathChallengeFrame(_));
+ EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
} else {
- encrypted = creator_.SerializeConnectivityProbingPacket();
- }
- {
- InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket());
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
- EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
- EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
- if (VersionHasIetfQuicFrames(creator_.transport_version())) {
- EXPECT_CALL(framer_visitor_, OnPathChallengeFrame(_));
- EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
- } else {
- EXPECT_CALL(framer_visitor_, OnPingFrame(_));
- EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
- }
- EXPECT_CALL(framer_visitor_, OnPacketComplete());
+ EXPECT_CALL(framer_visitor_, OnPingFrame(_));
+ EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
}
- // QuicFramerPeer::SetPerspective(&client_framer_, Perspective::IS_SERVER);
- server_framer_.ProcessPacket(QuicEncryptedPacket(
- encrypted->encrypted_buffer, encrypted->encrypted_length));
+ EXPECT_CALL(framer_visitor_, OnPacketComplete());
}
+ // QuicFramerPeer::SetPerspective(&client_framer_, Perspective::IS_SERVER);
+ server_framer_.ProcessPacket(QuicEncryptedPacket(
+ encrypted->encrypted_buffer, encrypted->encrypted_length));
}
TEST_P(QuicPacketCreatorTest, SerializePathChallengeProbePacket) {
@@ -973,28 +970,24 @@ TEST_P(QuicPacketCreatorTest, SerializePathChallengeProbePacket) {
QuicPathFrameBuffer payload = {
{0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee}};
- for (int i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) {
- EncryptionLevel level = static_cast<EncryptionLevel>(i);
-
- creator_.set_encryption_level(level);
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
- std::unique_ptr<SerializedPacket> encrypted(
- creator_.SerializePathChallengeConnectivityProbingPacket(&payload));
- {
- InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket());
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
- EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
- EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
- EXPECT_CALL(framer_visitor_, OnPathChallengeFrame(_));
- EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
- EXPECT_CALL(framer_visitor_, OnPacketComplete());
- }
- // QuicFramerPeer::SetPerspective(&client_framer_, Perspective::IS_SERVER);
- server_framer_.ProcessPacket(QuicEncryptedPacket(
- encrypted->encrypted_buffer, encrypted->encrypted_length));
+ std::unique_ptr<SerializedPacket> encrypted(
+ creator_.SerializePathChallengeConnectivityProbingPacket(&payload));
+ {
+ InSequence s;
+ EXPECT_CALL(framer_visitor_, OnPacket());
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+ EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+ EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+ EXPECT_CALL(framer_visitor_, OnPathChallengeFrame(_));
+ EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
+ EXPECT_CALL(framer_visitor_, OnPacketComplete());
}
+ // QuicFramerPeer::SetPerspective(&client_framer_, Perspective::IS_SERVER);
+ server_framer_.ProcessPacket(QuicEncryptedPacket(
+ encrypted->encrypted_buffer, encrypted->encrypted_length));
}
TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket1PayloadPadded) {
@@ -1004,30 +997,26 @@ TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket1PayloadPadded) {
QuicPathFrameBuffer payload0 = {
{0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee}};
- for (int i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) {
- EncryptionLevel level = static_cast<EncryptionLevel>(i);
- creator_.set_encryption_level(level);
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
- QuicCircularDeque<QuicPathFrameBuffer> payloads;
- payloads.push_back(payload0);
+ QuicCircularDeque<QuicPathFrameBuffer> payloads;
+ payloads.push_back(payload0);
- std::unique_ptr<SerializedPacket> encrypted(
- creator_.SerializePathResponseConnectivityProbingPacket(payloads,
- true));
- {
- InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket());
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
- EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
- EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
- EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_));
- EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
- EXPECT_CALL(framer_visitor_, OnPacketComplete());
- }
- server_framer_.ProcessPacket(QuicEncryptedPacket(
- encrypted->encrypted_buffer, encrypted->encrypted_length));
+ std::unique_ptr<SerializedPacket> encrypted(
+ creator_.SerializePathResponseConnectivityProbingPacket(payloads, true));
+ {
+ InSequence s;
+ EXPECT_CALL(framer_visitor_, OnPacket());
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+ EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+ EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+ EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_));
+ EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
+ EXPECT_CALL(framer_visitor_, OnPacketComplete());
}
+ server_framer_.ProcessPacket(QuicEncryptedPacket(
+ encrypted->encrypted_buffer, encrypted->encrypted_length));
}
TEST_P(QuicPacketCreatorTest,
@@ -1038,29 +1027,25 @@ TEST_P(QuicPacketCreatorTest,
QuicPathFrameBuffer payload0 = {
{0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee}};
- for (int i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) {
- EncryptionLevel level = static_cast<EncryptionLevel>(i);
- creator_.set_encryption_level(level);
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
- QuicCircularDeque<QuicPathFrameBuffer> payloads;
- payloads.push_back(payload0);
+ QuicCircularDeque<QuicPathFrameBuffer> payloads;
+ payloads.push_back(payload0);
- std::unique_ptr<SerializedPacket> encrypted(
- creator_.SerializePathResponseConnectivityProbingPacket(payloads,
- false));
- {
- InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket());
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
- EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
- EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
- EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_));
- EXPECT_CALL(framer_visitor_, OnPacketComplete());
- }
- server_framer_.ProcessPacket(QuicEncryptedPacket(
- encrypted->encrypted_buffer, encrypted->encrypted_length));
+ std::unique_ptr<SerializedPacket> encrypted(
+ creator_.SerializePathResponseConnectivityProbingPacket(payloads, false));
+ {
+ InSequence s;
+ EXPECT_CALL(framer_visitor_, OnPacket());
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+ EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+ EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+ EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_));
+ EXPECT_CALL(framer_visitor_, OnPacketComplete());
}
+ server_framer_.ProcessPacket(QuicEncryptedPacket(
+ encrypted->encrypted_buffer, encrypted->encrypted_length));
}
TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket2PayloadsPadded) {
@@ -1072,31 +1057,27 @@ TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket2PayloadsPadded) {
QuicPathFrameBuffer payload1 = {
{0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee, 0xde}};
- for (int i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) {
- EncryptionLevel level = static_cast<EncryptionLevel>(i);
- creator_.set_encryption_level(level);
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
- QuicCircularDeque<QuicPathFrameBuffer> payloads;
- payloads.push_back(payload0);
- payloads.push_back(payload1);
+ QuicCircularDeque<QuicPathFrameBuffer> payloads;
+ payloads.push_back(payload0);
+ payloads.push_back(payload1);
- std::unique_ptr<SerializedPacket> encrypted(
- creator_.SerializePathResponseConnectivityProbingPacket(payloads,
- true));
- {
- InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket());
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
- EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
- EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
- EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(2);
- EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
- EXPECT_CALL(framer_visitor_, OnPacketComplete());
- }
- server_framer_.ProcessPacket(QuicEncryptedPacket(
- encrypted->encrypted_buffer, encrypted->encrypted_length));
+ std::unique_ptr<SerializedPacket> encrypted(
+ creator_.SerializePathResponseConnectivityProbingPacket(payloads, true));
+ {
+ InSequence s;
+ EXPECT_CALL(framer_visitor_, OnPacket());
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+ EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+ EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+ EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(2);
+ EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
+ EXPECT_CALL(framer_visitor_, OnPacketComplete());
}
+ server_framer_.ProcessPacket(QuicEncryptedPacket(
+ encrypted->encrypted_buffer, encrypted->encrypted_length));
}
TEST_P(QuicPacketCreatorTest,
@@ -1109,30 +1090,26 @@ TEST_P(QuicPacketCreatorTest,
QuicPathFrameBuffer payload1 = {
{0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee, 0xde}};
- for (int i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) {
- EncryptionLevel level = static_cast<EncryptionLevel>(i);
- creator_.set_encryption_level(level);
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
- QuicCircularDeque<QuicPathFrameBuffer> payloads;
- payloads.push_back(payload0);
- payloads.push_back(payload1);
+ QuicCircularDeque<QuicPathFrameBuffer> payloads;
+ payloads.push_back(payload0);
+ payloads.push_back(payload1);
- std::unique_ptr<SerializedPacket> encrypted(
- creator_.SerializePathResponseConnectivityProbingPacket(payloads,
- false));
- {
- InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket());
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
- EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
- EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
- EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(2);
- EXPECT_CALL(framer_visitor_, OnPacketComplete());
- }
- server_framer_.ProcessPacket(QuicEncryptedPacket(
- encrypted->encrypted_buffer, encrypted->encrypted_length));
+ std::unique_ptr<SerializedPacket> encrypted(
+ creator_.SerializePathResponseConnectivityProbingPacket(payloads, false));
+ {
+ InSequence s;
+ EXPECT_CALL(framer_visitor_, OnPacket());
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+ EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+ EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+ EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(2);
+ EXPECT_CALL(framer_visitor_, OnPacketComplete());
}
+ server_framer_.ProcessPacket(QuicEncryptedPacket(
+ encrypted->encrypted_buffer, encrypted->encrypted_length));
}
TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket3PayloadsPadded) {
@@ -1146,32 +1123,28 @@ TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket3PayloadsPadded) {
QuicPathFrameBuffer payload2 = {
{0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee, 0xde, 0xad}};
- for (int i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) {
- EncryptionLevel level = static_cast<EncryptionLevel>(i);
- creator_.set_encryption_level(level);
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
- QuicCircularDeque<QuicPathFrameBuffer> payloads;
- payloads.push_back(payload0);
- payloads.push_back(payload1);
- payloads.push_back(payload2);
+ QuicCircularDeque<QuicPathFrameBuffer> payloads;
+ payloads.push_back(payload0);
+ payloads.push_back(payload1);
+ payloads.push_back(payload2);
- std::unique_ptr<SerializedPacket> encrypted(
- creator_.SerializePathResponseConnectivityProbingPacket(payloads,
- true));
- {
- InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket());
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
- EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
- EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
- EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(3);
- EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
- EXPECT_CALL(framer_visitor_, OnPacketComplete());
- }
- server_framer_.ProcessPacket(QuicEncryptedPacket(
- encrypted->encrypted_buffer, encrypted->encrypted_length));
+ std::unique_ptr<SerializedPacket> encrypted(
+ creator_.SerializePathResponseConnectivityProbingPacket(payloads, true));
+ {
+ InSequence s;
+ EXPECT_CALL(framer_visitor_, OnPacket());
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+ EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+ EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+ EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(3);
+ EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
+ EXPECT_CALL(framer_visitor_, OnPacketComplete());
}
+ server_framer_.ProcessPacket(QuicEncryptedPacket(
+ encrypted->encrypted_buffer, encrypted->encrypted_length));
}
TEST_P(QuicPacketCreatorTest,
@@ -1186,30 +1159,26 @@ TEST_P(QuicPacketCreatorTest,
QuicPathFrameBuffer payload2 = {
{0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee, 0xde, 0xad}};
- for (int i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) {
- EncryptionLevel level = static_cast<EncryptionLevel>(i);
- creator_.set_encryption_level(level);
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
- QuicCircularDeque<QuicPathFrameBuffer> payloads;
- payloads.push_back(payload0);
- payloads.push_back(payload1);
- payloads.push_back(payload2);
+ QuicCircularDeque<QuicPathFrameBuffer> payloads;
+ payloads.push_back(payload0);
+ payloads.push_back(payload1);
+ payloads.push_back(payload2);
- std::unique_ptr<SerializedPacket> encrypted(
- creator_.SerializePathResponseConnectivityProbingPacket(payloads,
- false));
- InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket());
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
- EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
- EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
- EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(3);
- EXPECT_CALL(framer_visitor_, OnPacketComplete());
+ std::unique_ptr<SerializedPacket> encrypted(
+ creator_.SerializePathResponseConnectivityProbingPacket(payloads, false));
+ InSequence s;
+ EXPECT_CALL(framer_visitor_, OnPacket());
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+ EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+ EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+ EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(3);
+ EXPECT_CALL(framer_visitor_, OnPacketComplete());
- server_framer_.ProcessPacket(QuicEncryptedPacket(
- encrypted->encrypted_buffer, encrypted->encrypted_length));
- }
+ server_framer_.ProcessPacket(QuicEncryptedPacket(
+ encrypted->encrypted_buffer, encrypted->encrypted_length));
}
TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthLeastAwaiting) {
@@ -1499,6 +1468,7 @@ TEST_P(QuicPacketCreatorTest, AddFrameAndFlush) {
}
TEST_P(QuicPacketCreatorTest, SerializeAndSendStreamFrame) {
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
if (!GetParam().version_serialization) {
creator_.StopSendingVersion();
}
@@ -1534,6 +1504,7 @@ TEST_P(QuicPacketCreatorTest, SerializeStreamFrameWithPadding) {
// Regression test to check that CreateAndSerializeStreamFrame uses a
// correctly formatted stream frame header when appending padding.
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
if (!GetParam().version_serialization) {
creator_.StopSendingVersion();
}
@@ -1725,9 +1696,10 @@ TEST_P(QuicPacketCreatorTest, ConsumeDataAndRandomPadding) {
TEST_P(QuicPacketCreatorTest, FlushWithExternalBuffer) {
creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
- char external_buffer[kMaxOutgoingPacketSize];
- char* expected_buffer = external_buffer;
- EXPECT_CALL(delegate_, GetPacketBuffer()).WillOnce(Return(expected_buffer));
+ char* buffer = new char[kMaxOutgoingPacketSize];
+ QuicPacketBuffer external_buffer = {buffer,
+ [](const char* p) { delete[] p; }};
+ EXPECT_CALL(delegate_, GetPacketBuffer()).WillOnce(Return(external_buffer));
QuicFrame frame;
MakeIOVector("test", &iov_);
@@ -1738,10 +1710,13 @@ TEST_P(QuicPacketCreatorTest, FlushWithExternalBuffer) {
/*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame));
EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke([expected_buffer](SerializedPacket serialized_packet) {
- EXPECT_EQ(expected_buffer, serialized_packet.encrypted_buffer);
+ .WillOnce(Invoke([&external_buffer](SerializedPacket serialized_packet) {
+ EXPECT_EQ(external_buffer.buffer, serialized_packet.encrypted_buffer);
}));
creator_.FlushCurrentPacket();
+ if (!GetQuicReloadableFlag(quic_avoid_leak_writer_buffer)) {
+ delete[] buffer;
+ }
}
// Test for error found in
@@ -2311,7 +2286,7 @@ class MockDelegate : public QuicPacketCreator::DelegateInterface {
MaybeBundleAckOpportunistically,
(),
(override));
- MOCK_METHOD(char*, GetPacketBuffer, (), (override));
+ MOCK_METHOD(QuicPacketBuffer, GetPacketBuffer, (), (override));
MOCK_METHOD(void, OnSerializedPacket, (SerializedPacket), (override));
MOCK_METHOD(void,
OnUnrecoverableError,
@@ -2466,7 +2441,8 @@ class QuicPacketCreatorMultiplePacketsTest : public QuicTest {
&delegate_,
&producer_),
ack_frame_(InitAckFrame(1)) {
- EXPECT_CALL(delegate_, GetPacketBuffer()).WillRepeatedly(Return(nullptr));
+ EXPECT_CALL(delegate_, GetPacketBuffer())
+ .WillRepeatedly(Return(QuicPacketBuffer()));
creator_.SetEncrypter(
ENCRYPTION_FORWARD_SECURE,
std::make_unique<NullEncrypter>(Perspective::IS_CLIENT));
@@ -2679,6 +2655,37 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeCryptoData) {
CheckPacketContains(contents, 0);
}
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ ConsumeCryptoDataCheckShouldGeneratePacket) {
+ delegate_.SetCanNotWrite();
+
+ if (GetQuicReloadableFlag(quic_fix_checking_should_generate_packet)) {
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).Times(0);
+ } else {
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ }
+ std::string data = "crypto data";
+ size_t consumed_bytes =
+ creator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0);
+ creator_.Flush();
+ if (GetQuicReloadableFlag(quic_fix_checking_should_generate_packet)) {
+ EXPECT_EQ(0u, consumed_bytes);
+ } else {
+ EXPECT_EQ(data.length(), consumed_bytes);
+ }
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+ if (GetQuicReloadableFlag(quic_fix_checking_should_generate_packet)) {
+ return;
+ }
+ PacketContents contents;
+ contents.num_crypto_frames = 1;
+ contents.num_padding_frames = 1;
+ CheckPacketContains(contents, 0);
+}
+
TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeData_NotWritable) {
delegate_.SetCanNotWrite();
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer.h
index ab29e15aa88..6efdb6005d8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer.h
@@ -125,17 +125,22 @@ class QUIC_EXPORT_PRIVATE QuicPacketWriter {
// True=Batch mode. False=PassThrough mode.
virtual bool IsBatchMode() const = 0;
- // PassThrough mode: Return nullptr.
+ // PassThrough mode: Return {nullptr, nullptr}
//
// Batch mode:
- // Return the starting address for the next packet's data. A minimum of
+ // Return the QuicPacketBuffer for the next packet. A minimum of
// kMaxOutgoingPacketSize is guaranteed to be available from the returned
- // address. If the internal buffer does not have enough space, nullptr is
- // returned. All arguments should be identical to the follow-up call to
- // |WritePacket|, they are here to allow advanced packet memory management in
- // packet writers, e.g. one packet buffer pool per |peer_address|.
- virtual char* GetNextWriteLocation(const QuicIpAddress& self_address,
- const QuicSocketAddress& peer_address) = 0;
+ // address. If the internal buffer does not have enough space,
+ // {nullptr, nullptr} is returned. All arguments should be identical to the
+ // follow-up call to |WritePacket|, they are here to allow advanced packet
+ // memory management in packet writers, e.g. one packet buffer pool per
+ // |peer_address|.
+ //
+ // If QuicPacketBuffer.release_buffer is !nullptr, it should be called iff
+ // the caller does not call WritePacket for the returned buffer.
+ virtual QuicPacketBuffer GetNextWriteLocation(
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address) = 0;
// PassThrough mode: Return WriteResult(WRITE_STATUS_OK, 0).
//
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.cc
index f1f25d871bf..d2b54d1b175 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.cc
@@ -45,7 +45,7 @@ bool QuicPacketWriterWrapper::IsBatchMode() const {
return writer_->IsBatchMode();
}
-char* QuicPacketWriterWrapper::GetNextWriteLocation(
+QuicPacketBuffer QuicPacketWriterWrapper::GetNextWriteLocation(
const QuicIpAddress& self_address,
const QuicSocketAddress& peer_address) {
return writer_->GetNextWriteLocation(self_address, peer_address);
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h
index 0b331aec6f8..afd360580b4 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h
@@ -35,8 +35,9 @@ class QUIC_NO_EXPORT QuicPacketWriterWrapper : public QuicPacketWriter {
const QuicSocketAddress& peer_address) const override;
bool SupportsReleaseTime() const override;
bool IsBatchMode() const override;
- char* GetNextWriteLocation(const QuicIpAddress& self_address,
- const QuicSocketAddress& peer_address) override;
+ QuicPacketBuffer GetNextWriteLocation(
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address) override;
WriteResult Flush() override;
// Takes ownership of |writer|.
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packets.h b/chromium/net/third_party/quiche/src/quic/core/quic_packets.h
index 04522e8538b..3e37a200c21 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packets.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packets.h
@@ -379,6 +379,8 @@ struct QUIC_EXPORT_PRIVATE SerializedPacket {
SerializedPacket(SerializedPacket&& other);
~SerializedPacket();
+ // TODO(wub): replace |encrypted_buffer|+|release_encrypted_buffer| by a
+ // QuicOwnedPacketBuffer.
// Not owned if |release_encrypted_buffer| is nullptr. Otherwise it is
// released by |release_encrypted_buffer| on destruction.
const char* encrypted_buffer;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc
index 92401b0db72..43730135c14 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc
@@ -32,9 +32,6 @@ static const size_t kMaxRetransmissionsOnTimeout = 2;
// The path degrading delay is the sum of this number of consecutive RTO delays.
const size_t kNumRetransmissionDelaysForPathDegradingDelay = 2;
-// The blachkhole delay is the sum of this number of consecutive RTO delays.
-const size_t kNumRetransmissionDelaysForBlackholeDelay = 5;
-
// Ensure the handshake timer isnt't faster than 10ms.
// This limits the tenth retransmitted packet to 10s after the initial CHLO.
static const int64_t kMinHandshakeTimeoutMs = 10;
@@ -110,7 +107,8 @@ QuicSentPacketManager::QuicSentPacketManager(
one_rtt_packet_acked_(false),
one_rtt_packet_sent_(false),
first_pto_srtt_multiplier_(0),
- use_standard_deviation_for_pto_(false) {
+ use_standard_deviation_for_pto_(false),
+ pto_multiplier_without_rtt_samples_(3) {
SetSendAlgorithm(congestion_control_type);
if (pto_enabled_) {
QUIC_RELOADABLE_FLAG_COUNT_N(quic_default_on_pto, 1, 2);
@@ -200,6 +198,9 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) {
} else if (config.HasClientSentConnectionOption(kPLE2, perspective)) {
first_pto_srtt_multiplier_ = 1.5;
}
+ if (config.HasClientSentConnectionOption(kAPTO, perspective)) {
+ pto_multiplier_without_rtt_samples_ = 1.5;
+ }
if (config.HasClientSentConnectionOption(kPSDA, perspective)) {
use_standard_deviation_for_pto_ = true;
rtt_stats_.EnableStandardDeviationCalculation();
@@ -403,6 +404,17 @@ void QuicSentPacketManager::PostProcessNewlyAckedPackets(
}
}
}
+ // Records the max consecutive RTO or PTO before forward progress has been
+ // made.
+ if (consecutive_rto_count_ >
+ stats_->max_consecutive_rto_with_forward_progress) {
+ stats_->max_consecutive_rto_with_forward_progress =
+ consecutive_rto_count_;
+ } else if (consecutive_pto_count_ >
+ stats_->max_consecutive_rto_with_forward_progress) {
+ stats_->max_consecutive_rto_with_forward_progress =
+ consecutive_pto_count_;
+ }
// Reset all retransmit counters any time a new packet is acked.
consecutive_rto_count_ = 0;
consecutive_tlp_count_ = 0;
@@ -442,40 +454,27 @@ void QuicSentPacketManager::MaybeInvokeCongestionEvent(
}
}
-void QuicSentPacketManager::RetransmitUnackedPackets(
- TransmissionType retransmission_type) {
- DCHECK(retransmission_type == ALL_UNACKED_RETRANSMISSION ||
- retransmission_type == ALL_INITIAL_RETRANSMISSION);
+void QuicSentPacketManager::RetransmitZeroRttPackets() {
QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked();
for (QuicUnackedPacketMap::iterator it = unacked_packets_.begin();
it != unacked_packets_.end(); ++it, ++packet_number) {
- if ((retransmission_type == ALL_UNACKED_RETRANSMISSION ||
- it->encryption_level == ENCRYPTION_ZERO_RTT)) {
+ if (it->encryption_level == ENCRYPTION_ZERO_RTT) {
if (it->in_flight) {
// Remove 0-RTT packets and packets of the wrong version from flight,
// because neither can be processed by the peer.
unacked_packets_.RemoveFromInFlight(&*it);
}
if (unacked_packets_.HasRetransmittableFrames(*it)) {
- MarkForRetransmission(packet_number, retransmission_type);
+ MarkForRetransmission(packet_number, ALL_ZERO_RTT_RETRANSMISSION);
}
}
}
- if (retransmission_type == ALL_UNACKED_RETRANSMISSION &&
- unacked_packets_.bytes_in_flight() > 0) {
- QUIC_BUG << "RetransmitUnackedPackets should remove all packets from flight"
- << ", bytes_in_flight:" << unacked_packets_.bytes_in_flight();
- }
}
void QuicSentPacketManager::NeuterUnencryptedPackets() {
for (QuicPacketNumber packet_number :
unacked_packets_.NeuterUnencryptedPackets()) {
- if (avoid_overestimate_bandwidth_with_aggregation_) {
- QUIC_RELOADABLE_FLAG_COUNT_N(
- quic_avoid_overestimate_bandwidth_with_aggregation, 1, 4);
- send_algorithm_->OnPacketNeutered(packet_number);
- }
+ send_algorithm_->OnPacketNeutered(packet_number);
}
if (handshake_mode_disabled_) {
consecutive_pto_count_ = 0;
@@ -486,11 +485,7 @@ void QuicSentPacketManager::NeuterUnencryptedPackets() {
void QuicSentPacketManager::NeuterHandshakePackets() {
for (QuicPacketNumber packet_number :
unacked_packets_.NeuterHandshakePackets()) {
- if (avoid_overestimate_bandwidth_with_aggregation_) {
- QUIC_RELOADABLE_FLAG_COUNT_N(
- quic_avoid_overestimate_bandwidth_with_aggregation, 2, 4);
- send_algorithm_->OnPacketNeutered(packet_number);
- }
+ send_algorithm_->OnPacketNeutered(packet_number);
}
if (handshake_mode_disabled_) {
consecutive_pto_count_ = 0;
@@ -573,7 +568,7 @@ void QuicSentPacketManager::MarkForRetransmission(
QUIC_BUG_IF(transmission_type != LOSS_RETRANSMISSION &&
transmission_type != RTO_RETRANSMISSION &&
!unacked_packets_.HasRetransmittableFrames(*transmission_info))
- << "transmission_type: " << TransmissionTypeToString(transmission_type);
+ << "transmission_type: " << transmission_type;
// Handshake packets should never be sent as probing retransmissions.
DCHECK(!transmission_info->has_crypto_handshake ||
transmission_type != PROBING_RETRANSMISSION);
@@ -646,8 +641,7 @@ void QuicSentPacketManager::MarkPacketHandled(QuicPacketNumber packet_number,
// Record as a spurious retransmission if this packet is a
// retransmission and no new data gets acked.
QUIC_DVLOG(1) << "Detect spurious retransmitted packet " << packet_number
- << " transmission type: "
- << TransmissionTypeToString(info->transmission_type);
+ << " transmission type: " << info->transmission_type;
RecordOneSpuriousRetransmission(*info);
}
}
@@ -754,6 +748,9 @@ QuicSentPacketManager::OnRetransmissionTimeout() {
case PTO_MODE:
QUIC_DVLOG(1) << ENDPOINT << "PTO mode";
++stats_->pto_count;
+ if (handshake_mode_disabled_ && !ShouldArmPtoForApplicationData()) {
+ ++stats_->crypto_retransmit_count;
+ }
++consecutive_pto_count_;
pending_timer_transmission_count_ = max_probe_packets_per_pto_;
return PTO_MODE;
@@ -919,6 +916,26 @@ void QuicSentPacketManager::StartExponentialBackoffAfterNthPto(
pto_exponential_backoff_start_point_ = exponential_backoff_start_point;
}
+void QuicSentPacketManager::RetransmitDataOfSpaceIfAny(
+ PacketNumberSpace space) {
+ DCHECK(supports_multiple_packet_number_spaces());
+ if (!unacked_packets_.GetLastInFlightPacketSentTime(space).IsInitialized()) {
+ // No in flight data of space.
+ return;
+ }
+ QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked();
+ for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
+ it != unacked_packets_.end(); ++it, ++packet_number) {
+ if (it->state == OUTSTANDING &&
+ unacked_packets_.HasRetransmittableFrames(*it) &&
+ unacked_packets_.GetPacketNumberSpace(it->encryption_level) == space) {
+ DCHECK(it->in_flight);
+ MarkForRetransmission(packet_number, PTO_RETRANSMISSION);
+ return;
+ }
+ }
+}
+
QuicSentPacketManager::RetransmissionTimeoutMode
QuicSentPacketManager::GetRetransmissionMode() const {
DCHECK(unacked_packets_.HasInFlightPackets() ||
@@ -958,14 +975,16 @@ void QuicSentPacketManager::InvokeLossDetection(QuicTime time) {
detection_stats.sent_packets_max_sequence_reordering;
}
+ stats_->sent_packets_num_borderline_time_reorderings +=
+ detection_stats.sent_packets_num_borderline_time_reorderings;
+
+ stats_->total_loss_detection_response_time +=
+ detection_stats.total_loss_detection_response_time;
+
for (const LostPacket& packet : packets_lost_) {
QuicTransmissionInfo* info =
unacked_packets_.GetMutableTransmissionInfo(packet.packet_number);
++stats_->packets_lost;
- if (time > info->sent_time) {
- stats_->total_loss_detection_time =
- stats_->total_loss_detection_time + (time - info->sent_time);
- }
if (debug_delegate_ != nullptr) {
debug_delegate_->OnPacketLoss(packet.packet_number,
info->encryption_level, LOSS_RETRANSMISSION,
@@ -1041,6 +1060,16 @@ const QuicTime QuicSentPacketManager::GetRetransmissionTime() const {
// Do not set the timer if there is any credit left.
return QuicTime::Zero();
}
+ PacketNumberSpace packet_number_space;
+ if (GetQuicReloadableFlag(quic_fix_server_pto_timeout) &&
+ supports_multiple_packet_number_spaces() &&
+ unacked_packets_.perspective() == Perspective::IS_SERVER &&
+ !GetEarliestPacketSentTimeForPto(&packet_number_space).IsInitialized()) {
+ // Do not set the timer on the server side if the only in flight packets are
+ // half RTT data.
+ QUIC_RELOADABLE_FLAG_COUNT(quic_fix_server_pto_timeout);
+ return QuicTime::Zero();
+ }
switch (GetRetransmissionMode()) {
case HANDSHAKE_MODE:
return unacked_packets_.GetLastCryptoPacketSentTime() +
@@ -1131,9 +1160,10 @@ const QuicTime::Delta QuicSentPacketManager::GetPathDegradingDelay() const {
max_tail_loss_probes_ + kNumRetransmissionDelaysForPathDegradingDelay);
}
-const QuicTime::Delta QuicSentPacketManager::GetNetworkBlackholeDelay() const {
+const QuicTime::Delta QuicSentPacketManager::GetNetworkBlackholeDelay(
+ int8_t num_rtos_for_blackhole_detection) const {
return GetNConsecutiveRetransmissionTimeoutDelay(
- max_tail_loss_probes_ + kNumRetransmissionDelaysForBlackholeDelay);
+ max_tail_loss_probes_ + num_rtos_for_blackhole_detection);
}
const QuicTime::Delta QuicSentPacketManager::GetCryptoRetransmissionDelay()
@@ -1202,8 +1232,9 @@ const QuicTime::Delta QuicSentPacketManager::GetProbeTimeoutDelay() const {
if (rtt_stats_.smoothed_rtt().IsZero()) {
// Respect kMinHandshakeTimeoutMs to avoid a potential amplification attack.
QUIC_BUG_IF(rtt_stats_.initial_rtt().IsZero());
- return std::max(3 * rtt_stats_.initial_rtt(),
- QuicTime::Delta::FromMilliseconds(kMinHandshakeTimeoutMs)) *
+ return std::max(
+ pto_multiplier_without_rtt_samples_ * rtt_stats_.initial_rtt(),
+ QuicTime::Delta::FromMilliseconds(kMinHandshakeTimeoutMs)) *
(1 << consecutive_pto_count_);
}
const QuicTime::Delta rtt_var = use_standard_deviation_for_pto_
@@ -1354,8 +1385,7 @@ AckResult QuicSentPacketManager::OnAckFrameEnd(
<< ", least_unacked: " << unacked_packets_.GetLeastUnacked()
<< ", packets_acked_: " << packets_acked_;
} else {
- QUIC_PEER_BUG << "Received "
- << EncryptionLevelToString(ack_decrypted_level)
+ QUIC_PEER_BUG << "Received " << ack_decrypted_level
<< " ack for unackable packet: "
<< acked_packet.packet_number << " with state: "
<< QuicUtils::SentPacketStateToString(info->state);
@@ -1368,8 +1398,7 @@ AckResult QuicSentPacketManager::OnAckFrameEnd(
}
continue;
}
- QUIC_DVLOG(1) << ENDPOINT << "Got an "
- << EncryptionLevelToString(ack_decrypted_level)
+ QUIC_DVLOG(1) << ENDPOINT << "Got an " << ack_decrypted_level
<< " ack for packet " << acked_packet.packet_number
<< " , state: "
<< QuicUtils::SentPacketStateToString(info->state);
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h
index 371fa814537..72307b3b838 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h
@@ -140,15 +140,11 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
// TODO(fayang): Rename this function to OnHandshakeComplete.
void SetHandshakeConfirmed();
- // Requests retransmission of all unacked packets of |retransmission_type|.
- // The behavior of this method depends on the value of |retransmission_type|:
- // ALL_UNACKED_RETRANSMISSION - All unacked packets will be retransmitted.
- // This can happen, for example, after a version negotiation packet has been
- // received and all packets needs to be retransmitted with the new version.
- // ALL_INITIAL_RETRANSMISSION - Only initially encrypted packets will be
- // retransmitted. This can happen, for example, when a CHLO has been rejected
- // and the previously encrypted data needs to be encrypted with a new key.
- void RetransmitUnackedPackets(TransmissionType retransmission_type);
+ // Requests retransmission of all unacked 0-RTT packets.
+ // Only initially encrypted packets will be retransmitted. This can happen,
+ // for example, when a CHLO has been rejected and the previously encrypted
+ // data needs to be encrypted with a new key.
+ void RetransmitZeroRttPackets();
// Notify the sent packet manager of an external network measurement or
// prediction for either |bandwidth| or |rtt|; either can be empty.
@@ -216,7 +212,8 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
const QuicTime::Delta GetPathDegradingDelay() const;
// Returns the current delay for detecting network blackhole.
- const QuicTime::Delta GetNetworkBlackholeDelay() const;
+ const QuicTime::Delta GetNetworkBlackholeDelay(
+ int8_t num_rtos_for_blackhole_detection) const;
const RttStats* GetRttStats() const { return &rtt_stats_; }
@@ -397,6 +394,9 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
void StartExponentialBackoffAfterNthPto(
size_t exponential_backoff_start_point);
+ // Called to retransmit in flight packet of |space| if any.
+ void RetransmitDataOfSpaceIfAny(PacketNumberSpace space);
+
bool supports_multiple_packet_number_spaces() const {
return unacked_packets_.supports_multiple_packet_number_spaces();
}
@@ -411,6 +411,8 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
bool one_rtt_packet_acked() const { return one_rtt_packet_acked_; }
+ void OnUserAgentIdKnown() { loss_algorithm_->OnUserAgentIdKnown(); }
+
private:
friend class test::QuicConnectionPeer;
friend class test::QuicSentPacketManagerPeer;
@@ -657,8 +659,9 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
// calculating PTO timeout.
bool use_standard_deviation_for_pto_;
- const bool avoid_overestimate_bandwidth_with_aggregation_ =
- GetQuicReloadableFlag(quic_avoid_overestimate_bandwidth_with_aggregation);
+ // The multiplier for caculating PTO timeout before any RTT sample is
+ // available.
+ float pto_multiplier_without_rtt_samples_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc
index 79fc798568b..97d83f57933 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc
@@ -7,6 +7,7 @@
#include <memory>
#include <utility>
+#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h"
@@ -621,7 +622,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) {
// know packet 2 is a spurious until it gets acked.
EXPECT_EQ(1u, stats_.packets_spuriously_retransmitted);
EXPECT_EQ(1u, stats_.packets_lost);
- EXPECT_LT(QuicTime::Delta::Zero(), stats_.total_loss_detection_time);
+ EXPECT_LT(0.0, stats_.total_loss_detection_response_time);
EXPECT_LE(1u, stats_.sent_packets_max_sequence_reordering);
}
@@ -942,6 +943,7 @@ TEST_F(QuicSentPacketManagerTest, TailLossProbeThenRTO) {
manager_.OnRetransmissionTimeout();
EXPECT_EQ(2u, stats_.tlp_count);
EXPECT_EQ(1u, stats_.rto_count);
+ EXPECT_EQ(0u, stats_.max_consecutive_rto_with_forward_progress);
// There are 2 RTO retransmissions.
EXPECT_EQ(104 * kDefaultLength, manager_.GetBytesInFlight());
QuicPacketNumber largest_acked = QuicPacketNumber(103);
@@ -965,6 +967,7 @@ TEST_F(QuicSentPacketManagerTest, TailLossProbeThenRTO) {
// All packets before 103 should be lost.
// Packet 104 is still in flight.
EXPECT_EQ(1000u, manager_.GetBytesInFlight());
+ EXPECT_EQ(1u, stats_.max_consecutive_rto_with_forward_progress);
}
TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeout) {
@@ -1019,54 +1022,6 @@ TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeout) {
EXPECT_FALSE(manager_.HasUnackedCryptoPackets());
}
-TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeoutVersionNegotiation) {
- // Send 2 crypto packets and 3 data packets.
- const size_t kNumSentCryptoPackets = 2;
- for (size_t i = 1; i <= kNumSentCryptoPackets; ++i) {
- SendCryptoPacket(i);
- }
- const size_t kNumSentDataPackets = 3;
- for (size_t i = 1; i <= kNumSentDataPackets; ++i) {
- SendDataPacket(kNumSentCryptoPackets + i);
- }
- EXPECT_TRUE(manager_.HasUnackedCryptoPackets());
-
- EXPECT_CALL(notifier_, RetransmitFrames(_, _))
- .Times(2)
- .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(6); }))
- .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(7); }));
- manager_.OnRetransmissionTimeout();
- EXPECT_TRUE(manager_.HasUnackedCryptoPackets());
-
- // Now act like a version negotiation packet arrived, which would cause all
- // unacked packets to be retransmitted.
- // Mark packets [1, 7] lost. And the frames in 6 and 7 are same as packets 1
- // and 2, respectively.
- EXPECT_CALL(notifier_, OnFrameLost(_)).Times(7);
- manager_.RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION);
-
- // Ensure the first two pending packets are the crypto retransmits.
- RetransmitCryptoPacket(8);
- RetransmitCryptoPacket(9);
- RetransmitDataPacket(10, ALL_UNACKED_RETRANSMISSION);
- RetransmitDataPacket(11, ALL_UNACKED_RETRANSMISSION);
- RetransmitDataPacket(12, ALL_UNACKED_RETRANSMISSION);
-
- EXPECT_EQ(QuicPacketNumber(1u), manager_.GetLeastUnacked());
- // Least unacked isn't raised until an ack is received, so ack the
- // crypto packets.
- uint64_t acked[] = {8, 9};
- ExpectAcksAndLosses(true, acked, QUICHE_ARRAYSIZE(acked), nullptr, 0);
- manager_.OnAckFrameStart(QuicPacketNumber(9), QuicTime::Delta::Infinite(),
- clock_.Now());
- manager_.OnAckRange(QuicPacketNumber(8), QuicPacketNumber(10));
- EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
- ENCRYPTION_INITIAL));
- EXPECT_CALL(notifier_, HasUnackedCryptoData()).WillRepeatedly(Return(false));
- EXPECT_EQ(QuicPacketNumber(10u), manager_.GetLeastUnacked());
-}
-
TEST_F(QuicSentPacketManagerTest, CryptoHandshakeSpuriousRetransmission) {
// Send 1 crypto packet.
SendCryptoPacket(1);
@@ -1119,28 +1074,6 @@ TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeoutUnsentDataPacket) {
}
TEST_F(QuicSentPacketManagerTest,
- CryptoHandshakeRetransmissionThenRetransmitAll) {
- // Send 1 crypto packet.
- SendCryptoPacket(1);
-
- EXPECT_TRUE(manager_.HasUnackedCryptoPackets());
-
- // Retransmit the crypto packet as 2.
- EXPECT_CALL(notifier_, RetransmitFrames(_, _))
- .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(2); }));
- manager_.OnRetransmissionTimeout();
- // Now retransmit all the unacked packets, which occurs when there is a
- // version negotiation.
- EXPECT_CALL(notifier_, OnFrameLost(_)).Times(2);
- manager_.RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION);
- // Both packets 1 and 2 are unackable.
- EXPECT_FALSE(manager_.unacked_packets().IsUnacked(QuicPacketNumber(1)));
- EXPECT_FALSE(manager_.unacked_packets().IsUnacked(QuicPacketNumber(2)));
- EXPECT_TRUE(manager_.HasUnackedCryptoPackets());
- EXPECT_FALSE(manager_.HasInFlightPackets());
-}
-
-TEST_F(QuicSentPacketManagerTest,
CryptoHandshakeRetransmissionThenNeuterAndAck) {
// Send 1 crypto packet.
SendCryptoPacket(1);
@@ -2732,6 +2665,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeout) {
manager_.OnRetransmissionTimeout();
EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now()));
EXPECT_EQ(1u, stats_.pto_count);
+ EXPECT_EQ(0u, stats_.max_consecutive_rto_with_forward_progress);
// Verify two probe packets get sent.
EXPECT_CALL(notifier_, RetransmitFrames(_, _))
@@ -2765,6 +2699,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeout) {
// Verify PTO is correctly re-armed based on sent time of packet 4.
EXPECT_EQ(sent_time + expected_pto_delay, manager_.GetRetransmissionTime());
+ EXPECT_EQ(1u, stats_.max_consecutive_rto_with_forward_progress);
}
TEST_F(QuicSentPacketManagerTest, SendOneProbePacket) {
@@ -2811,7 +2746,7 @@ TEST_F(QuicSentPacketManagerTest, SendOneProbePacket) {
TEST_F(QuicSentPacketManagerTest, DisableHandshakeModeClient) {
QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT);
- manager_.EnableIetfPtoAndLossDetection();
+ manager_.EnableMultiplePacketNumberSpacesSupport();
// Send CHLO.
SendCryptoPacket(1);
EXPECT_NE(QuicTime::Zero(), manager_.GetRetransmissionTime());
@@ -3340,6 +3275,7 @@ TEST_F(QuicSentPacketManagerTest, ClientMultiplePacketNumberSpacePtoTimeout) {
manager_.OnRetransmissionTimeout();
EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now()));
EXPECT_EQ(1u, stats_.pto_count);
+ EXPECT_EQ(1u, stats_.crypto_retransmit_count);
// Verify probe packet gets sent.
EXPECT_CALL(notifier_, RetransmitFrames(_, _))
@@ -3823,11 +3759,7 @@ TEST_F(QuicSentPacketManagerTest, SetHandshakeConfirmed) {
return true;
}));
- if (GetQuicReloadableFlag(
- quic_avoid_overestimate_bandwidth_with_aggregation)) {
- EXPECT_CALL(*send_algorithm_, OnPacketNeutered(QuicPacketNumber(2)))
- .Times(1);
- }
+ EXPECT_CALL(*send_algorithm_, OnPacketNeutered(QuicPacketNumber(2))).Times(1);
manager_.SetHandshakeConfirmed();
}
@@ -3841,11 +3773,8 @@ TEST_F(QuicSentPacketManagerTest, NeuterUnencryptedPackets) {
.WillOnce(Return(false))
.WillOnce(Return(true));
EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
- if (GetQuicReloadableFlag(
- quic_avoid_overestimate_bandwidth_with_aggregation)) {
- EXPECT_CALL(*send_algorithm_, OnPacketNeutered(QuicPacketNumber(1)))
- .Times(1);
- }
+
+ EXPECT_CALL(*send_algorithm_, OnPacketNeutered(QuicPacketNumber(1))).Times(1);
manager_.NeuterUnencryptedPackets();
}
@@ -3911,7 +3840,7 @@ TEST_F(QuicSentPacketManagerTest, GetPathDegradingDelay) {
// Regression test for b/154050235.
TEST_F(QuicSentPacketManagerTest, ExponentialBackoffWithNoRttMeasurement) {
QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT);
- manager_.EnableIetfPtoAndLossDetection();
+ manager_.EnableMultiplePacketNumberSpacesSupport();
RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(kInitialRttMs),
rtt_stats->initial_rtt());
@@ -3939,7 +3868,7 @@ TEST_F(QuicSentPacketManagerTest, ExponentialBackoffWithNoRttMeasurement) {
}
TEST_F(QuicSentPacketManagerTest, PtoDelayWithTinyInitialRtt) {
- manager_.EnableIetfPtoAndLossDetection();
+ manager_.EnableMultiplePacketNumberSpacesSupport();
RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
// Assume client provided a tiny initial RTT.
rtt_stats->set_initial_rtt(QuicTime::Delta::FromMicroseconds(1));
@@ -3998,6 +3927,199 @@ TEST_F(QuicSentPacketManagerTest, HandshakeAckCausesInitialKeyDropping) {
manager_.MaybeSendProbePackets();
}
+// Regression test for b/156487311
+TEST_F(QuicSentPacketManagerTest, ClearLastInflightPacketsSentTime) {
+ manager_.EnableMultiplePacketNumberSpacesSupport();
+ EXPECT_CALL(*send_algorithm_, PacingRate(_))
+ .WillRepeatedly(Return(QuicBandwidth::Zero()));
+ EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
+ .WillRepeatedly(Return(10 * kDefaultTCPMSS));
+
+ // Send INITIAL 1.
+ SendDataPacket(1, ENCRYPTION_INITIAL);
+ const QuicTime packet1_sent_time = clock_.Now();
+ // Send HANDSHAKE 2.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
+ SendDataPacket(2, ENCRYPTION_HANDSHAKE);
+ SendDataPacket(3, ENCRYPTION_HANDSHAKE);
+ SendDataPacket(4, ENCRYPTION_HANDSHAKE);
+ const QuicTime packet2_sent_time = clock_.Now();
+
+ // Send half RTT 5.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
+ SendDataPacket(5, ENCRYPTION_FORWARD_SECURE);
+
+ // Received ACK for INITIAL 1.
+ ExpectAck(1);
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(90));
+ manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
+ int pto_rttvar_multiplier =
+ GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
+ const QuicTime::Delta pto_delay =
+ rtt_stats->smoothed_rtt() +
+ pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
+ if (GetQuicReloadableFlag(quic_fix_last_inflight_packets_sent_time)) {
+ // Verify PTO is armed based on handshake data.
+ EXPECT_EQ(packet2_sent_time + pto_delay, manager_.GetRetransmissionTime());
+ } else {
+ // Problematic: PTO is still armed based on initial data.
+ EXPECT_EQ(packet1_sent_time + pto_delay, manager_.GetRetransmissionTime());
+ clock_.AdvanceTime(pto_delay);
+ manager_.OnRetransmissionTimeout();
+ // Nothing to retransmit in INITIAL space.
+ EXPECT_CALL(notifier_, RetransmitFrames(_, _)).Times(0);
+ manager_.MaybeSendProbePackets();
+ // PING packet gets sent.
+ SendPingPacket(6, ENCRYPTION_INITIAL);
+ manager_.AdjustPendingTimerTransmissions();
+
+ // Verify PTO is armed based on packet 2.
+ EXPECT_EQ(packet2_sent_time + pto_delay * 2,
+ manager_.GetRetransmissionTime());
+ clock_.AdvanceTime(pto_delay * 2);
+ manager_.OnRetransmissionTimeout();
+ EXPECT_CALL(notifier_, RetransmitFrames(_, _)).Times(testing::AtLeast(1));
+ manager_.MaybeSendProbePackets();
+ }
+}
+
+// Regression test for b/157895910.
+TEST_F(QuicSentPacketManagerTest, EarliestSentTimeNotInitializedWhenPtoFires) {
+ SetQuicReloadableFlag(quic_fix_last_inflight_packets_sent_time, true);
+ manager_.EnableMultiplePacketNumberSpacesSupport();
+ EXPECT_CALL(*send_algorithm_, PacingRate(_))
+ .WillRepeatedly(Return(QuicBandwidth::Zero()));
+ EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
+ .WillRepeatedly(Return(10 * kDefaultTCPMSS));
+
+ // Send INITIAL 1.
+ SendDataPacket(1, ENCRYPTION_INITIAL);
+
+ // Send HANDSHAKE packets.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
+ SendDataPacket(2, ENCRYPTION_HANDSHAKE);
+ SendDataPacket(3, ENCRYPTION_HANDSHAKE);
+ SendDataPacket(4, ENCRYPTION_HANDSHAKE);
+
+ // Send half RTT packet.
+ SendDataPacket(5, ENCRYPTION_FORWARD_SECURE);
+
+ // Received ACK for INITIAL packet 1.
+ ExpectAck(1);
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(90));
+ manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
+
+ // Received ACK for HANDSHAKE packets.
+ uint64_t acked[] = {2, 3, 4};
+ ExpectAcksAndLosses(true, acked, QUICHE_ARRAYSIZE(acked), nullptr, 0);
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(90));
+ manager_.OnAckFrameStart(QuicPacketNumber(4), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(5));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(4),
+ ENCRYPTION_HANDSHAKE));
+ if (GetQuicReloadableFlag(quic_fix_server_pto_timeout)) {
+ // Verify PTO will not be armed.
+ EXPECT_EQ(QuicTime::Zero(), manager_.GetRetransmissionTime());
+ return;
+ }
+ // PTO fires but there is nothing to send.
+ EXPECT_NE(QuicTime::Zero(), manager_.GetRetransmissionTime());
+ manager_.OnRetransmissionTimeout();
+ EXPECT_QUIC_BUG(manager_.MaybeSendProbePackets(),
+ "earlist_sent_time not initialized when trying to send PTO "
+ "retransmissions");
+}
+
+TEST_F(QuicSentPacketManagerTest, MaybeRetransmitInitialData) {
+ manager_.EnableMultiplePacketNumberSpacesSupport();
+ EXPECT_CALL(*send_algorithm_, PacingRate(_))
+ .WillRepeatedly(Return(QuicBandwidth::Zero()));
+ EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
+ .WillRepeatedly(Return(10 * kDefaultTCPMSS));
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(100),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ QuicTime::Delta srtt = rtt_stats->smoothed_rtt();
+
+ // Send packet 1.
+ SendDataPacket(1, ENCRYPTION_INITIAL);
+ QuicTime packet1_sent_time = clock_.Now();
+
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
+ // Send packets 2 and 3.
+ SendDataPacket(2, ENCRYPTION_HANDSHAKE);
+ QuicTime packet2_sent_time = clock_.Now();
+ SendDataPacket(3, ENCRYPTION_HANDSHAKE);
+ // Verify PTO is correctly set based on packet 1.
+ int pto_rttvar_multiplier =
+ GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
+ QuicTime::Delta expected_pto_delay =
+ srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
+ EXPECT_EQ(packet1_sent_time + expected_pto_delay,
+ manager_.GetRetransmissionTime());
+
+ // Assume connection is going to send INITIAL ACK.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
+ EXPECT_CALL(notifier_, RetransmitFrames(_, _))
+ .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) {
+ RetransmitDataPacket(4, type, ENCRYPTION_INITIAL);
+ })));
+ manager_.RetransmitDataOfSpaceIfAny(INITIAL_DATA);
+ // Verify PTO is re-armed based on packet 2.
+ EXPECT_EQ(packet2_sent_time + expected_pto_delay,
+ manager_.GetRetransmissionTime());
+
+ // Connection is going to send another INITIAL ACK.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
+ EXPECT_CALL(notifier_, RetransmitFrames(_, _))
+ .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) {
+ RetransmitDataPacket(5, type, ENCRYPTION_INITIAL);
+ })));
+ manager_.RetransmitDataOfSpaceIfAny(INITIAL_DATA);
+ // Verify PTO does not change.
+ EXPECT_EQ(packet2_sent_time + expected_pto_delay,
+ manager_.GetRetransmissionTime());
+}
+
+TEST_F(QuicSentPacketManagerTest,
+ AggressivePtoBeforeAnyRttSamplesAreAvailable) {
+ manager_.EnableMultiplePacketNumberSpacesSupport();
+ EXPECT_CALL(*send_algorithm_, PacingRate(_))
+ .WillRepeatedly(Return(QuicBandwidth::Zero()));
+ EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
+ .WillRepeatedly(Return(10 * kDefaultTCPMSS));
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
+
+ QuicConfig config;
+ QuicTagVector options;
+ options.push_back(kAPTO);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ manager_.SetFromConfig(config);
+
+ // Send INITIAL 1.
+ SendDataPacket(1, ENCRYPTION_INITIAL);
+ // Verify retransmission timeout is expected.
+ EXPECT_EQ(clock_.Now() + 1.5 * rtt_stats->initial_rtt(),
+ manager_.GetRetransmissionTime());
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session.cc b/chromium/net/third_party/quiche/src/quic/core/quic_session.cc
index 0f00ff3843d..59e6cc8093e 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_session.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_session.cc
@@ -73,12 +73,9 @@ QuicSession::QuicSession(
config_.GetMaxBidirectionalStreamsToSend(),
config_.GetMaxUnidirectionalStreamsToSend() +
num_expected_unidirectional_static_streams),
- num_dynamic_incoming_streams_(0),
- num_draining_incoming_streams_(0),
- num_draining_outgoing_streams_(0),
- num_outgoing_static_streams_(0),
- num_incoming_static_streams_(0),
- num_locally_closed_incoming_streams_highest_offset_(0),
+ num_draining_streams_(0),
+ num_outgoing_draining_streams_(0),
+ num_static_streams_(0),
flow_controller_(
this,
QuicUtils::GetInvalidStreamId(connection->transport_version()),
@@ -101,10 +98,9 @@ QuicSession::QuicSession(
use_http2_priority_write_scheduler_(false),
is_configured_(false),
enable_round_robin_scheduling_(false),
- deprecate_draining_streams_(
- GetQuicReloadableFlag(quic_deprecate_draining_streams)),
- break_close_loop_(
- GetQuicReloadableFlag(quic_break_session_stream_close_loop)) {
+ was_zero_rtt_rejected_(false),
+ fix_gquic_stream_type_(
+ GetQuicReloadableFlag(quic_fix_gquic_stream_type)) {
closed_streams_clean_up_alarm_ =
QuicWrapUnique<QuicAlarm>(connection_->alarm_factory()->CreateAlarm(
new ClosedStreamsCleanUpDelegate(this)));
@@ -117,9 +113,6 @@ QuicSession::QuicSession(
config_.GetMaxUnidirectionalStreamsToSend() +
num_expected_unidirectional_static_streams);
}
- if (break_close_loop_) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_break_session_stream_close_loop);
- }
}
void QuicSession::Initialize() {
@@ -127,7 +120,11 @@ void QuicSession::Initialize() {
connection_->SetSessionNotifier(this);
connection_->SetDataProducer(this);
connection_->SetFromConfig(config_);
-
+ if (GetQuicReloadableFlag(quic_support_handshake_done_in_t050) &&
+ version().UsesTls() && !version().HasHandshakeDone() &&
+ perspective_ == Perspective::IS_CLIENT) {
+ config_.SetSupportHandshakeDone();
+ }
// On the server side, version negotiation has been done by the dispatcher,
// and the server session is created with the right version.
if (perspective() == Perspective::IS_SERVER) {
@@ -144,16 +141,6 @@ void QuicSession::Initialize() {
QuicSession::~QuicSession() {
QUIC_LOG_IF(WARNING, !zombie_streams_.empty()) << "Still have zombie streams";
- QUIC_LOG_IF(WARNING, num_locally_closed_incoming_streams_highest_offset() >
- stream_id_manager_.max_open_incoming_streams())
- << "Surprisingly high number of locally closed peer initiated streams"
- "still waiting for final byte offset: "
- << num_locally_closed_incoming_streams_highest_offset();
- QUIC_LOG_IF(WARNING, GetNumLocallyClosedOutgoingStreamsHighestOffset() >
- stream_id_manager_.max_open_outgoing_streams())
- << "Surprisingly high number of locally closed self initiated streams"
- "still waiting for final byte offset: "
- << GetNumLocallyClosedOutgoingStreamsHighestOffset();
}
void QuicSession::PendingStreamOnStreamFrame(const QuicStreamFrame& frame) {
@@ -197,8 +184,8 @@ void QuicSession::OnStreamFrame(const QuicStreamFrame& frame) {
if (UsesPendingStreams() &&
QuicUtils::GetStreamType(stream_id, perspective(),
- IsIncomingStream(stream_id)) ==
- READ_UNIDIRECTIONAL &&
+ IsIncomingStream(stream_id),
+ version()) == READ_UNIDIRECTIONAL &&
stream_map_.find(stream_id) == stream_map_.end()) {
PendingStreamOnStreamFrame(frame);
return;
@@ -245,8 +232,8 @@ void QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) {
// If stream_id is READ_UNIDIRECTIONAL, close the connection.
if (QuicUtils::GetStreamType(stream_id, perspective(),
- IsIncomingStream(stream_id)) ==
- READ_UNIDIRECTIONAL) {
+ IsIncomingStream(stream_id),
+ version()) == READ_UNIDIRECTIONAL) {
QUIC_DVLOG(1) << ENDPOINT
<< "Received STOP_SENDING for a read-only stream_id: "
<< stream_id << ".";
@@ -311,7 +298,7 @@ void QuicSession::PendingStreamOnRstStream(const QuicRstStreamFrame& frame) {
// Pending stream is currently read only. We can safely close the stream.
DCHECK_EQ(READ_UNIDIRECTIONAL,
QuicUtils::GetStreamType(pending->id(), perspective(),
- /*peer_initiated = */ true));
+ /*peer_initiated = */ true, version()));
ClosePendingStream(stream_id);
}
@@ -326,8 +313,8 @@ void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) {
if (VersionHasIetfQuicFrames(transport_version()) &&
QuicUtils::GetStreamType(stream_id, perspective(),
- IsIncomingStream(stream_id)) ==
- WRITE_UNIDIRECTIONAL) {
+ IsIncomingStream(stream_id),
+ version()) == WRITE_UNIDIRECTIONAL) {
connection()->CloseConnection(
QUIC_INVALID_STREAM_ID, "Received RESET_STREAM for a write-only stream",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
@@ -340,8 +327,8 @@ void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) {
if (UsesPendingStreams() &&
QuicUtils::GetStreamType(stream_id, perspective(),
- IsIncomingStream(stream_id)) ==
- READ_UNIDIRECTIONAL &&
+ IsIncomingStream(stream_id),
+ version()) == READ_UNIDIRECTIONAL &&
stream_map_.find(stream_id) == stream_map_.end()) {
PendingStreamOnRstStream(frame);
return;
@@ -398,10 +385,7 @@ void QuicSession::OnConnectionClosed(const QuicConnectionCloseFrame& frame,
on_closed_frame_ = frame;
}
- if (GetQuicReloadableFlag(quic_notify_handshaker_on_connection_close)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_notify_handshaker_on_connection_close);
- GetMutableCryptoStream()->OnConnectionClosed(frame.quic_error_code, source);
- }
+ GetMutableCryptoStream()->OnConnectionClosed(frame.quic_error_code, source);
// Copy all non static streams in a new map for the ease of deleting.
QuicSmallMap<QuicStreamId, QuicStream*, 10> non_static_streams;
@@ -460,12 +444,12 @@ void QuicSession::OnPacketReceived(const QuicSocketAddress& /*self_address*/,
void QuicSession::OnPathDegrading() {}
+void QuicSession::OnForwardProgressMadeAfterPathDegrading() {}
+
bool QuicSession::AllowSelfAddressChange() const {
return false;
}
-void QuicSession::OnForwardProgressConfirmed() {}
-
void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
// Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't
// assume that it still exists.
@@ -483,8 +467,8 @@ void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
if (VersionHasIetfQuicFrames(transport_version()) &&
QuicUtils::GetStreamType(stream_id, perspective(),
- IsIncomingStream(stream_id)) ==
- READ_UNIDIRECTIONAL) {
+ IsIncomingStream(stream_id),
+ version()) == READ_UNIDIRECTIONAL) {
connection()->CloseConnection(
QUIC_WINDOW_UPDATE_RECEIVED_ON_READ_UNIDIRECTIONAL_STREAM,
"WindowUpdateFrame received on READ_UNIDIRECTIONAL stream.",
@@ -619,7 +603,7 @@ void QuicSession::OnCanWrite() {
ConnectionCloseBehavior::SILENT_CLOSE);
return;
}
- if (!connection_->CanWriteStreamData()) {
+ if (!CanWriteStreamData()) {
return;
}
currently_writing_stream_id_ = write_blocked_streams_.PopFront();
@@ -663,11 +647,26 @@ bool QuicSession::WillingAndAbleToWrite() const {
HasPendingHandshake()) {
return true;
}
- return control_frame_manager_.WillingToWrite() ||
- !streams_with_pending_retransmission_.empty() ||
- write_blocked_streams_.HasWriteBlockedSpecialStream() ||
- (!flow_controller_.IsBlocked() &&
- write_blocked_streams_.HasWriteBlockedDataStreams());
+ if (control_frame_manager_.WillingToWrite() ||
+ !streams_with_pending_retransmission_.empty()) {
+ return true;
+ }
+ if (!GetQuicReloadableFlag(quic_fix_willing_and_able_to_write)) {
+ return write_blocked_streams_.HasWriteBlockedSpecialStream() ||
+ (!flow_controller_.IsBlocked() &&
+ write_blocked_streams_.HasWriteBlockedDataStreams());
+ }
+ QUIC_RELOADABLE_FLAG_COUNT(quic_fix_willing_and_able_to_write);
+ if (flow_controller_.IsBlocked()) {
+ if (VersionUsesHttp3(transport_version())) {
+ return false;
+ }
+ // Crypto and headers streams are not blocked by connection level flow
+ // control.
+ return write_blocked_streams_.HasWriteBlockedSpecialStream();
+ }
+ return write_blocked_streams_.HasWriteBlockedSpecialStream() ||
+ write_blocked_streams_.HasWriteBlockedDataStreams();
}
bool QuicSession::HasPendingHandshake() const {
@@ -681,12 +680,6 @@ bool QuicSession::HasPendingHandshake() const {
QuicUtils::GetCryptoStreamId(transport_version()));
}
-uint64_t QuicSession::GetNumOpenDynamicStreams() const {
- return stream_map_.size() - GetNumDrainingStreams() +
- locally_closed_streams_highest_offset_.size() -
- num_incoming_static_streams_ - num_outgoing_static_streams_;
-}
-
void QuicSession::ProcessUdpPacket(const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address,
const QuicReceivedPacket& packet) {
@@ -763,22 +756,11 @@ void QuicSession::SendRstStream(QuicStreamId id,
connection_->OnStreamReset(id, error);
}
-
- if (break_close_loop_) {
- return;
- }
-
- if (error != QUIC_STREAM_NO_ERROR && QuicContainsKey(zombie_streams_, id)) {
- OnStreamDoneWaitingForAcks(id);
- return;
- }
- CloseStreamInner(id, true);
}
void QuicSession::ResetStream(QuicStreamId id,
QuicRstStreamErrorCode error,
QuicStreamOffset bytes_written) {
- DCHECK(break_close_loop_);
QuicStream* stream = GetStream(id);
if (stream != nullptr && stream->is_static()) {
connection()->CloseConnection(
@@ -800,8 +782,8 @@ void QuicSession::MaybeSendRstStreamFrame(QuicStreamId id,
QuicStreamOffset bytes_written) {
DCHECK(connection()->connected());
if (!VersionHasIetfQuicFrames(transport_version()) ||
- QuicUtils::GetStreamType(id, perspective(), IsIncomingStream(id)) !=
- READ_UNIDIRECTIONAL) {
+ QuicUtils::GetStreamType(id, perspective(), IsIncomingStream(id),
+ version()) != READ_UNIDIRECTIONAL) {
control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
}
}
@@ -810,8 +792,8 @@ void QuicSession::MaybeSendStopSendingFrame(QuicStreamId id,
QuicRstStreamErrorCode error) {
DCHECK(connection()->connected());
if (VersionHasIetfQuicFrames(transport_version()) &&
- QuicUtils::GetStreamType(id, perspective(), IsIncomingStream(id)) !=
- WRITE_UNIDIRECTIONAL) {
+ QuicUtils::GetStreamType(id, perspective(), IsIncomingStream(id),
+ version()) != WRITE_UNIDIRECTIONAL) {
control_frame_manager_.WriteOrBufferStopSending(error, id);
}
}
@@ -854,24 +836,11 @@ void QuicSession::SendMaxStreams(QuicStreamCount stream_count,
}
void QuicSession::CloseStream(QuicStreamId stream_id) {
- CloseStreamInner(stream_id, false);
-}
-
-void QuicSession::InsertLocallyClosedStreamsHighestOffset(
- const QuicStreamId id,
- QuicStreamOffset offset) {
- locally_closed_streams_highest_offset_[id] = offset;
- if (IsIncomingStream(id)) {
- ++num_locally_closed_incoming_streams_highest_offset_;
- }
-}
-
-void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool rst_sent) {
QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
StreamMap::iterator it = stream_map_.find(stream_id);
if (it == stream_map_.end()) {
- // When CloseStreamInner has been called recursively (via
+ // When CloseStream has been called recursively (via
// QuicStream::OnClose), the stream will already have been deleted
// from stream_map_, so return immediately.
QUIC_DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id;
@@ -887,89 +856,18 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool rst_sent) {
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return;
}
- if (break_close_loop_) {
- stream->CloseReadSide();
- stream->CloseWriteSide();
- return;
- }
- StreamType type = stream->type();
-
- // Tell the stream that a RST has been sent.
- if (rst_sent) {
- stream->set_rst_sent(true);
- }
-
- if (stream->IsWaitingForAcks()) {
- zombie_streams_[stream->id()] = std::move(it->second);
- } else {
- // Clean up the stream since it is no longer waiting for acks.
- streams_waiting_for_acks_.erase(stream->id());
- closed_streams_.push_back(std::move(it->second));
- // Do not retransmit data of a closed stream.
- streams_with_pending_retransmission_.erase(stream_id);
- if (!closed_streams_clean_up_alarm_->IsSet()) {
- closed_streams_clean_up_alarm_->Set(
- connection_->clock()->ApproximateNow());
- }
- }
-
- // If we haven't received a FIN or RST for this stream, we need to keep track
- // of the how many bytes the stream's flow controller believes it has
- // received, for accurate connection level flow control accounting.
- const bool had_fin_or_rst = stream->HasReceivedFinalOffset();
- if (!had_fin_or_rst) {
- InsertLocallyClosedStreamsHighestOffset(
- stream_id, stream->flow_controller()->highest_received_byte_offset());
- }
- bool stream_was_draining = false;
- if (deprecate_draining_streams_) {
- stream_was_draining = stream->was_draining();
- QUIC_DVLOG_IF(1, stream_was_draining)
- << ENDPOINT << "Stream " << stream_id << " was draining";
- }
- stream_map_.erase(it);
- if (IsIncomingStream(stream_id)) {
- --num_dynamic_incoming_streams_;
- }
- if (!deprecate_draining_streams_) {
- stream_was_draining =
- draining_streams_.find(stream_id) != draining_streams_.end();
- }
- if (stream_was_draining) {
- if (IsIncomingStream(stream_id)) {
- QUIC_BUG_IF(num_draining_incoming_streams_ == 0);
- --num_draining_incoming_streams_;
- } else if (deprecate_draining_streams_) {
- QUIC_BUG_IF(num_draining_outgoing_streams_ == 0);
- --num_draining_outgoing_streams_;
- }
- draining_streams_.erase(stream_id);
- } else if (VersionHasIetfQuicFrames(transport_version())) {
- // Stream was not draining, but we did have a fin or rst, so we can now
- // free the stream ID if version 99.
- if (had_fin_or_rst && connection_->connected()) {
- // Do not bother informing stream ID manager if connection is closed.
- v99_streamid_manager_.OnStreamClosed(stream_id);
- }
- } else if (stream_id_manager_.handles_accounting() && had_fin_or_rst &&
- connection_->connected()) {
- stream_id_manager_.OnStreamClosed(
- /*is_incoming=*/IsIncomingStream(stream_id));
- }
-
- stream->OnClose();
+ stream->CloseReadSide();
+ stream->CloseWriteSide();
+}
- if (!stream_was_draining && !IsIncomingStream(stream_id) && had_fin_or_rst &&
- !VersionHasIetfQuicFrames(transport_version())) {
- // Streams that first became draining already called OnCanCreate...
- // This covers the case where the stream went directly to being closed.
- OnCanCreateNewOutgoingStream(type != BIDIRECTIONAL);
- }
+void QuicSession::InsertLocallyClosedStreamsHighestOffset(
+ const QuicStreamId id,
+ QuicStreamOffset offset) {
+ locally_closed_streams_highest_offset_[id] = offset;
}
void QuicSession::OnStreamClosed(QuicStreamId stream_id) {
QUIC_DVLOG(1) << ENDPOINT << "Closing stream: " << stream_id;
- DCHECK(break_close_loop_);
StreamMap::iterator it = stream_map_.find(stream_id);
if (it == stream_map_.end()) {
QUIC_DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id;
@@ -1002,48 +900,38 @@ void QuicSession::OnStreamClosed(QuicStreamId stream_id) {
InsertLocallyClosedStreamsHighestOffset(
stream_id, stream->flow_controller()->highest_received_byte_offset());
stream_map_.erase(it);
- if (IsIncomingStream(stream_id)) {
- --num_dynamic_incoming_streams_;
- }
return;
}
- bool stream_was_draining = false;
- if (deprecate_draining_streams_) {
- stream_was_draining = stream->was_draining();
- QUIC_DVLOG_IF(1, stream_was_draining)
- << ENDPOINT << "Stream " << stream_id << " was draining";
- }
+ const bool stream_was_draining = stream->was_draining();
+ QUIC_DVLOG_IF(1, stream_was_draining)
+ << ENDPOINT << "Stream " << stream_id << " was draining";
stream_map_.erase(it);
- if (IsIncomingStream(stream_id)) {
- --num_dynamic_incoming_streams_;
- }
- if (!deprecate_draining_streams_) {
- stream_was_draining =
- draining_streams_.find(stream_id) != draining_streams_.end();
- }
if (stream_was_draining) {
- if (IsIncomingStream(stream_id)) {
- QUIC_BUG_IF(num_draining_incoming_streams_ == 0);
- --num_draining_incoming_streams_;
- } else if (deprecate_draining_streams_) {
- QUIC_BUG_IF(num_draining_outgoing_streams_ == 0);
- --num_draining_outgoing_streams_;
+ QUIC_BUG_IF(num_draining_streams_ == 0);
+ --num_draining_streams_;
+ if (!IsIncomingStream(stream_id)) {
+ QUIC_BUG_IF(num_outgoing_draining_streams_ == 0);
+ --num_outgoing_draining_streams_;
}
- draining_streams_.erase(stream_id);
// Stream Id manager has been informed with draining streams.
return;
}
- if (!connection_->connected()) {
+ if (!GetQuicReloadableFlag(quic_notify_stream_id_manager_when_disconnected) &&
+ !connection_->connected()) {
// Do not bother informing stream ID manager if connection has been
// disconnected.
return;
}
- if (stream_id_manager_.handles_accounting() &&
- !VersionHasIetfQuicFrames(transport_version())) {
+ if (!VersionHasIetfQuicFrames(transport_version())) {
stream_id_manager_.OnStreamClosed(
/*is_incoming=*/IsIncomingStream(stream_id));
}
+ if (GetQuicReloadableFlag(quic_notify_stream_id_manager_when_disconnected) &&
+ !connection_->connected()) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_notify_stream_id_manager_when_disconnected);
+ return;
+ }
if (IsIncomingStream(stream_id)) {
// Stream Id manager is only interested in peer initiated stream IDs.
if (VersionHasIetfQuicFrames(transport_version())) {
@@ -1090,13 +978,11 @@ void QuicSession::OnFinalByteOffsetReceived(
flow_controller_.AddBytesConsumed(offset_diff);
locally_closed_streams_highest_offset_.erase(it);
- if (stream_id_manager_.handles_accounting() &&
- !VersionHasIetfQuicFrames(transport_version())) {
+ if (!VersionHasIetfQuicFrames(transport_version())) {
stream_id_manager_.OnStreamClosed(
/*is_incoming=*/IsIncomingStream(stream_id));
}
if (IsIncomingStream(stream_id)) {
- --num_locally_closed_incoming_streams_highest_offset_;
if (VersionHasIetfQuicFrames(transport_version())) {
v99_streamid_manager_.OnStreamClosed(stream_id);
}
@@ -1120,6 +1006,21 @@ bool QuicSession::OneRttKeysAvailable() const {
}
void QuicSession::OnConfigNegotiated() {
+ // In versions with TLS, the configs will be set twice if 0-RTT is available.
+ // In the second config setting, 1-RTT keys are guaranteed to be available.
+ if (GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls) &&
+ version().UsesTls() && is_configured_ &&
+ connection_->encryption_level() != ENCRYPTION_FORWARD_SECURE) {
+ QUIC_BUG
+ << ENDPOINT
+ << "1-RTT keys missing when config is negotiated for the second time.";
+ connection_->CloseConnection(
+ QUIC_INTERNAL_ERROR,
+ "1-RTT keys missing when config is negotiated for the second time.",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+
QUIC_DVLOG(1) << ENDPOINT << "OnConfigNegotiated";
connection_->SetFromConfig(config_);
@@ -1128,6 +1029,19 @@ void QuicSession::OnConfigNegotiated() {
if (config_.HasReceivedMaxBidirectionalStreams()) {
max_streams = config_.ReceivedMaxBidirectionalStreams();
}
+ if (was_zero_rtt_rejected_ &&
+ max_streams <
+ v99_streamid_manager_.outgoing_bidirectional_stream_count()) {
+ connection_->CloseConnection(
+ QUIC_ZERO_RTT_UNRETRANSMITTABLE,
+ quiche::QuicheStrCat(
+ "Server rejected 0-RTT, aborting because new bidirectional "
+ "initial stream limit ",
+ max_streams, " is less than current open streams: ",
+ v99_streamid_manager_.outgoing_bidirectional_stream_count()),
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
QUIC_DVLOG(1) << ENDPOINT
<< "Setting Bidirectional outgoing_max_streams_ to "
<< max_streams;
@@ -1135,8 +1049,12 @@ void QuicSession::OnConfigNegotiated() {
max_streams <
v99_streamid_manager_.max_outgoing_bidirectional_streams()) {
connection_->CloseConnection(
- QUIC_MAX_STREAMS_ERROR,
+ was_zero_rtt_rejected_ ? QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED
+ : QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED,
quiche::QuicheStrCat(
+ was_zero_rtt_rejected_
+ ? "Server rejected 0-RTT, aborting because "
+ : "",
"new bidirectional limit ", max_streams,
" decreases the current limit: ",
v99_streamid_manager_.max_outgoing_bidirectional_streams()),
@@ -1152,11 +1070,30 @@ void QuicSession::OnConfigNegotiated() {
if (config_.HasReceivedMaxUnidirectionalStreams()) {
max_streams = config_.ReceivedMaxUnidirectionalStreams();
}
+
+ if (was_zero_rtt_rejected_ &&
+ max_streams <
+ v99_streamid_manager_.outgoing_unidirectional_stream_count()) {
+ connection_->CloseConnection(
+ QUIC_ZERO_RTT_UNRETRANSMITTABLE,
+ quiche::QuicheStrCat(
+ "Server rejected 0-RTT, aborting because new unidirectional "
+ "initial stream limit ",
+ max_streams, " is less than current open streams: ",
+ v99_streamid_manager_.outgoing_unidirectional_stream_count()),
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+
if (max_streams <
v99_streamid_manager_.max_outgoing_unidirectional_streams()) {
connection_->CloseConnection(
- QUIC_MAX_STREAMS_ERROR,
+ was_zero_rtt_rejected_ ? QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED
+ : QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED,
quiche::QuicheStrCat(
+ was_zero_rtt_rejected_
+ ? "Server rejected 0-RTT, aborting because "
+ : "",
"new unidirectional limit ", max_streams,
" decreases the current limit: ",
v99_streamid_manager_.max_outgoing_unidirectional_streams()),
@@ -1177,6 +1114,17 @@ void QuicSession::OnConfigNegotiated() {
}
QUIC_DVLOG(1) << ENDPOINT << "Setting max_open_outgoing_streams_ to "
<< max_streams;
+ if (was_zero_rtt_rejected_ &&
+ max_streams < stream_id_manager_.num_open_outgoing_streams()) {
+ connection_->CloseConnection(
+ QUIC_INTERNAL_ERROR,
+ quiche::QuicheStrCat(
+ "Server rejected 0-RTT, aborting because new stream limit ",
+ max_streams, " is less than current open streams: ",
+ stream_id_manager_.num_open_outgoing_streams()),
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
stream_id_manager_.set_max_open_outgoing_streams(max_streams);
}
@@ -1271,11 +1219,16 @@ void QuicSession::OnConfigNegotiated() {
OnNewSessionFlowControlWindow(
config_.ReceivedInitialSessionFlowControlWindowBytes());
}
+
is_configured_ = true;
connection()->OnConfigNegotiated();
// Ask flow controllers to try again since the config could have unblocked us.
- if (connection_->version().AllowsLowFlowControlLimits()) {
+ // Or if this session is configured on TLS enabled QUIC versions,
+ // attempt to retransmit 0-RTT data if there's any.
+ if (connection_->version().AllowsLowFlowControlLimits() ||
+ (GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls) &&
+ version().UsesTls())) {
OnCanWrite();
}
}
@@ -1373,8 +1326,15 @@ void QuicSession::OnNewStreamUnidirectionalFlowControlWindow(
// Inform all existing outgoing unidirectional streams about the new window.
for (auto const& kv : stream_map_) {
const QuicStreamId id = kv.first;
- if (QuicUtils::IsBidirectionalStreamId(id)) {
- continue;
+ if (fix_gquic_stream_type_ && !version().HasIetfQuicFrames()) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_gquic_stream_type, 1, 3);
+ if (kv.second->type() == BIDIRECTIONAL) {
+ continue;
+ }
+ } else {
+ if (QuicUtils::IsBidirectionalStreamId(id, version())) {
+ continue;
+ }
}
if (!QuicUtils::IsOutgoingStreamId(connection_->version(), id,
perspective())) {
@@ -1382,6 +1342,9 @@ void QuicSession::OnNewStreamUnidirectionalFlowControlWindow(
}
QUIC_DVLOG(1) << ENDPOINT << "Informing unidirectional stream " << id
<< " of new stream flow control window " << new_window;
+ if (!ValidateStreamFlowControlLimit(new_window, kv.second.get())) {
+ return;
+ }
if (!kv.second->ConfigSendWindowOffset(new_window)) {
return;
}
@@ -1397,8 +1360,15 @@ void QuicSession::OnNewStreamOutgoingBidirectionalFlowControlWindow(
// Inform all existing outgoing bidirectional streams about the new window.
for (auto const& kv : stream_map_) {
const QuicStreamId id = kv.first;
- if (!QuicUtils::IsBidirectionalStreamId(id)) {
- continue;
+ if (fix_gquic_stream_type_ && !version().HasIetfQuicFrames()) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_gquic_stream_type, 2, 3);
+ if (kv.second->type() != BIDIRECTIONAL) {
+ continue;
+ }
+ } else {
+ if (!QuicUtils::IsBidirectionalStreamId(id, version())) {
+ continue;
+ }
}
if (!QuicUtils::IsOutgoingStreamId(connection_->version(), id,
perspective())) {
@@ -1406,6 +1376,9 @@ void QuicSession::OnNewStreamOutgoingBidirectionalFlowControlWindow(
}
QUIC_DVLOG(1) << ENDPOINT << "Informing outgoing bidirectional stream "
<< id << " of new stream flow control window " << new_window;
+ if (!ValidateStreamFlowControlLimit(new_window, kv.second.get())) {
+ return;
+ }
if (!kv.second->ConfigSendWindowOffset(new_window)) {
return;
}
@@ -1421,8 +1394,15 @@ void QuicSession::OnNewStreamIncomingBidirectionalFlowControlWindow(
// Inform all existing incoming bidirectional streams about the new window.
for (auto const& kv : stream_map_) {
const QuicStreamId id = kv.first;
- if (!QuicUtils::IsBidirectionalStreamId(id)) {
- continue;
+ if (fix_gquic_stream_type_ && !version().HasIetfQuicFrames()) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_gquic_stream_type, 3, 3);
+ if (kv.second->type() != BIDIRECTIONAL) {
+ continue;
+ }
+ } else {
+ if (!QuicUtils::IsBidirectionalStreamId(id, version())) {
+ continue;
+ }
}
if (QuicUtils::IsOutgoingStreamId(connection_->version(), id,
perspective())) {
@@ -1430,39 +1410,92 @@ void QuicSession::OnNewStreamIncomingBidirectionalFlowControlWindow(
}
QUIC_DVLOG(1) << ENDPOINT << "Informing incoming bidirectional stream "
<< id << " of new stream flow control window " << new_window;
+ if (!ValidateStreamFlowControlLimit(new_window, kv.second.get())) {
+ return;
+ }
if (!kv.second->ConfigSendWindowOffset(new_window)) {
return;
}
}
}
+bool QuicSession::ValidateStreamFlowControlLimit(QuicStreamOffset new_window,
+ const QuicStream* stream) {
+ if (was_zero_rtt_rejected_ &&
+ new_window < stream->flow_controller()->bytes_sent()) {
+ QUIC_BUG_IF(perspective() == Perspective::IS_SERVER)
+ << "Server should never receive configs twice.";
+ connection_->CloseConnection(
+ QUIC_ZERO_RTT_UNRETRANSMITTABLE,
+ quiche::QuicheStrCat(
+ "Server rejected 0-RTT, aborting because new stream max data ",
+ new_window, " for stream ", stream->id(),
+ " is less than currently used: ",
+ stream->flow_controller()->bytes_sent()),
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+
+ if (version().AllowsLowFlowControlLimits() &&
+ new_window < stream->flow_controller()->send_window_offset()) {
+ QUIC_BUG_IF(perspective() == Perspective::IS_SERVER)
+ << "Server should never receive configs twice.";
+ connection_->CloseConnection(
+ was_zero_rtt_rejected_ ? QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED
+ : QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED,
+ quiche::QuicheStrCat(
+ was_zero_rtt_rejected_ ? "Server rejected 0-RTT, aborting because "
+ : "",
+ "new stream max data ", new_window, " decreases current limit: ",
+ stream->flow_controller()->send_window_offset()),
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+ return true;
+}
+
void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) {
QUIC_DVLOG(1) << ENDPOINT << "OnNewSessionFlowControlWindow " << new_window;
- bool close_connection = false;
- if (!connection_->version().AllowsLowFlowControlLimits()) {
- if (new_window < kMinimumFlowControlSendWindow) {
- close_connection = true;
- QUIC_LOG_FIRST_N(ERROR, 1)
- << "Peer sent us an invalid session flow control send window: "
- << new_window << ", below default: " << kMinimumFlowControlSendWindow;
- }
- } else if (perspective_ == Perspective::IS_CLIENT &&
- new_window < flow_controller_.send_window_offset()) {
- // The client receives a lower limit than remembered, violating
- // https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-7.3.1
- QUIC_LOG_FIRST_N(ERROR, 1)
- << "Peer sent us an invalid session flow control send window: "
- << new_window
- << ", below current: " << flow_controller_.send_window_offset();
- close_connection = true;
+
+ if (was_zero_rtt_rejected_ && new_window < flow_controller_.bytes_sent()) {
+ std::string error_details = quiche::QuicheStrCat(
+ "Server rejected 0-RTT. Aborting because the client received session "
+ "flow control send window: ",
+ new_window,
+ ", which is below currently used: ", flow_controller_.bytes_sent());
+ QUIC_LOG(ERROR) << error_details;
+ connection_->CloseConnection(
+ QUIC_ZERO_RTT_UNRETRANSMITTABLE, error_details,
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
}
- if (close_connection) {
+ if (!connection_->version().AllowsLowFlowControlLimits() &&
+ new_window < kMinimumFlowControlSendWindow) {
+ std::string error_details = quiche::QuicheStrCat(
+ "Peer sent us an invalid session flow control send window: ",
+ new_window, ", below minimum: ", kMinimumFlowControlSendWindow);
+ QUIC_LOG_FIRST_N(ERROR, 1) << error_details;
connection_->CloseConnection(
- QUIC_FLOW_CONTROL_INVALID_WINDOW,
- quiche::QuicheStrCat("New connection window too low: ", new_window),
+ QUIC_FLOW_CONTROL_INVALID_WINDOW, error_details,
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return;
}
+ if (perspective_ == Perspective::IS_CLIENT &&
+ new_window < flow_controller_.send_window_offset()) {
+ // The client receives a lower limit than remembered, violating
+ // https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-7.3.1
+ std::string error_details = quiche::QuicheStrCat(
+ was_zero_rtt_rejected_ ? "Server rejected 0-RTT, aborting because "
+ : "",
+ "new session max data ", new_window,
+ " decreases current limit: ", flow_controller_.send_window_offset());
+ QUIC_LOG(ERROR) << error_details;
+ connection_->CloseConnection(
+ was_zero_rtt_rejected_ ? QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED
+ : QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED,
+ error_details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
flow_controller_.UpdateSendWindowOffset(new_window);
}
@@ -1497,31 +1530,17 @@ void QuicSession::OnNewEncryptionKeyAvailable(
EncryptionLevel level,
std::unique_ptr<QuicEncrypter> encrypter) {
connection()->SetEncrypter(level, std::move(encrypter));
-
- if (connection_->version().handshake_protocol == PROTOCOL_TLS1_3 &&
- (perspective() == Perspective::IS_CLIENT ||
- GetQuicReloadableFlag(quic_change_default_encryption_level))) {
- QUIC_DVLOG(1) << ENDPOINT << "Set default encryption level to "
- << EncryptionLevelToString(level);
- QUIC_RELOADABLE_FLAG_COUNT(quic_change_default_encryption_level);
- connection()->SetDefaultEncryptionLevel(level);
+ if (connection_->version().handshake_protocol != PROTOCOL_TLS1_3) {
return;
}
- if (connection_->version().handshake_protocol == PROTOCOL_TLS1_3 &&
- level == ENCRYPTION_FORWARD_SECURE) {
- // Set connection's default encryption level once 1-RTT write key is
- // available.
- QUIC_DVLOG(1) << ENDPOINT << "Set default encryption level to "
- << EncryptionLevelToString(level);
- connection()->SetDefaultEncryptionLevel(level);
- }
+ QUIC_DVLOG(1) << ENDPOINT << "Set default encryption level to " << level;
+ connection()->SetDefaultEncryptionLevel(level);
}
void QuicSession::SetDefaultEncryptionLevel(EncryptionLevel level) {
DCHECK_EQ(PROTOCOL_QUIC_CRYPTO, connection_->version().handshake_protocol);
- QUIC_DVLOG(1) << ENDPOINT << "Set default encryption level to "
- << EncryptionLevelToString(level);
+ QUIC_DVLOG(1) << ENDPOINT << "Set default encryption level to " << level;
connection()->SetDefaultEncryptionLevel(level);
switch (level) {
@@ -1531,7 +1550,7 @@ void QuicSession::SetDefaultEncryptionLevel(EncryptionLevel level) {
if (perspective() == Perspective::IS_CLIENT) {
// Retransmit old 0-RTT data (if any) with the new 0-RTT keys, since
// they can't be decrypted by the server.
- connection_->RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION);
+ connection_->RetransmitZeroRttPackets();
// Given any streams blocked by encryption a chance to write.
OnCanWrite();
}
@@ -1541,13 +1560,9 @@ void QuicSession::SetDefaultEncryptionLevel(EncryptionLevel level) {
case ENCRYPTION_FORWARD_SECURE:
QUIC_BUG_IF(!config_.negotiated())
<< ENDPOINT << "Handshake confirmed without parameter negotiation.";
- if (!GetQuicReloadableFlag(quic_bw_sampler_app_limited_starting_value)) {
- connection_->ResetHasNonAppLimitedSampleAfterHandshakeCompletion();
- }
break;
default:
- QUIC_BUG << "Unknown encryption level: "
- << EncryptionLevelToString(level);
+ QUIC_BUG << "Unknown encryption level: " << level;
}
}
@@ -1557,15 +1572,17 @@ void QuicSession::OnOneRttKeysAvailable() {
<< ENDPOINT << "Handshake completes without cipher suite negotiation.";
QUIC_BUG_IF(!config_.negotiated())
<< ENDPOINT << "Handshake completes without parameter negotiation.";
- if (connection()->version().HasHandshakeDone() &&
+ if ((connection()->version().HasHandshakeDone() ||
+ (GetQuicReloadableFlag(quic_support_handshake_done_in_t050) &&
+ config_.PeerSupportsHandshakeDone())) &&
perspective_ == Perspective::IS_SERVER) {
+ if (!connection()->version().HasHandshakeDone()) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_support_handshake_done_in_t050);
+ }
// Server sends HANDSHAKE_DONE to signal confirmation of the handshake
// to the client.
control_frame_manager_.WriteOrBufferHandshakeDone();
}
- if (!GetQuicReloadableFlag(quic_bw_sampler_app_limited_starting_value)) {
- connection_->ResetHasNonAppLimitedSampleAfterHandshakeCompletion();
- }
}
void QuicSession::DiscardOldDecryptionKey(EncryptionLevel level) {
@@ -1576,8 +1593,7 @@ void QuicSession::DiscardOldDecryptionKey(EncryptionLevel level) {
}
void QuicSession::DiscardOldEncryptionKey(EncryptionLevel level) {
- QUIC_DVLOG(1) << ENDPOINT << "Discard keys of "
- << EncryptionLevelToString(level);
+ QUIC_DVLOG(1) << ENDPOINT << "Discard keys of " << level;
if (connection()->version().handshake_protocol == PROTOCOL_TLS1_3) {
connection()->RemoveEncrypter(level);
}
@@ -1594,8 +1610,7 @@ void QuicSession::DiscardOldEncryptionKey(EncryptionLevel level) {
QUIC_BUG << "Tries to drop 1-RTT keys";
break;
default:
- QUIC_BUG << "Unknown encryption level: "
- << EncryptionLevelToString(level);
+ QUIC_BUG << "Unknown encryption level: " << level;
}
}
@@ -1603,6 +1618,46 @@ void QuicSession::NeuterHandshakeData() {
connection()->OnHandshakeComplete();
}
+void QuicSession::OnZeroRttRejected() {
+ was_zero_rtt_rejected_ = true;
+ connection_->RetransmitZeroRttPackets();
+ if (connection_->encryption_level() == ENCRYPTION_FORWARD_SECURE) {
+ QUIC_BUG << "1-RTT keys already available when 0-RTT is rejected.";
+ connection_->CloseConnection(
+ QUIC_INTERNAL_ERROR,
+ "1-RTT keys already available when 0-RTT is rejected.",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ }
+}
+
+bool QuicSession::FillTransportParameters(TransportParameters* params) {
+ if (version().AuthenticatesHandshakeConnectionIds()) {
+ if (perspective() == Perspective::IS_SERVER) {
+ config_.SetOriginalConnectionIdToSend(
+ connection_->GetOriginalDestinationConnectionId());
+ config_.SetInitialSourceConnectionIdToSend(connection_->connection_id());
+ } else {
+ config_.SetInitialSourceConnectionIdToSend(
+ connection_->client_connection_id());
+ }
+ }
+ return config_.FillTransportParameters(params);
+}
+
+QuicErrorCode QuicSession::ProcessTransportParameters(
+ const TransportParameters& params,
+ bool is_resumption,
+ std::string* error_details) {
+ HelloType hello_type;
+ if (perspective_ == Perspective::IS_CLIENT) {
+ hello_type = SERVER;
+ } else {
+ hello_type = CLIENT;
+ }
+ return config_.ProcessTransportParameters(params, hello_type, is_resumption,
+ error_details);
+}
+
void QuicSession::OnCryptoHandshakeMessageSent(
const CryptoHandshakeMessage& /*message*/) {}
@@ -1648,14 +1703,11 @@ void QuicSession::ActivateStream(std::unique_ptr<QuicStream> stream) {
<< ". activating stream " << stream_id;
DCHECK(!QuicContainsKey(stream_map_, stream_id));
stream_map_[stream_id] = std::move(stream);
- if (IsIncomingStream(stream_id)) {
- is_static ? ++num_incoming_static_streams_
- : ++num_dynamic_incoming_streams_;
- } else if (is_static) {
- ++num_outgoing_static_streams_;
+ if (is_static) {
+ ++num_static_streams_;
+ return;
}
- if (stream_id_manager_.handles_accounting() && !is_static &&
- !VersionHasIetfQuicFrames(transport_version())) {
+ if (!VersionHasIetfQuicFrames(transport_version())) {
// Do not inform stream ID manager of static streams.
stream_id_manager_.ActivateStream(
/*is_incoming=*/IsIncomingStream(stream_id));
@@ -1678,8 +1730,7 @@ QuicStreamId QuicSession::GetNextOutgoingUnidirectionalStreamId() {
bool QuicSession::CanOpenNextOutgoingBidirectionalStream() {
if (!VersionHasIetfQuicFrames(transport_version())) {
- return stream_id_manager_.CanOpenNextOutgoingStream(
- GetNumOpenOutgoingStreams());
+ return stream_id_manager_.CanOpenNextOutgoingStream();
}
if (v99_streamid_manager_.CanOpenNextOutgoingBidirectionalStream()) {
return true;
@@ -1695,8 +1746,7 @@ bool QuicSession::CanOpenNextOutgoingBidirectionalStream() {
bool QuicSession::CanOpenNextOutgoingUnidirectionalStream() {
if (!VersionHasIetfQuicFrames(transport_version())) {
- return stream_id_manager_.CanOpenNextOutgoingStream(
- GetNumOpenOutgoingStreams());
+ return stream_id_manager_.CanOpenNextOutgoingStream();
}
if (v99_streamid_manager_.CanOpenNextOutgoingUnidirectionalStream()) {
return true;
@@ -1745,19 +1795,11 @@ QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) {
return nullptr;
}
- if (!VersionHasIetfQuicFrames(transport_version())) {
- // TODO(fayang): Let LegacyQuicStreamIdManager count open streams and make
- // CanOpenIncomingStream interface consistent with that of v99.
- if (!stream_id_manager_.CanOpenIncomingStream(
- GetNumOpenIncomingStreams())) {
- // Refuse to open the stream.
- if (break_close_loop_) {
- ResetStream(stream_id, QUIC_REFUSED_STREAM, 0);
- } else {
- SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0);
- }
- return nullptr;
- }
+ if (!VersionHasIetfQuicFrames(transport_version()) &&
+ !stream_id_manager_.CanOpenIncomingStream()) {
+ // Refuse to open the stream.
+ ResetStream(stream_id, QUIC_REFUSED_STREAM, 0);
+ return nullptr;
}
return CreateIncomingStream(stream_id);
@@ -1765,48 +1807,17 @@ QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) {
void QuicSession::StreamDraining(QuicStreamId stream_id, bool unidirectional) {
DCHECK(QuicContainsKey(stream_map_, stream_id));
- if (deprecate_draining_streams_) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_deprecate_draining_streams);
- QUIC_DVLOG(1) << ENDPOINT << "Stream " << stream_id << " is draining";
- if (VersionHasIetfQuicFrames(transport_version())) {
- v99_streamid_manager_.OnStreamClosed(stream_id);
- } else if (stream_id_manager_.handles_accounting()) {
- stream_id_manager_.OnStreamClosed(
- /*is_incoming=*/IsIncomingStream(stream_id));
- }
- if (IsIncomingStream(stream_id)) {
- ++num_draining_incoming_streams_;
- return;
- }
- ++num_draining_outgoing_streams_;
- OnCanCreateNewOutgoingStream(unidirectional);
- return;
- }
- if (!QuicContainsKey(draining_streams_, stream_id)) {
- draining_streams_.insert(stream_id);
- if (IsIncomingStream(stream_id)) {
- ++num_draining_incoming_streams_;
- }
- if (VersionHasIetfQuicFrames(transport_version())) {
- v99_streamid_manager_.OnStreamClosed(stream_id);
- } else if (stream_id_manager_.handles_accounting()) {
- stream_id_manager_.OnStreamClosed(
- /*is_incoming=*/IsIncomingStream(stream_id));
- }
+ QUIC_DVLOG(1) << ENDPOINT << "Stream " << stream_id << " is draining";
+ if (VersionHasIetfQuicFrames(transport_version())) {
+ v99_streamid_manager_.OnStreamClosed(stream_id);
+ } else {
+ stream_id_manager_.OnStreamClosed(
+ /*is_incoming=*/IsIncomingStream(stream_id));
}
+ ++num_draining_streams_;
if (!IsIncomingStream(stream_id)) {
- // Inform application that a stream is available.
- if (VersionHasIetfQuicFrames(transport_version())) {
- OnCanCreateNewOutgoingStream(
- !QuicUtils::IsBidirectionalStreamId(stream_id));
- } else {
- QuicStream* stream = GetStream(stream_id);
- if (!stream) {
- QUIC_BUG << "Stream doesn't exist when draining.";
- return;
- }
- OnCanCreateNewOutgoingStream(stream->type() != BIDIRECTIONAL);
- }
+ ++num_outgoing_draining_streams_;
+ OnCanCreateNewOutgoingStream(unidirectional);
}
}
@@ -1924,46 +1935,15 @@ bool QuicSession::IsStaticStream(QuicStreamId id) const {
return it->second->is_static();
}
-size_t QuicSession::GetNumOpenIncomingStreams() const {
- DCHECK(!VersionHasIetfQuicFrames(transport_version()));
- if (stream_id_manager_.handles_accounting()) {
- return stream_id_manager_.num_open_incoming_streams();
- }
- return num_dynamic_incoming_streams_ - num_draining_incoming_streams_ +
- num_locally_closed_incoming_streams_highest_offset_;
-}
-
-size_t QuicSession::GetNumOpenOutgoingStreams() const {
- DCHECK(!VersionHasIetfQuicFrames(transport_version()));
- if (stream_id_manager_.handles_accounting()) {
- return stream_id_manager_.num_open_outgoing_streams();
- }
- DCHECK_GE(GetNumDynamicOutgoingStreams() +
- GetNumLocallyClosedOutgoingStreamsHighestOffset(),
- GetNumDrainingOutgoingStreams());
- return GetNumDynamicOutgoingStreams() +
- GetNumLocallyClosedOutgoingStreamsHighestOffset() -
- GetNumDrainingOutgoingStreams();
-}
-
size_t QuicSession::GetNumActiveStreams() const {
- if (!VersionHasIetfQuicFrames(transport_version()) &&
- stream_id_manager_.handles_accounting()) {
+ if (!VersionHasIetfQuicFrames(transport_version())) {
// Exclude locally_closed_streams when determine whether to keep connection
// alive.
return stream_id_manager_.num_open_incoming_streams() +
stream_id_manager_.num_open_outgoing_streams() -
locally_closed_streams_highest_offset_.size();
}
- return stream_map_.size() - GetNumDrainingStreams() -
- num_incoming_static_streams_ - num_outgoing_static_streams_;
-}
-
-size_t QuicSession::GetNumDrainingStreams() const {
- if (deprecate_draining_streams_) {
- return num_draining_incoming_streams_ + num_draining_outgoing_streams_;
- }
- return draining_streams_.size();
+ return stream_map_.size() - num_draining_streams_ - num_static_streams_;
}
void QuicSession::MarkConnectionLevelWriteBlocked(QuicStreamId id) {
@@ -1994,31 +1974,6 @@ void QuicSession::SendPing() {
control_frame_manager_.WritePing();
}
-size_t QuicSession::GetNumDynamicOutgoingStreams() const {
- DCHECK_GE(
- static_cast<size_t>(stream_map_.size() + pending_stream_map_.size()),
- num_dynamic_incoming_streams_ + num_outgoing_static_streams_ +
- num_incoming_static_streams_);
- return stream_map_.size() + pending_stream_map_.size() -
- num_dynamic_incoming_streams_ - num_outgoing_static_streams_ -
- num_incoming_static_streams_;
-}
-
-size_t QuicSession::GetNumDrainingOutgoingStreams() const {
- if (deprecate_draining_streams_) {
- return num_draining_outgoing_streams_;
- }
- DCHECK_GE(draining_streams_.size(), num_draining_incoming_streams_);
- return draining_streams_.size() - num_draining_incoming_streams_;
-}
-
-size_t QuicSession::GetNumLocallyClosedOutgoingStreamsHighestOffset() const {
- DCHECK_GE(locally_closed_streams_highest_offset_.size(),
- num_locally_closed_incoming_streams_highest_offset_);
- return locally_closed_streams_highest_offset_.size() -
- num_locally_closed_incoming_streams_highest_offset_;
-}
-
bool QuicSession::IsConnectionFlowControlBlocked() const {
return flow_controller_.IsBlocked();
}
@@ -2273,6 +2228,18 @@ QuicUint128 QuicSession::GetStatelessResetToken() const {
return QuicUtils::GenerateStatelessResetToken(connection_->connection_id());
}
+bool QuicSession::CanWriteStreamData() const {
+ // Don't write stream data if there are queued data packets.
+ if (connection_->HasQueuedPackets()) {
+ return false;
+ }
+ // Immediately write handshake data.
+ if (HasPendingHandshake()) {
+ return true;
+ }
+ return connection_->CanWrite(HAS_RETRANSMITTABLE_DATA);
+}
+
bool QuicSession::RetransmitLostData() {
QuicConnection::ScopedPacketFlusher retransmission_flusher(connection_);
// Retransmit crypto data first.
@@ -2305,7 +2272,7 @@ bool QuicSession::RetransmitLostData() {
}
}
while (!streams_with_pending_retransmission_.empty()) {
- if (!connection_->CanWriteStreamData()) {
+ if (!CanWriteStreamData()) {
break;
}
// Retransmit lost data on headers and data streams.
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session.h b/chromium/net/third_party/quiche/src/quic/core/quic_session.h
index 5a1ebbc602c..9233402d4ea 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_session.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_session.h
@@ -33,6 +33,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
namespace quic {
@@ -110,17 +111,21 @@ class QUIC_EXPORT_PRIVATE QuicSession
bool is_connectivity_probe) override;
void OnCanWrite() override;
bool SendProbingData() override;
+ bool ValidateStatelessReset(
+ const quic::QuicSocketAddress& /*self_address*/,
+ const quic::QuicSocketAddress& /*peer_address*/) override {
+ return true;
+ }
void OnCongestionWindowChange(QuicTime /*now*/) override {}
void OnConnectionMigration(AddressChangeType /*type*/) override {}
// Adds a connection level WINDOW_UPDATE frame.
void OnAckNeedsRetransmittableFrame() override;
void SendPing() override;
bool WillingAndAbleToWrite() const override;
- bool HasPendingHandshake() const override;
void OnPathDegrading() override;
+ void OnForwardProgressMadeAfterPathDegrading() override;
bool AllowSelfAddressChange() const override;
HandshakeState GetHandshakeState() const override;
- void OnForwardProgressConfirmed() override;
bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override;
bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override;
void OnStopSendingFrame(const QuicStopSendingFrame& frame) override;
@@ -255,6 +260,11 @@ class QUIC_EXPORT_PRIVATE QuicSession
void DiscardOldEncryptionKey(EncryptionLevel level) override;
void NeuterUnencryptedData() override;
void NeuterHandshakeData() override;
+ void OnZeroRttRejected() override;
+ bool FillTransportParameters(TransportParameters* params) override;
+ QuicErrorCode ProcessTransportParameters(const TransportParameters& params,
+ bool is_resumption,
+ std::string* error_details) override;
// Implement StreamDelegateInterface.
void OnStreamError(QuicErrorCode error_code,
@@ -322,33 +332,6 @@ class QUIC_EXPORT_PRIVATE QuicSession
// never counting unfinished streams.
size_t GetNumActiveStreams() const;
- // Returns the number of currently draining streams.
- size_t GetNumDrainingStreams() const;
-
- // Returns the number of currently open peer initiated streams, excluding
- // static streams.
- // TODO(fayang): remove this and instead use
- // LegacyStreamIdManager::num_open_incoming_streams() in tests when
- // deprecating quic_stream_id_manager_handles_accounting.
- size_t GetNumOpenIncomingStreams() const;
-
- // Returns the number of currently open self initiated streams, excluding
- // static streams.
- // TODO(fayang): remove this and instead use
- // LegacyStreamIdManager::num_open_outgoing_streams() in tests when
- // deprecating quic_stream_id_manager_handles_accounting.
- size_t GetNumOpenOutgoingStreams() const;
-
- // Returns the number of open peer initiated static streams.
- size_t num_incoming_static_streams() const {
- return num_incoming_static_streams_;
- }
-
- // Returns the number of open self initiated static streams.
- size_t num_outgoing_static_streams() const {
- return num_outgoing_static_streams_;
- }
-
// Add the stream to the session's write-blocked list because it is blocked by
// connection-level flow control but not by its own stream-level flow control.
// The stream will be given a chance to write when a connection-level
@@ -363,6 +346,10 @@ class QUIC_EXPORT_PRIVATE QuicSession
// Called when stream |id| is newly waiting for acks.
void OnStreamWaitingForAcks(QuicStreamId id);
+ // Returns true if there is pending handshake data in the crypto stream.
+ // TODO(ianswett): Make this private or remove.
+ bool HasPendingHandshake() const;
+
// Returns true if the session has data to be sent, either queued in the
// connection, or in a write-blocked stream.
bool HasDataToWrite() const;
@@ -435,12 +422,6 @@ class QUIC_EXPORT_PRIVATE QuicSession
// Return true if given stream is peer initiated.
bool IsIncomingStream(QuicStreamId id) const;
- size_t GetNumLocallyClosedOutgoingStreamsHighestOffset() const;
-
- size_t num_locally_closed_incoming_streams_highest_offset() const {
- return num_locally_closed_incoming_streams_highest_offset_;
- }
-
// Record errors when a connection is closed at the server side, should only
// be called from server's perspective.
// Noop if |error| is QUIC_NO_ERROR.
@@ -478,27 +459,30 @@ class QUIC_EXPORT_PRIVATE QuicSession
// uses TLS handshake.
virtual void OnAlpnSelected(quiche::QuicheStringPiece alpn);
- bool deprecate_draining_streams() const {
- return deprecate_draining_streams_;
- }
-
- bool break_close_loop() const { return break_close_loop_; }
-
// Called on clients by the crypto handshaker to provide application state
// necessary for sending application data in 0-RTT. The state provided here is
// the same state that was provided to the crypto handshaker in
- // QuicCryptoClientStream::OnApplicationState on a previous connection.
- // Application protocols that require state to be carried over from the
- // previous connection to support 0-RTT data must implement this method to
- // ingest this state. For example, an HTTP/3 QuicSession would implement this
- // function to process the remembered server SETTINGS frame and apply those
- // SETTINGS to 0-RTT data. This function returns true if the application state
- // has been successfully processed, and false if there was an error processing
- // the cached state and the connection should be closed.
- virtual bool SetApplicationState(ApplicationState* /*cached_state*/) {
+ // QuicCryptoStream::SetServerApplicationStateForResumption on a previous
+ // connection. Application protocols that require state to be carried over
+ // from the previous connection to support 0-RTT data must implement this
+ // method to ingest this state. For example, an HTTP/3 QuicSession would
+ // implement this function to process the remembered server SETTINGS and apply
+ // those SETTINGS to 0-RTT data. This function returns true if the application
+ // state has been successfully processed, and false if there was an error
+ // processing the cached state and the connection should be closed.
+ virtual bool ResumeApplicationState(ApplicationState* /*cached_state*/) {
return true;
}
+ const quiche::QuicheOptional<std::string> user_agent_id() const {
+ return user_agent_id_;
+ }
+
+ void SetUserAgentId(std::string user_agent_id) {
+ user_agent_id_ = std::move(user_agent_id);
+ connection()->OnUserAgentIdKnown();
+ }
+
protected:
using StreamMap = QuicSmallMap<QuicStreamId, std::unique_ptr<QuicStream>, 10>;
@@ -541,18 +525,10 @@ class QUIC_EXPORT_PRIVATE QuicSession
bool CanOpenNextOutgoingBidirectionalStream();
bool CanOpenNextOutgoingUnidirectionalStream();
- // Returns the number of open dynamic streams.
- uint64_t GetNumOpenDynamicStreams() const;
-
// Returns the maximum bidirectional streams parameter sent with the handshake
// as a transport parameter, or in the most recent MAX_STREAMS frame.
QuicStreamCount GetAdvertisedMaxIncomingBidirectionalStreams() const;
- // Performs the work required to close |stream_id|. If |rst_sent| then a
- // Reset Stream frame has already been sent for this stream.
- // TODO(fayang): Remove CloseStreamInner.
- virtual void CloseStreamInner(QuicStreamId stream_id, bool rst_sent);
-
// When a stream is closed locally, it may not yet know how many bytes the
// peer sent on that stream.
// When this data arrives (via stream frame w. FIN, trailing headers, or RST)
@@ -589,10 +565,6 @@ class QUIC_EXPORT_PRIVATE QuicSession
return &write_blocked_streams_;
}
- size_t GetNumDynamicOutgoingStreams() const;
-
- size_t GetNumDrainingOutgoingStreams() const;
-
// Returns true if the stream is still active.
bool IsOpenStream(QuicStreamId id);
@@ -630,6 +602,14 @@ class QUIC_EXPORT_PRIVATE QuicSession
QuicDatagramQueue* datagram_queue() { return &datagram_queue_; }
+ size_t num_static_streams() const { return num_static_streams_; }
+
+ bool was_zero_rtt_rejected() const { return was_zero_rtt_rejected_; }
+
+ size_t num_outgoing_draining_streams() const {
+ return num_outgoing_draining_streams_;
+ }
+
// Processes the stream type information of |pending| depending on
// different kinds of sessions' own rules. Returns true if the pending stream
// is converted into a normal stream.
@@ -704,6 +684,9 @@ class QUIC_EXPORT_PRIVATE QuicSession
// if all lost data is retransmitted. Returns false otherwise.
bool RetransmitLostData();
+ // Returns true if stream data should be written.
+ bool CanWriteStreamData() const;
+
// Closes the pending stream |stream_id| before it has been created.
void ClosePendingStream(QuicStreamId stream_id);
@@ -720,6 +703,12 @@ class QUIC_EXPORT_PRIVATE QuicSession
QuicRstStreamErrorCode error,
QuicStreamOffset bytes_written);
+ // Closes the connection and returns false if |new_window| is lower than
+ // |stream|'s current flow control window.
+ // Returns true otherwise.
+ bool ValidateStreamFlowControlLimit(QuicStreamOffset new_window,
+ const QuicStream* stream);
+
// Sends a STOP_SENDING frame if the stream type allows.
void MaybeSendStopSendingFrame(QuicStreamId id, QuicRstStreamErrorCode error);
@@ -756,13 +745,6 @@ class QUIC_EXPORT_PRIVATE QuicSession
// which are waiting for the first byte of payload to arrive.
PendingStreamMap pending_stream_map_;
- // Set of stream ids that are "draining" -- a FIN has been sent and received,
- // but the stream object still exists because not all the received data has
- // been consumed.
- // TODO(fayang): Remove draining_streams_ when deprecate
- // quic_deprecate_draining_streams.
- QuicHashSet<QuicStreamId> draining_streams_;
-
// Set of stream ids that are waiting for acks excluding crypto stream id.
QuicHashSet<QuicStreamId> streams_waiting_for_acks_;
@@ -774,37 +756,16 @@ class QUIC_EXPORT_PRIVATE QuicSession
// Manages stream IDs for version99/IETF QUIC
UberQuicStreamIdManager v99_streamid_manager_;
- // A counter for peer initiated dynamic streams which are in the stream_map_.
- // TODO(fayang): Remove this when deprecating
- // quic_stream_id_manager_handles_accounting.
- size_t num_dynamic_incoming_streams_;
+ // A counter for streams which have sent and received FIN but waiting for
+ // application to consume data.
+ size_t num_draining_streams_;
- // A counter for peer initiated streams which have sent and received FIN but
+ // A counter for self initiated streams which have sent and received FIN but
// waiting for application to consume data.
- // TODO(fayang): Remove this when deprecating
- // quic_stream_id_manager_handles_accounting.
- size_t num_draining_incoming_streams_;
+ size_t num_outgoing_draining_streams_;
- // A counter for self initiated streams which have sent and received FIN but
- // waiting for application to consume data. Only used when
- // deprecate_draining_streams_ is true.
- // TODO(fayang): Remove this when deprecating
- // quic_stream_id_manager_handles_accounting.
- size_t num_draining_outgoing_streams_;
-
- // A counter for self initiated static streams which are in
- // stream_map_.
- size_t num_outgoing_static_streams_;
-
- // A counter for peer initiated static streams which are in
- // stream_map_.
- size_t num_incoming_static_streams_;
-
- // A counter for peer initiated streams which are in the
- // locally_closed_streams_highest_offset_.
- // TODO(fayang): Remove this when deprecating
- // quic_stream_id_manager_handles_accounting.
- size_t num_locally_closed_incoming_streams_highest_offset_;
+ // A counter for static streams which are in stream_map_.
+ size_t num_static_streams_;
// Received information for a connection close.
QuicConnectionCloseFrame on_closed_frame_;
@@ -842,6 +803,8 @@ class QUIC_EXPORT_PRIVATE QuicSession
// list may be a superset of the connection framer's supported versions.
ParsedQuicVersionVector supported_versions_;
+ quiche::QuicheOptional<std::string> user_agent_id_;
+
// If true, write_blocked_streams_ uses HTTP2 (tree-style) priority write
// scheduler.
bool use_http2_priority_write_scheduler_;
@@ -853,11 +816,11 @@ class QUIC_EXPORT_PRIVATE QuicSession
// If true, enables round robin scheduling.
bool enable_round_robin_scheduling_;
- // Latched value of quic_deprecate_draining_streams.
- const bool deprecate_draining_streams_;
+ // Whether the session has received a 0-RTT rejection (QUIC+TLS only).
+ bool was_zero_rtt_rejected_;
- // Latched value of quic_break_session_stream_close_loop.
- const bool break_close_loop_;
+ // Latched value of flag quic_fix_gquic_stream_type.
+ const bool fix_gquic_stream_type_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc
index 9d5e977d0a6..12a48300bdb 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc
@@ -10,6 +10,7 @@
#include <utility>
#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
+#include "net/third_party/quiche/src/quic/core/crypto/null_decrypter.h"
#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h"
#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h"
#include "net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.h"
@@ -77,6 +78,17 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
kInitialStreamFlowControlWindowForTest);
session()->config()->SetInitialSessionFlowControlWindowToSend(
kInitialSessionFlowControlWindowForTest);
+ if (session()->version().AuthenticatesHandshakeConnectionIds()) {
+ if (session()->perspective() == Perspective::IS_CLIENT) {
+ session()->config()->SetOriginalConnectionIdToSend(
+ session()->connection()->connection_id());
+ session()->config()->SetInitialSourceConnectionIdToSend(
+ session()->connection()->connection_id());
+ } else {
+ session()->config()->SetInitialSourceConnectionIdToSend(
+ session()->connection()->client_connection_id());
+ }
+ }
if (session()->connection()->version().handshake_protocol ==
PROTOCOL_TLS1_3) {
TransportParameters transport_parameters;
@@ -123,6 +135,8 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
HandshakeState GetHandshakeState() const override {
return one_rtt_keys_available() ? HANDSHAKE_COMPLETE : HANDSHAKE_START;
}
+ void SetServerApplicationStateForResumption(
+ std::unique_ptr<ApplicationState> /*application_state*/) override {}
MOCK_METHOD(void, OnCanWrite, (), (override));
bool HasPendingCryptoRetransmission() const override { return false; }
@@ -183,6 +197,9 @@ class TestSession : public QuicSession {
this->connection()->SetEncrypter(
ENCRYPTION_FORWARD_SECURE,
std::make_unique<NullEncrypter>(connection->perspective()));
+ if (this->connection()->version().SupportsAntiAmplificationLimit()) {
+ QuicConnectionPeer::SetAddressValidated(this->connection());
+ }
}
~TestSession() override { DeleteConnection(); }
@@ -216,7 +233,7 @@ class TestSession : public QuicSession {
TestStream* CreateIncomingStream(QuicStreamId id) override {
// Enforce the limit on the number of open streams.
if (!VersionHasIetfQuicFrames(connection()->transport_version()) &&
- GetNumOpenIncomingStreams() + 1 >
+ stream_id_manager().num_open_incoming_streams() + 1 >
max_open_incoming_bidirectional_streams()) {
// No need to do this test for version 99; it's done by
// QuicSession::GetOrCreateStream.
@@ -226,11 +243,10 @@ class TestSession : public QuicSession {
return nullptr;
}
- TestStream* stream =
- new TestStream(id, this,
- DetermineStreamType(
- id, connection()->transport_version(), perspective(),
- /*is_incoming=*/true, BIDIRECTIONAL));
+ TestStream* stream = new TestStream(
+ id, this,
+ DetermineStreamType(id, connection()->version(), perspective(),
+ /*is_incoming=*/true, BIDIRECTIONAL));
ActivateStream(QuicWrapUnique(stream));
++num_incoming_streams_created_;
return stream;
@@ -239,8 +255,7 @@ class TestSession : public QuicSession {
TestStream* CreateIncomingStream(PendingStream* pending) override {
QuicStreamId id = pending->id();
TestStream* stream = new TestStream(
- pending, DetermineStreamType(id, connection()->transport_version(),
- perspective(),
+ pending, DetermineStreamType(id, connection()->version(), perspective(),
/*is_incoming=*/true, BIDIRECTIONAL));
ActivateStream(QuicWrapUnique(stream));
++num_incoming_streams_created_;
@@ -309,7 +324,7 @@ class TestSession : public QuicSession {
MakeIOVector("not empty", &iov);
QuicStreamPeer::SendBuffer(stream).SaveStreamData(&iov, 1, 0, 9);
QuicConsumedData consumed =
- WritevData(stream->id(), 9, 0, FIN, NOT_RETRANSMISSION, QuicheNullOpt);
+ WritevData(stream->id(), 9, 0, FIN, NOT_RETRANSMISSION, QUICHE_NULLOPT);
QuicStreamPeer::SendBuffer(stream).OnStreamDataConsumed(
consumed.bytes_consumed);
return consumed;
@@ -326,7 +341,7 @@ class TestSession : public QuicSession {
QuicConsumedData SendLargeFakeData(QuicStream* stream, int bytes) {
DCHECK(writev_consumes_all_data_);
return WritevData(stream->id(), bytes, 0, FIN, NOT_RETRANSMISSION,
- QuicheNullOpt);
+ QUICHE_NULLOPT);
}
bool UsesPendingStreams() const override { return uses_pending_streams_; }
@@ -421,15 +436,15 @@ class QuicSessionTestBase : public QuicTestWithParam<ParsedQuicVersion> {
void CloseStream(QuicStreamId id) {
if (VersionHasIetfQuicFrames(transport_version())) {
- if (QuicUtils::GetStreamType(id, session_.perspective(),
- session_.IsIncomingStream(id)) ==
- READ_UNIDIRECTIONAL) {
+ if (QuicUtils::GetStreamType(
+ id, session_.perspective(), session_.IsIncomingStream(id),
+ connection_->version()) == READ_UNIDIRECTIONAL) {
// Verify reset is not sent for READ_UNIDIRECTIONAL streams.
EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0);
EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(0);
- } else if (QuicUtils::GetStreamType(id, session_.perspective(),
- session_.IsIncomingStream(id)) ==
- WRITE_UNIDIRECTIONAL) {
+ } else if (QuicUtils::GetStreamType(
+ id, session_.perspective(), session_.IsIncomingStream(id),
+ connection_->version()) == WRITE_UNIDIRECTIONAL) {
// Verify RESET_STREAM but not STOP_SENDING is sent for write-only
// stream.
EXPECT_CALL(*connection_, SendControlFrame(_))
@@ -554,6 +569,11 @@ class QuicSessionTestServer : public QuicSessionTestBase {
kQuicDefaultConnectionIdLength) {
client_framer_.set_visitor(&framer_visitor_);
client_framer_.SetInitialObfuscators(TestConnectionId());
+ if (client_framer_.version().KnowsWhichDecrypterToUse()) {
+ client_framer_.InstallDecrypter(
+ ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<NullDecrypter>(Perspective::IS_CLIENT));
+ }
}
QuicPathFrameBuffer path_frame_buffer1_;
@@ -595,6 +615,7 @@ TEST_P(QuicSessionTestServer, OneRttKeysAvailable) {
if (connection_->version().HasHandshakeDone()) {
EXPECT_CALL(*connection_, SendControlFrame(_));
}
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_.GetMutableCryptoStream()->OnHandshakeMessage(message);
EXPECT_TRUE(session_.OneRttKeysAvailable());
}
@@ -990,6 +1011,7 @@ TEST_P(QuicSessionTestServer, Http2Priority) {
QuicTagVector copt;
copt.push_back(kH2PR);
QuicConfigPeer::SetReceivedConnectionOptions(session_.config(), copt);
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_.OnConfigNegotiated();
ASSERT_TRUE(session_.use_http2_priority_write_scheduler());
@@ -1072,6 +1094,7 @@ TEST_P(QuicSessionTestServer, RoundRobinScheduling) {
QuicTagVector copt;
copt.push_back(kRRWS);
QuicConfigPeer::SetReceivedConnectionOptions(session_.config(), copt);
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_.OnConfigNegotiated();
session_.set_writev_consumes_all_data(true);
@@ -1117,6 +1140,7 @@ TEST_P(QuicSessionTestServer, OnCanWriteBundlesStreams) {
CryptoHandshakeMessage msg;
MockPacketWriter* writer = static_cast<MockPacketWriter*>(
QuicConnectionPeer::GetWriter(session_.connection()));
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_.GetMutableCryptoStream()->OnHandshakeMessage(msg);
// Drive congestion control manually.
@@ -1428,6 +1452,7 @@ TEST_P(QuicSessionTestServer, InvalidGoAway) {
// Test that server session will send a connectivity probe in response to a
// connectivity probe on the same path.
TEST_P(QuicSessionTestServer, ServerReplyToConnectivityProbe) {
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
QuicSocketAddress old_peer_address =
QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort);
EXPECT_EQ(old_peer_address, session_.peer_address());
@@ -1461,6 +1486,7 @@ TEST_P(QuicSessionTestServer, ServerReplyToConnectivityProbes) {
if (!VersionHasIetfQuicFrames(transport_version())) {
return;
}
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
QuicSocketAddress old_peer_address =
QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort);
EXPECT_EQ(old_peer_address, session_.peer_address());
@@ -1495,6 +1521,7 @@ TEST_P(QuicSessionTestServer, IncreasedTimeoutAfterCryptoHandshake) {
EXPECT_CALL(*connection_, SendControlFrame(_));
}
CryptoHandshakeMessage msg;
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_.GetMutableCryptoStream()->OnHandshakeMessage(msg);
EXPECT_EQ(kMaximumIdleTimeoutSecs + 3,
QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds());
@@ -1775,6 +1802,7 @@ TEST_P(QuicSessionTestServer, InvalidStreamFlowControlWindowInHandshake) {
} else {
EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
}
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_.OnConfigNegotiated();
}
@@ -1784,6 +1812,7 @@ TEST_P(QuicSessionTestServer, CustomFlowControlWindow) {
copt.push_back(kIFW7);
QuicConfigPeer::SetReceivedConnectionOptions(session_.config(), copt);
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_.OnConfigNegotiated();
EXPECT_EQ(192 * 1024u, QuicFlowControllerPeer::ReceiveWindowSize(
session_.flow_controller()));
@@ -2047,8 +2076,13 @@ TEST_P(QuicSessionTestClient, InvalidSessionFlowControlWindowInHandshake) {
const uint32_t kInvalidWindow = kMinimumFlowControlSendWindow - 1;
QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(session_.config(),
kInvalidWindow);
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_FLOW_CONTROL_INVALID_WINDOW, _, _));
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(connection_->version().AllowsLowFlowControlLimits()
+ ? QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED
+ : QUIC_FLOW_CONTROL_INVALID_WINDOW,
+ _, _));
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_.OnConfigNegotiated();
}
@@ -2059,7 +2093,9 @@ TEST_P(QuicSessionTestClient, InvalidBidiStreamLimitInHandshake) {
}
QuicConfigPeer::SetReceivedMaxBidirectionalStreams(
session_.config(), kDefaultMaxStreamsPerConnection - 1);
- EXPECT_CALL(*connection_, CloseConnection(QUIC_MAX_STREAMS_ERROR, _, _));
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED, _, _));
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_.OnConfigNegotiated();
}
@@ -2070,7 +2106,9 @@ TEST_P(QuicSessionTestClient, InvalidUniStreamLimitInHandshake) {
}
QuicConfigPeer::SetReceivedMaxUnidirectionalStreams(
session_.config(), kDefaultMaxStreamsPerConnection - 1);
- EXPECT_CALL(*connection_, CloseConnection(QUIC_MAX_STREAMS_ERROR, _, _));
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED, _, _));
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_.OnConfigNegotiated();
}
@@ -2088,6 +2126,8 @@ TEST_P(QuicSessionTestClient, InvalidStreamFlowControlWindowInHandshake) {
.WillOnce(
Invoke(connection_, &MockQuicConnection::ReallyCloseConnection));
EXPECT_CALL(*connection_, SendConnectionClosePacket(_, _));
+
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_.OnConfigNegotiated();
}
@@ -2430,14 +2470,9 @@ TEST_P(QuicSessionTestServer, RetransmitLostDataCausesConnectionClose) {
session_.OnFrameLost(QuicFrame(frame));
// Retransmit stream data causes connection close. Stream has not sent fin
// yet, so an RST is sent.
- if (session_.break_close_loop()) {
- EXPECT_CALL(*stream, OnCanWrite()).WillOnce(Invoke([this, stream]() {
- session_.CloseStream(stream->id());
- }));
- } else {
- EXPECT_CALL(*stream, OnCanWrite())
- .WillOnce(Invoke(stream, &QuicStream::OnClose));
- }
+ EXPECT_CALL(*stream, OnCanWrite()).WillOnce(Invoke([this, stream]() {
+ session_.CloseStream(stream->id());
+ }));
if (VersionHasIetfQuicFrames(transport_version())) {
// Once for the RST_STREAM, once for the STOP_SENDING
EXPECT_CALL(*connection_, SendControlFrame(_))
@@ -2466,6 +2501,7 @@ TEST_P(QuicSessionTestServer, SendMessage) {
EXPECT_CALL(*connection_, SendControlFrame(_));
}
CryptoHandshakeMessage handshake_message;
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_.GetMutableCryptoStream()->OnHandshakeMessage(handshake_message);
EXPECT_TRUE(session_.OneRttKeysAvailable());
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc
index 40a67bba21c..6318ac1ecff 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc
@@ -46,7 +46,7 @@ QuicByteCount GetInitialStreamFlowControlWindowToSend(QuicSession* session,
// Unidirectional streams (v99 only).
if (VersionHasIetfQuicFrames(version.transport_version) &&
- !QuicUtils::IsBidirectionalStreamId(stream_id)) {
+ !QuicUtils::IsBidirectionalStreamId(stream_id, version)) {
return session->config()
->GetInitialMaxStreamDataBytesUnidirectionalToSend();
}
@@ -74,7 +74,7 @@ QuicByteCount GetReceivedFlowControlWindow(QuicSession* session,
// Unidirectional streams (v99 only).
if (VersionHasIetfQuicFrames(version.transport_version) &&
- !QuicUtils::IsBidirectionalStreamId(stream_id)) {
+ !QuicUtils::IsBidirectionalStreamId(stream_id, version)) {
if (session->config()
->HasReceivedInitialMaxStreamDataBytesUnidirectional()) {
return session->config()
@@ -359,7 +359,8 @@ QuicStream::QuicStream(QuicStreamId id,
type != CRYPTO
? QuicUtils::GetStreamType(id_,
session->perspective(),
- session->IsIncomingStream(id_))
+ session->IsIncomingStream(id_),
+ session->version())
: type),
perspective_(session->perspective()) {
if (type_ == WRITE_UNIDIRECTIONAL) {
@@ -432,15 +433,13 @@ void QuicStream::OnStreamFrame(const QuicStreamFrame& frame) {
return;
}
- if (frame.fin) {
- if (!session_->deprecate_draining_streams() || !fin_received_) {
- fin_received_ = true;
- if (fin_sent_) {
- DCHECK(!was_draining_ || !session_->deprecate_draining_streams());
- session_->StreamDraining(id_,
- /*unidirectional=*/type_ != BIDIRECTIONAL);
- was_draining_ = true;
- }
+ if (frame.fin && !fin_received_) {
+ fin_received_ = true;
+ if (fin_sent_) {
+ DCHECK(!was_draining_);
+ session_->StreamDraining(id_,
+ /*unidirectional=*/type_ != BIDIRECTIONAL);
+ was_draining_ = true;
}
}
@@ -582,14 +581,12 @@ void QuicStream::Reset(QuicRstStreamErrorCode error) {
stream_error_ = error;
session()->SendRstStream(id(), error, stream_bytes_written());
rst_sent_ = true;
- if (session_->break_close_loop()) {
- if (read_side_closed_ && write_side_closed_ && !IsWaitingForAcks()) {
- session()->OnStreamDoneWaitingForAcks(id_);
- return;
- }
- CloseReadSide();
- CloseWriteSide();
+ if (read_side_closed_ && write_side_closed_ && !IsWaitingForAcks()) {
+ session()->OnStreamDoneWaitingForAcks(id_);
+ return;
}
+ CloseReadSide();
+ CloseWriteSide();
}
void QuicStream::OnUnrecoverableError(QuicErrorCode error,
@@ -781,12 +778,8 @@ void QuicStream::CloseReadSide() {
if (write_side_closed_) {
QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << id();
- if (session_->break_close_loop()) {
- session_->OnStreamClosed(id());
- OnClose();
- } else {
- session_->CloseStream(id());
- }
+ session_->OnStreamClosed(id());
+ OnClose();
}
}
@@ -799,12 +792,8 @@ void QuicStream::CloseWriteSide() {
write_side_closed_ = true;
if (read_side_closed_) {
QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << id();
- if (session_->break_close_loop()) {
- session_->OnStreamClosed(id());
- OnClose();
- } else {
- session_->CloseStream(id());
- }
+ session_->OnStreamClosed(id());
+ OnClose();
}
}
@@ -827,12 +816,7 @@ void QuicStream::StopReading() {
}
void QuicStream::OnClose() {
- if (session()->break_close_loop()) {
- DCHECK(read_side_closed_ && write_side_closed_);
- } else {
- CloseReadSide();
- CloseWriteSide();
- }
+ DCHECK(read_side_closed_ && write_side_closed_);
if (!fin_sent_ && !rst_sent_) {
// For flow control accounting, tell the peer how many bytes have been
@@ -946,16 +930,11 @@ bool QuicStream::ConfigSendWindowOffset(QuicStreamOffset new_offset) {
<< "ConfigSendWindowOffset called on stream without flow control";
return false;
}
- if (perspective_ == Perspective::IS_CLIENT &&
- session()->version().AllowsLowFlowControlLimits() &&
- new_offset < flow_controller_->send_window_offset()) {
- OnUnrecoverableError(
- QUIC_FLOW_CONTROL_INVALID_WINDOW,
- quiche::QuicheStrCat("New stream max data ", new_offset,
- " decreases current limit: ",
- flow_controller_->send_window_offset()));
- return false;
- }
+
+ QUIC_BUG_IF(session()->version().AllowsLowFlowControlLimits() &&
+ new_offset < flow_controller_->send_window_offset())
+ << ENDPOINT << "The new offset " << new_offset
+ << " decreases current offset " << flow_controller_->send_window_offset();
if (flow_controller_->UpdateSendWindowOffset(new_offset)) {
// Let session unblock this stream.
session_->MarkConnectionLevelWriteBlocked(id_);
@@ -1048,7 +1027,7 @@ bool QuicStream::RetransmitStreamData(QuicStreamOffset offset,
stream_bytes_written());
consumed = stream_delegate_->WritevData(
id_, retransmission_length, retransmission_offset,
- can_bundle_fin ? FIN : NO_FIN, type, QuicheNullOpt);
+ can_bundle_fin ? FIN : NO_FIN, type, QUICHE_NULLOPT);
QUIC_DVLOG(1) << ENDPOINT << "stream " << id_
<< " is forced to retransmit stream data ["
<< retransmission_offset << ", "
@@ -1070,7 +1049,7 @@ bool QuicStream::RetransmitStreamData(QuicStreamOffset offset,
QUIC_DVLOG(1) << ENDPOINT << "stream " << id_
<< " retransmits fin only frame.";
consumed = stream_delegate_->WritevData(id_, 0, stream_bytes_written(), FIN,
- type, QuicheNullOpt);
+ type, QUICHE_NULLOPT);
if (!consumed.fin_consumed) {
return false;
}
@@ -1148,7 +1127,7 @@ void QuicStream::WriteBufferedData() {
}
QuicConsumedData consumed_data =
stream_delegate_->WritevData(id(), write_length, stream_bytes_written(),
- state, NOT_RETRANSMISSION, QuicheNullOpt);
+ state, NOT_RETRANSMISSION, QUICHE_NULLOPT);
OnStreamDataConsumed(consumed_data.bytes_consumed);
@@ -1228,7 +1207,7 @@ void QuicStream::WritePendingRetransmission() {
<< " retransmits fin only frame.";
consumed =
stream_delegate_->WritevData(id_, 0, stream_bytes_written(), FIN,
- LOSS_RETRANSMISSION, QuicheNullOpt);
+ LOSS_RETRANSMISSION, QUICHE_NULLOPT);
fin_lost_ = !consumed.fin_consumed;
if (fin_lost_) {
// Connection is write blocked.
@@ -1243,7 +1222,7 @@ void QuicStream::WritePendingRetransmission() {
(pending.offset + pending.length == stream_bytes_written());
consumed = stream_delegate_->WritevData(
id_, pending.length, pending.offset, can_bundle_fin ? FIN : NO_FIN,
- LOSS_RETRANSMISSION, QuicheNullOpt);
+ LOSS_RETRANSMISSION, QUICHE_NULLOPT);
QUIC_DVLOG(1) << ENDPOINT << "stream " << id_
<< " tries to retransmit stream data [" << pending.offset
<< ", " << pending.offset + pending.length
@@ -1302,6 +1281,22 @@ void QuicStream::SendStopSending(uint16_t code) {
session_->SendStopSending(code, id_);
}
+QuicFlowController* QuicStream::flow_controller() {
+ if (flow_controller_.has_value()) {
+ return &flow_controller_.value();
+ }
+ QUIC_BUG << "Trying to access non-existent flow controller.";
+ return nullptr;
+}
+
+const QuicFlowController* QuicStream::flow_controller() const {
+ if (flow_controller_.has_value()) {
+ return &flow_controller_.value();
+ }
+ QUIC_BUG << "Trying to access non-existent flow controller.";
+ return nullptr;
+}
+
// static
spdy::SpdyStreamPrecedence QuicStream::CalculateDefaultPriority(
const QuicSession* session) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_stream.h
index fe9d04c021f..7a847f09ec1 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream.h
@@ -165,14 +165,6 @@ class QUIC_EXPORT_PRIVATE QuicStream
// stream to write any pending data.
virtual void OnCanWrite();
- // Called just before the object is destroyed.
- // The object should not be accessed after OnClose is called.
- // Sends a RST_STREAM with code QUIC_RST_ACKNOWLEDGEMENT if neither a FIN nor
- // a RST_STREAM has been sent.
- // TODO(fayang): move this to protected when deprecating
- // quic_break_session_stream_close_loop.
- virtual void OnClose();
-
// Called by the session when the endpoint receives a RST_STREAM from the
// peer.
virtual void OnStreamReset(const QuicRstStreamFrame& frame);
@@ -237,7 +229,9 @@ class QUIC_EXPORT_PRIVATE QuicStream
int num_frames_received() const;
int num_duplicate_frames_received() const;
- QuicFlowController* flow_controller() { return &*flow_controller_; }
+ QuicFlowController* flow_controller();
+
+ const QuicFlowController* flow_controller() const;
// Called when endpoint receives a frame which could increase the highest
// offset.
@@ -381,6 +375,12 @@ class QUIC_EXPORT_PRIVATE QuicStream
const QuicReferenceCountedPointer<QuicAckListenerInterface>&
/*ack_listener*/) {}
+ // Called just before the object is destroyed.
+ // The object should not be accessed after OnClose is called.
+ // Sends a RST_STREAM with code QUIC_RST_ACKNOWLEDGEMENT if neither a FIN nor
+ // a RST_STREAM has been sent.
+ virtual void OnClose();
+
// True if buffered data in send buffer is below buffered_data_threshold_.
bool CanWriteNewData() const;
@@ -539,8 +539,7 @@ class QUIC_EXPORT_PRIVATE QuicStream
// If initialized, reset this stream at this deadline.
QuicTime deadline_;
- // True if this stream has entered draining state. Only used when
- // quic_deprecate_draining_streams is true.
+ // True if this stream has entered draining state.
bool was_draining_;
// Indicates whether this stream is bidirectional, read unidirectional or
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc
index ba31decd2b9..528d9557ec4 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc
@@ -55,6 +55,14 @@ bool QuicStreamIdManager::OnStreamsBlockedFrame(
" exceeds incoming max stream ", incoming_advertised_max_streams_);
return false;
}
+ if (GetQuicReloadableFlag(quic_stop_sending_duplicate_max_streams)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_stop_sending_duplicate_max_streams);
+ DCHECK_LE(incoming_advertised_max_streams_, incoming_actual_max_streams_);
+ if (incoming_advertised_max_streams_ == incoming_actual_max_streams_) {
+ // We have told peer about current max.
+ return true;
+ }
+ }
if (frame.stream_count < incoming_actual_max_streams_) {
// Peer thinks it's blocked on a stream count that is less than our current
// max. Inform the peer of the correct stream count.
@@ -104,12 +112,17 @@ void QuicStreamIdManager::MaybeSendMaxStreamsFrame() {
}
void QuicStreamIdManager::SendMaxStreamsFrame() {
+ if (GetQuicReloadableFlag(quic_stop_sending_duplicate_max_streams)) {
+ QUIC_BUG_IF(incoming_advertised_max_streams_ >=
+ incoming_actual_max_streams_);
+ }
incoming_advertised_max_streams_ = incoming_actual_max_streams_;
delegate_->SendMaxStreams(incoming_advertised_max_streams_, unidirectional_);
}
void QuicStreamIdManager::OnStreamClosed(QuicStreamId stream_id) {
- DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id), unidirectional_);
+ DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id, version_),
+ unidirectional_);
if (QuicUtils::IsOutgoingStreamId(version_, stream_id, perspective_)) {
// Nothing to do for outgoing streams.
return;
@@ -147,7 +160,8 @@ bool QuicStreamIdManager::MaybeIncreaseLargestPeerStreamId(
const QuicStreamId stream_id,
std::string* error_details) {
// |stream_id| must be an incoming stream of the right directionality.
- DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id), unidirectional_);
+ DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id, version_),
+ unidirectional_);
DCHECK_NE(QuicUtils::IsServerInitiatedStreamId(version_.transport_version,
stream_id),
perspective_ == Perspective::IS_SERVER);
@@ -193,7 +207,7 @@ bool QuicStreamIdManager::MaybeIncreaseLargestPeerStreamId(
}
bool QuicStreamIdManager::IsAvailableStream(QuicStreamId id) const {
- DCHECK_NE(QuicUtils::IsBidirectionalStreamId(id), unidirectional_);
+ DCHECK_NE(QuicUtils::IsBidirectionalStreamId(id, version_), unidirectional_);
if (QuicUtils::IsOutgoingStreamId(version_, id, perspective_)) {
// Stream IDs under next_ougoing_stream_id_ are either open or previously
// open but now closed.
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc
index 2179ba2c860..689d4112d85 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc
@@ -139,13 +139,18 @@ TEST_P(QuicStreamIdManagerTest, CheckMaxStreamsBadValuesOverMaxFailsOutgoing) {
}
// Check the case of the stream count in a STREAMS_BLOCKED frame is less than
-// the count most recently advertised in a MAX_STREAMS frame. This should cause
-// a MAX_STREAMS frame with the most recently advertised count to be sent.
+// the count most recently advertised in a MAX_STREAMS frame.
TEST_P(QuicStreamIdManagerTest, ProcessStreamsBlockedOk) {
QuicStreamCount stream_count =
stream_id_manager_.incoming_initial_max_open_streams();
QuicStreamsBlockedFrame frame(0, stream_count - 1, IsUnidirectional());
- EXPECT_CALL(delegate_, SendMaxStreams(stream_count, IsUnidirectional()));
+ if (GetQuicReloadableFlag(quic_stop_sending_duplicate_max_streams)) {
+ // We have notified peer about current max.
+ EXPECT_CALL(delegate_, SendMaxStreams(stream_count, IsUnidirectional()))
+ .Times(0);
+ } else {
+ EXPECT_CALL(delegate_, SendMaxStreams(stream_count, IsUnidirectional()));
+ }
std::string error_details;
EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame, &error_details));
}
@@ -398,7 +403,12 @@ TEST_P(QuicStreamIdManagerTest, StreamsBlockedEdgeConditions) {
// Check that receipt of a STREAMS BLOCKED with stream-count = 0 invokes a
// MAX STREAMS, count = 123, when the MaxOpen... is set to 123.
EXPECT_CALL(delegate_, SendMaxStreams(123u, IsUnidirectional()));
- stream_id_manager_.SetMaxOpenIncomingStreams(123);
+ if (GetQuicReloadableFlag(quic_stop_sending_duplicate_max_streams)) {
+ QuicStreamIdManagerPeer::set_incoming_actual_max_streams(
+ &stream_id_manager_, 123);
+ } else {
+ stream_id_manager_.SetMaxOpenIncomingStreams(123);
+ }
frame.stream_count = 0;
EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame, &error_details));
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc
index f30a3be7216..356a77d2f59 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc
@@ -305,7 +305,7 @@ TEST_P(QuicStreamTest, BlockIfOnlySomeDataConsumed) {
EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this]() {
return session_->ConsumeData(stream_->id(), 1u, 0u, NO_FIN,
- NOT_RETRANSMISSION, QuicheNullOpt);
+ NOT_RETRANSMISSION, QUICHE_NULLOPT);
}));
stream_->WriteOrBufferData(quiche::QuicheStringPiece(kData1, 2), false,
nullptr);
@@ -324,7 +324,7 @@ TEST_P(QuicStreamTest, BlockIfFinNotConsumedWithData) {
EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this]() {
return session_->ConsumeData(stream_->id(), 2u, 0u, NO_FIN,
- NOT_RETRANSMISSION, QuicheNullOpt);
+ NOT_RETRANSMISSION, QUICHE_NULLOPT);
}));
stream_->WriteOrBufferData(quiche::QuicheStringPiece(kData1, 2), true,
nullptr);
@@ -372,7 +372,7 @@ TEST_P(QuicStreamTest, WriteOrBufferData) {
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this]() {
return session_->ConsumeData(stream_->id(), kDataLen - 1, 0u, NO_FIN,
- NOT_RETRANSMISSION, QuicheNullOpt);
+ NOT_RETRANSMISSION, QUICHE_NULLOPT);
}));
stream_->WriteOrBufferData(kData1, false, nullptr);
@@ -388,7 +388,8 @@ TEST_P(QuicStreamTest, WriteOrBufferData) {
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this]() {
return session_->ConsumeData(stream_->id(), kDataLen - 1, kDataLen - 1,
- NO_FIN, NOT_RETRANSMISSION, QuicheNullOpt);
+ NO_FIN, NOT_RETRANSMISSION,
+ QUICHE_NULLOPT);
}));
EXPECT_CALL(*stream_, OnCanWriteNewData());
stream_->OnCanWrite();
@@ -398,7 +399,8 @@ TEST_P(QuicStreamTest, WriteOrBufferData) {
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this]() {
return session_->ConsumeData(stream_->id(), 2u, 2 * kDataLen - 2,
- NO_FIN, NOT_RETRANSMISSION, QuicheNullOpt);
+ NO_FIN, NOT_RETRANSMISSION,
+ QUICHE_NULLOPT);
}));
EXPECT_CALL(*stream_, OnCanWriteNewData());
stream_->OnCanWrite();
@@ -445,7 +447,7 @@ TEST_P(QuicStreamTest, RstAlwaysSentIfNoFinSent) {
EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this]() {
return session_->ConsumeData(stream_->id(), 1u, 0u, NO_FIN,
- NOT_RETRANSMISSION, QuicheNullOpt);
+ NOT_RETRANSMISSION, QUICHE_NULLOPT);
}));
stream_->WriteOrBufferData(quiche::QuicheStringPiece(kData1, 1), false,
nullptr);
@@ -455,12 +457,8 @@ TEST_P(QuicStreamTest, RstAlwaysSentIfNoFinSent) {
// Now close the stream, and expect that we send a RST.
EXPECT_CALL(*session_, SendRstStream(_, _, _));
- if (session_->break_close_loop()) {
- stream_->CloseReadSide();
- stream_->CloseWriteSide();
- } else {
- stream_->OnClose();
- }
+ stream_->CloseReadSide();
+ stream_->CloseWriteSide();
EXPECT_FALSE(session_->HasUnackedStreamData());
EXPECT_FALSE(fin_sent());
EXPECT_TRUE(rst_sent());
@@ -479,7 +477,7 @@ TEST_P(QuicStreamTest, RstNotSentIfFinSent) {
EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this]() {
return session_->ConsumeData(stream_->id(), 1u, 0u, FIN,
- NOT_RETRANSMISSION, QuicheNullOpt);
+ NOT_RETRANSMISSION, QUICHE_NULLOPT);
}));
stream_->WriteOrBufferData(quiche::QuicheStringPiece(kData1, 1), true,
nullptr);
@@ -487,12 +485,8 @@ TEST_P(QuicStreamTest, RstNotSentIfFinSent) {
EXPECT_FALSE(rst_sent());
// Now close the stream, and expect that we do not send a RST.
- if (session_->break_close_loop()) {
- stream_->CloseReadSide();
- stream_->CloseWriteSide();
- } else {
- stream_->OnClose();
- }
+ stream_->CloseReadSide();
+ stream_->CloseWriteSide();
EXPECT_TRUE(fin_sent());
EXPECT_FALSE(rst_sent());
}
@@ -516,12 +510,8 @@ TEST_P(QuicStreamTest, OnlySendOneRst) {
// Now close the stream (any further resets being sent would break the
// expectation above).
- if (session_->break_close_loop()) {
- stream_->CloseReadSide();
- stream_->CloseWriteSide();
- } else {
- stream_->OnClose();
- }
+ stream_->CloseReadSide();
+ stream_->CloseWriteSide();
EXPECT_FALSE(fin_sent());
EXPECT_TRUE(rst_sent());
}
@@ -657,12 +647,8 @@ TEST_P(QuicStreamTest, InvalidFinalByteOffsetFromRst) {
CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _));
stream_->OnStreamReset(rst_frame);
EXPECT_TRUE(stream_->HasReceivedFinalOffset());
- if (session_->break_close_loop()) {
- stream_->CloseReadSide();
- stream_->CloseWriteSide();
- } else {
- stream_->OnClose();
- }
+ stream_->CloseReadSide();
+ stream_->CloseWriteSide();
}
TEST_P(QuicStreamTest, FinalByteOffsetFromZeroLengthStreamFrame) {
@@ -760,13 +746,13 @@ TEST_P(QuicStreamTest, SetDrainingIncomingOutgoing) {
EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this]() {
return session_->ConsumeData(stream_->id(), 2u, 0u, FIN,
- NOT_RETRANSMISSION, QuicheNullOpt);
+ NOT_RETRANSMISSION, QUICHE_NULLOPT);
}));
stream_->WriteOrBufferData(quiche::QuicheStringPiece(kData1, 2), true,
nullptr);
EXPECT_TRUE(stream_->write_side_closed());
- EXPECT_EQ(1u, session_->GetNumDrainingStreams());
+ EXPECT_EQ(1u, QuicSessionPeer::GetNumDrainingStreams(session_.get()));
EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
}
@@ -778,7 +764,7 @@ TEST_P(QuicStreamTest, SetDrainingOutgoingIncoming) {
EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this]() {
return session_->ConsumeData(stream_->id(), 2u, 0u, FIN,
- NOT_RETRANSMISSION, QuicheNullOpt);
+ NOT_RETRANSMISSION, QUICHE_NULLOPT);
}));
stream_->WriteOrBufferData(quiche::QuicheStringPiece(kData1, 2), true,
nullptr);
@@ -794,7 +780,7 @@ TEST_P(QuicStreamTest, SetDrainingOutgoingIncoming) {
EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
EXPECT_FALSE(stream_->reading_stopped());
- EXPECT_EQ(1u, session_->GetNumDrainingStreams());
+ EXPECT_EQ(1u, QuicSessionPeer::GetNumDrainingStreams(session_.get()));
EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
}
@@ -1054,7 +1040,7 @@ TEST_P(QuicStreamTest, WriteBufferedData) {
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this]() {
return session_->ConsumeData(stream_->id(), 100u, 0u, NO_FIN,
- NOT_RETRANSMISSION, QuicheNullOpt);
+ NOT_RETRANSMISSION, QUICHE_NULLOPT);
}));
stream_->WriteOrBufferData(data, false, nullptr);
stream_->WriteOrBufferData(data, false, nullptr);
@@ -1067,7 +1053,7 @@ TEST_P(QuicStreamTest, WriteBufferedData) {
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this]() {
return session_->ConsumeData(stream_->id(), 100, 100u, NO_FIN,
- NOT_RETRANSMISSION, QuicheNullOpt);
+ NOT_RETRANSMISSION, QUICHE_NULLOPT);
}));
// Buffered data size > threshold, do not ask upper layer for more data.
EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(0);
@@ -1082,7 +1068,7 @@ TEST_P(QuicStreamTest, WriteBufferedData) {
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this, data_to_write]() {
return session_->ConsumeData(stream_->id(), data_to_write, 200u, NO_FIN,
- NOT_RETRANSMISSION, QuicheNullOpt);
+ NOT_RETRANSMISSION, QUICHE_NULLOPT);
}));
// Buffered data size < threshold, ask upper layer for more data.
EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1);
@@ -1132,7 +1118,7 @@ TEST_P(QuicStreamTest, WriteBufferedData) {
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this, data_to_write]() {
return session_->ConsumeData(stream_->id(), data_to_write, 0u, NO_FIN,
- NOT_RETRANSMISSION, QuicheNullOpt);
+ NOT_RETRANSMISSION, QUICHE_NULLOPT);
}));
EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1);
@@ -1194,7 +1180,7 @@ TEST_P(QuicStreamTest, WriteMemSlices) {
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this]() {
return session_->ConsumeData(stream_->id(), 100u, 0u, NO_FIN,
- NOT_RETRANSMISSION, QuicheNullOpt);
+ NOT_RETRANSMISSION, QUICHE_NULLOPT);
}));
// There is no buffered data before, all data should be consumed.
QuicConsumedData consumed = stream_->WriteMemSlices(span1, false);
@@ -1217,7 +1203,7 @@ TEST_P(QuicStreamTest, WriteMemSlices) {
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this, data_to_write]() {
return session_->ConsumeData(stream_->id(), data_to_write, 100u, NO_FIN,
- NOT_RETRANSMISSION, QuicheNullOpt);
+ NOT_RETRANSMISSION, QUICHE_NULLOPT);
}));
EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1);
stream_->OnCanWrite();
@@ -1254,7 +1240,7 @@ TEST_P(QuicStreamTest, WriteMemSlicesReachStreamLimit) {
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this]() {
return session_->ConsumeData(stream_->id(), 5u, 0u, NO_FIN,
- NOT_RETRANSMISSION, QuicheNullOpt);
+ NOT_RETRANSMISSION, QUICHE_NULLOPT);
}));
// There is no buffered data before, all data should be consumed.
QuicConsumedData consumed = stream_->WriteMemSlices(span1, false);
@@ -1392,7 +1378,7 @@ TEST_P(QuicStreamTest, OnStreamFrameLost) {
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this]() {
return session_->ConsumeData(stream_->id(), 9u, 18u, FIN,
- NOT_RETRANSMISSION, QuicheNullOpt);
+ NOT_RETRANSMISSION, QUICHE_NULLOPT);
}));
stream_->OnCanWrite();
EXPECT_FALSE(stream_->HasPendingRetransmission());
@@ -1422,7 +1408,7 @@ TEST_P(QuicStreamTest, CannotBundleLostFin) {
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this]() {
return session_->ConsumeData(stream_->id(), 9u, 0u, NO_FIN,
- NOT_RETRANSMISSION, QuicheNullOpt);
+ NOT_RETRANSMISSION, QUICHE_NULLOPT);
}));
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(Return(QuicConsumedData(0, true)));
@@ -1511,7 +1497,7 @@ TEST_P(QuicStreamTest, RetransmitStreamData) {
EXPECT_CALL(*session_, WritevData(stream_->id(), 10, 0, NO_FIN, _, _))
.WillOnce(InvokeWithoutArgs([this]() {
return session_->ConsumeData(stream_->id(), 8, 0u, NO_FIN,
- NOT_RETRANSMISSION, QuicheNullOpt);
+ NOT_RETRANSMISSION, QUICHE_NULLOPT);
}));
EXPECT_FALSE(stream_->RetransmitStreamData(0, 18, true, PTO_RETRANSMISSION));
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_syscall_wrapper.cc b/chromium/net/third_party/quiche/src/quic/core/quic_syscall_wrapper.cc
new file mode 100644
index 00000000000..b2404c6ee97
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_syscall_wrapper.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/quic_syscall_wrapper.h"
+
+#include <atomic>
+#include <cerrno>
+
+namespace quic {
+namespace {
+std::atomic<QuicSyscallWrapper*> global_syscall_wrapper(new QuicSyscallWrapper);
+} // namespace
+
+ssize_t QuicSyscallWrapper::Sendmsg(int sockfd, const msghdr* msg, int flags) {
+ return ::sendmsg(sockfd, msg, flags);
+}
+
+int QuicSyscallWrapper::Sendmmsg(int sockfd,
+ mmsghdr* msgvec,
+ unsigned int vlen,
+ int flags) {
+#if defined(__linux__) && !defined(__ANDROID__)
+ return ::sendmmsg(sockfd, msgvec, vlen, flags);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+QuicSyscallWrapper* GetGlobalSyscallWrapper() {
+ return global_syscall_wrapper.load();
+}
+
+void SetGlobalSyscallWrapper(QuicSyscallWrapper* wrapper) {
+ global_syscall_wrapper.store(wrapper);
+}
+
+ScopedGlobalSyscallWrapperOverride::ScopedGlobalSyscallWrapperOverride(
+ QuicSyscallWrapper* wrapper_in_scope)
+ : original_wrapper_(GetGlobalSyscallWrapper()) {
+ SetGlobalSyscallWrapper(wrapper_in_scope);
+}
+
+ScopedGlobalSyscallWrapperOverride::~ScopedGlobalSyscallWrapperOverride() {
+ SetGlobalSyscallWrapper(original_wrapper_);
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_syscall_wrapper.h b/chromium/net/third_party/quiche/src/quic/core/quic_syscall_wrapper.h
new file mode 100644
index 00000000000..3a80ac6f6cf
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_syscall_wrapper.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_PLATFORM_IMPL_QUIC_SYSCALL_WRAPPER_H_
+#define QUICHE_QUIC_PLATFORM_IMPL_QUIC_SYSCALL_WRAPPER_H_
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+
+struct mmsghdr;
+namespace quic {
+
+// QuicSyscallWrapper is a pass-through proxy to the real syscalls.
+class QUIC_EXPORT_PRIVATE QuicSyscallWrapper {
+ public:
+ virtual ~QuicSyscallWrapper() = default;
+
+ virtual ssize_t Sendmsg(int sockfd, const msghdr* msg, int flags);
+
+ virtual int Sendmmsg(int sockfd,
+ mmsghdr* msgvec,
+ unsigned int vlen,
+ int flags);
+};
+
+// A global instance of QuicSyscallWrapper, used by some socket util functions.
+QuicSyscallWrapper* GetGlobalSyscallWrapper();
+
+// Change the global QuicSyscallWrapper to |wrapper|, for testing.
+void SetGlobalSyscallWrapper(QuicSyscallWrapper* wrapper);
+
+// ScopedGlobalSyscallWrapperOverride changes the global QuicSyscallWrapper
+// during its lifetime, for testing.
+class QUIC_EXPORT_PRIVATE ScopedGlobalSyscallWrapperOverride {
+ public:
+ explicit ScopedGlobalSyscallWrapperOverride(
+ QuicSyscallWrapper* wrapper_in_scope);
+ ~ScopedGlobalSyscallWrapperOverride();
+
+ private:
+ QuicSyscallWrapper* original_wrapper_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_PLATFORM_IMPL_QUIC_SYSCALL_WRAPPER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_tag.cc b/chromium/net/third_party/quiche/src/quic/core/quic_tag.cc
index 270383d27ae..d6c2f6c25de 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_tag.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_tag.cc
@@ -74,4 +74,35 @@ bool ContainsQuicTag(const QuicTagVector& tag_vector, QuicTag tag) {
tag_vector.end();
}
+QuicTag ParseQuicTag(quiche::QuicheStringPiece tag_string) {
+ quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&tag_string);
+ std::string tag_bytes;
+ if (tag_string.length() == 8) {
+ tag_bytes = quiche::QuicheTextUtils::HexDecode(tag_string);
+ tag_string = tag_bytes;
+ }
+ QuicTag tag = 0;
+ // Iterate over every character from right to left.
+ for (auto it = tag_string.rbegin(); it != tag_string.rend(); ++it) {
+ // The cast here is required on platforms where char is signed.
+ unsigned char token_char = static_cast<unsigned char>(*it);
+ tag <<= 8;
+ tag |= token_char;
+ }
+ return tag;
+}
+
+QuicTagVector ParseQuicTagVector(quiche::QuicheStringPiece tags_string) {
+ QuicTagVector tag_vector;
+ quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&tags_string);
+ if (!tags_string.empty()) {
+ std::vector<quiche::QuicheStringPiece> tag_strings =
+ quiche::QuicheTextUtils::Split(tags_string, ',');
+ for (quiche::QuicheStringPiece tag_string : tag_strings) {
+ tag_vector.push_back(ParseQuicTag(tag_string));
+ }
+ }
+ return tag_vector;
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_tag.h b/chromium/net/third_party/quiche/src/quic/core/quic_tag.h
index 71fcdd597f4..7ba6cfc5f39 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_tag.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_tag.h
@@ -10,6 +10,7 @@
#include <vector>
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
namespace quic {
@@ -48,6 +49,17 @@ QUIC_EXPORT_PRIVATE bool FindMutualQuicTag(const QuicTagVector& our_tags,
// treat it as a number if not.
QUIC_EXPORT_PRIVATE std::string QuicTagToString(QuicTag tag);
+// Utility function that converts a string of the form "ABCD" to its
+// corresponding QuicTag. Note that tags that are less than four characters
+// long are right-padded with zeroes. Tags that contain non-ASCII characters
+// are represented as 8-character-long hexadecimal strings.
+QUIC_EXPORT_PRIVATE QuicTag ParseQuicTag(quiche::QuicheStringPiece tag_string);
+
+// Utility function that converts a string of the form "ABCD,EFGH" to a vector
+// of the form {kABCD,kEFGH}. Note the caveats on ParseQuicTag.
+QUIC_EXPORT_PRIVATE QuicTagVector
+ParseQuicTagVector(quiche::QuicheStringPiece tags_string);
+
} // namespace quic
#endif // QUICHE_QUIC_CORE_QUIC_TAG_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_tag_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_tag_test.cc
index 3d58133eeb7..13c899edd41 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_tag_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_tag_test.cc
@@ -33,6 +33,48 @@ TEST_F(QuicTagTest, MakeQuicTag) {
EXPECT_EQ('D', bytes[3]);
}
+TEST_F(QuicTagTest, ParseQuicTag) {
+ QuicTag tag_abcd = MakeQuicTag('A', 'B', 'C', 'D');
+ EXPECT_EQ(ParseQuicTag("ABCD"), tag_abcd);
+ EXPECT_EQ(ParseQuicTag("ABCDE"), tag_abcd);
+ QuicTag tag_efgh = MakeQuicTag('E', 'F', 'G', 'H');
+ EXPECT_EQ(ParseQuicTag("EFGH"), tag_efgh);
+ QuicTag tag_ijk = MakeQuicTag('I', 'J', 'K', 0);
+ EXPECT_EQ(ParseQuicTag("IJK"), tag_ijk);
+ QuicTag tag_l = MakeQuicTag('L', 0, 0, 0);
+ EXPECT_EQ(ParseQuicTag("L"), tag_l);
+ QuicTag tag_hex = MakeQuicTag('M', 'N', 'O', static_cast<char>(255));
+ EXPECT_EQ(ParseQuicTag("4d4e4fff"), tag_hex);
+ EXPECT_EQ(ParseQuicTag("4D4E4FFF"), tag_hex);
+ QuicTag tag_with_numbers = MakeQuicTag('P', 'Q', '1', '2');
+ EXPECT_EQ(ParseQuicTag("PQ12"), tag_with_numbers);
+ QuicTag tag_with_custom_chars = MakeQuicTag('r', '$', '_', '7');
+ EXPECT_EQ(ParseQuicTag("r$_7"), tag_with_custom_chars);
+ QuicTag tag_zero = 0;
+ EXPECT_EQ(ParseQuicTag(""), tag_zero);
+ QuicTagVector tag_vector;
+ EXPECT_EQ(ParseQuicTagVector(""), tag_vector);
+ EXPECT_EQ(ParseQuicTagVector(" "), tag_vector);
+ tag_vector.push_back(tag_abcd);
+ EXPECT_EQ(ParseQuicTagVector("ABCD"), tag_vector);
+ tag_vector.push_back(tag_efgh);
+ EXPECT_EQ(ParseQuicTagVector("ABCD,EFGH"), tag_vector);
+ tag_vector.push_back(tag_ijk);
+ EXPECT_EQ(ParseQuicTagVector("ABCD,EFGH,IJK"), tag_vector);
+ tag_vector.push_back(tag_l);
+ EXPECT_EQ(ParseQuicTagVector("ABCD,EFGH,IJK,L"), tag_vector);
+ tag_vector.push_back(tag_hex);
+ EXPECT_EQ(ParseQuicTagVector("ABCD,EFGH,IJK,L,4d4e4fff"), tag_vector);
+ tag_vector.push_back(tag_with_numbers);
+ EXPECT_EQ(ParseQuicTagVector("ABCD,EFGH,IJK,L,4d4e4fff,PQ12"), tag_vector);
+ tag_vector.push_back(tag_with_custom_chars);
+ EXPECT_EQ(ParseQuicTagVector("ABCD,EFGH,IJK,L,4d4e4fff,PQ12,r$_7"),
+ tag_vector);
+ tag_vector.push_back(tag_zero);
+ EXPECT_EQ(ParseQuicTagVector("ABCD,EFGH,IJK,L,4d4e4fff,PQ12,r$_7,"),
+ tag_vector);
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time.h b/chromium/net/third_party/quiche/src/quic/core/quic_time.h
index adecbcd1514..079b59a6bdc 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_time.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_time.h
@@ -184,6 +184,14 @@ class QUIC_EXPORT_PRIVATE QuicWallTime {
QUIC_TIME_WARN_UNUSED_RESULT QuicWallTime
Subtract(QuicTime::Delta delta) const;
+ bool operator==(const QuicWallTime& other) const {
+ return microseconds_ == other.microseconds_;
+ }
+
+ QuicTime::Delta operator-(const QuicWallTime& rhs) const {
+ return QuicTime::Delta::FromMicroseconds(microseconds_ - rhs.microseconds_);
+ }
+
private:
explicit constexpr QuicWallTime(uint64_t microseconds)
: microseconds_(microseconds) {}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc b/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc
index edbce0c709c..eeaf297c1ca 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc
@@ -64,6 +64,7 @@ void QuicTraceVisitor::OnPacketSent(const SerializedPacket& serialized_packet,
case BLOCKED_FRAME:
case PING_FRAME:
case HANDSHAKE_DONE_FRAME:
+ case ACK_FREQUENCY_FRAME:
PopulateFrameInfo(frame, event->add_frames());
break;
@@ -218,6 +219,7 @@ void QuicTraceVisitor::PopulateFrameInfo(const QuicFrame& frame,
case MESSAGE_FRAME:
case CRYPTO_FRAME:
case NEW_TOKEN_FRAME:
+ case ACK_FREQUENCY_FRAME:
break;
case NUM_FRAME_TYPES:
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_types.cc b/chromium/net/third_party/quiche/src/quic/core/quic_types.cc
index 36614cd8f0a..a52571e3905 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_types.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_types.cc
@@ -173,8 +173,7 @@ std::string TransmissionTypeToString(TransmissionType transmission_type) {
switch (transmission_type) {
RETURN_STRING_LITERAL(NOT_RETRANSMISSION);
RETURN_STRING_LITERAL(HANDSHAKE_RETRANSMISSION);
- RETURN_STRING_LITERAL(ALL_UNACKED_RETRANSMISSION);
- RETURN_STRING_LITERAL(ALL_INITIAL_RETRANSMISSION);
+ RETURN_STRING_LITERAL(ALL_ZERO_RTT_RETRANSMISSION);
RETURN_STRING_LITERAL(LOSS_RETRANSMISSION);
RETURN_STRING_LITERAL(RTO_RETRANSMISSION);
RETURN_STRING_LITERAL(TLP_RETRANSMISSION);
@@ -191,6 +190,11 @@ std::string TransmissionTypeToString(TransmissionType transmission_type) {
}
}
+std::ostream& operator<<(std::ostream& os, TransmissionType transmission_type) {
+ os << TransmissionTypeToString(transmission_type);
+ return os;
+}
+
std::string PacketHeaderFormatToString(PacketHeaderFormat format) {
switch (format) {
RETURN_STRING_LITERAL(IETF_QUIC_LONG_HEADER_PACKET);
@@ -261,11 +265,17 @@ std::string SerializedPacketFateToString(SerializedPacketFate fate) {
RETURN_STRING_LITERAL(BUFFER);
RETURN_STRING_LITERAL(SEND_TO_WRITER);
RETURN_STRING_LITERAL(FAILED_TO_WRITE_COALESCED_PACKET);
+ RETURN_STRING_LITERAL(LEGACY_VERSION_ENCAPSULATE);
default:
return quiche::QuicheStrCat("Unknown(", static_cast<int>(fate), ")");
}
}
+std::ostream& operator<<(std::ostream& os, SerializedPacketFate fate) {
+ os << SerializedPacketFateToString(fate);
+ return os;
+}
+
std::string EncryptionLevelToString(EncryptionLevel level) {
switch (level) {
RETURN_STRING_LITERAL(ENCRYPTION_INITIAL);
@@ -278,6 +288,11 @@ std::string EncryptionLevelToString(EncryptionLevel level) {
}
}
+std::ostream& operator<<(std::ostream& os, EncryptionLevel level) {
+ os << EncryptionLevelToString(level);
+ return os;
+}
+
std::string QuicConnectionCloseTypeString(QuicConnectionCloseType type) {
switch (type) {
RETURN_STRING_LITERAL(GOOGLE_QUIC_CONNECTION_CLOSE);
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_types.h b/chromium/net/third_party/quiche/src/quic/core/quic_types.h
index f2919ef3766..0c736f93178 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_types.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_types.h
@@ -163,21 +163,24 @@ struct QUIC_EXPORT_PRIVATE WriteResult {
enum TransmissionType : int8_t {
NOT_RETRANSMISSION,
FIRST_TRANSMISSION_TYPE = NOT_RETRANSMISSION,
- HANDSHAKE_RETRANSMISSION, // Retransmits due to handshake timeouts.
- // TODO(fayang): remove ALL_UNACKED_RETRANSMISSION.
- ALL_UNACKED_RETRANSMISSION, // Retransmits all unacked packets.
- ALL_INITIAL_RETRANSMISSION, // Retransmits all initially encrypted packets.
- LOSS_RETRANSMISSION, // Retransmits due to loss detection.
- RTO_RETRANSMISSION, // Retransmits due to retransmit time out.
- TLP_RETRANSMISSION, // Tail loss probes.
- PTO_RETRANSMISSION, // Retransmission due to probe timeout.
- PROBING_RETRANSMISSION, // Retransmission in order to probe bandwidth.
+ HANDSHAKE_RETRANSMISSION, // Retransmits due to handshake timeouts.
+ ALL_ZERO_RTT_RETRANSMISSION, // Retransmits all packets encrypted with 0-RTT
+ // key.
+ LOSS_RETRANSMISSION, // Retransmits due to loss detection.
+ RTO_RETRANSMISSION, // Retransmits due to retransmit time out.
+ TLP_RETRANSMISSION, // Tail loss probes.
+ PTO_RETRANSMISSION, // Retransmission due to probe timeout.
+ PROBING_RETRANSMISSION, // Retransmission in order to probe bandwidth.
LAST_TRANSMISSION_TYPE = PROBING_RETRANSMISSION,
};
QUIC_EXPORT_PRIVATE std::string TransmissionTypeToString(
TransmissionType transmission_type);
+QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+ std::ostream& os,
+ TransmissionType transmission_type);
+
enum HasRetransmittableData : uint8_t {
NO_RETRANSMITTABLE_DATA,
HAS_RETRANSMITTABLE_DATA,
@@ -224,6 +227,8 @@ enum QuicFrameType : uint8_t {
STOP_WAITING_FRAME = 6,
PING_FRAME = 7,
CRYPTO_FRAME = 8,
+ // TODO(b/157935330): stop hard coding this when deprecate T050.
+ HANDSHAKE_DONE_FRAME = 9,
// STREAM and ACK frames are special frames. They are encoded differently on
// the wire and their values do not need to be stable.
@@ -245,7 +250,7 @@ enum QuicFrameType : uint8_t {
MESSAGE_FRAME,
NEW_TOKEN_FRAME,
RETIRE_CONNECTION_ID_FRAME,
- HANDSHAKE_DONE_FRAME,
+ ACK_FREQUENCY_FRAME,
NUM_FRAME_TYPES
};
@@ -305,6 +310,9 @@ enum QuicIetfFrameType : uint8_t {
IETF_EXTENSION_MESSAGE = 0x21,
IETF_EXTENSION_MESSAGE_NO_LENGTH_V99 = 0x30,
IETF_EXTENSION_MESSAGE_V99 = 0x31,
+
+ // An QUIC extension frame for sender control of acknowledgement delays
+ IETF_ACK_FREQUENCY = 0xaf
};
QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
const QuicIetfFrameType& c);
@@ -440,6 +448,9 @@ inline bool EncryptionLevelIsValid(EncryptionLevel level) {
QUIC_EXPORT_PRIVATE std::string EncryptionLevelToString(EncryptionLevel level);
+QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
+ EncryptionLevel level);
+
// Enumeration of whether a server endpoint will request a client certificate,
// and whether that endpoint requires a valid client certificate to establish a
// connection.
@@ -687,11 +698,16 @@ enum SerializedPacketFate : uint8_t {
SEND_TO_WRITER, // Send packet to writer.
FAILED_TO_WRITE_COALESCED_PACKET, // Packet cannot be coalesced, error occurs
// when sending existing coalesced packet.
+ LEGACY_VERSION_ENCAPSULATE, // Perform Legacy Version Encapsulation on this
+ // packet.
};
QUIC_EXPORT_PRIVATE std::string SerializedPacketFateToString(
SerializedPacketFate fate);
+QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
+ const SerializedPacketFate fate);
+
// There are three different forms of CONNECTION_CLOSE.
enum QuicConnectionCloseType {
GOOGLE_QUIC_CONNECTION_CLOSE = 0,
@@ -734,6 +750,45 @@ struct QUIC_NO_EXPORT NextReleaseTimeResult {
bool allow_burst;
};
+// QuicPacketBuffer bundles a buffer and a function that releases it. Note
+// it does not assume ownership of buffer, i.e. it doesn't release the buffer on
+// destruction.
+struct QUIC_NO_EXPORT QuicPacketBuffer {
+ QuicPacketBuffer() = default;
+
+ QuicPacketBuffer(char* buffer,
+ std::function<void(const char*)> release_buffer)
+ : buffer(buffer), release_buffer(std::move(release_buffer)) {}
+
+ char* buffer = nullptr;
+ std::function<void(const char*)> release_buffer;
+};
+
+// QuicOwnedPacketBuffer is a QuicPacketBuffer that assumes buffer ownership.
+struct QUIC_NO_EXPORT QuicOwnedPacketBuffer : public QuicPacketBuffer {
+ QuicOwnedPacketBuffer(const QuicOwnedPacketBuffer&) = delete;
+ QuicOwnedPacketBuffer& operator=(const QuicOwnedPacketBuffer&) = delete;
+
+ QuicOwnedPacketBuffer(char* buffer,
+ std::function<void(const char*)> release_buffer)
+ : QuicPacketBuffer(buffer, std::move(release_buffer)) {}
+
+ QuicOwnedPacketBuffer(QuicOwnedPacketBuffer&& owned_buffer)
+ : QuicPacketBuffer(std::move(owned_buffer)) {
+ // |owned_buffer| does not own a buffer any more.
+ owned_buffer.buffer = nullptr;
+ }
+
+ explicit QuicOwnedPacketBuffer(QuicPacketBuffer&& packet_buffer)
+ : QuicPacketBuffer(std::move(packet_buffer)) {}
+
+ ~QuicOwnedPacketBuffer() {
+ if (release_buffer != nullptr && buffer != nullptr) {
+ release_buffer(buffer);
+ }
+ }
+};
+
} // namespace quic
#endif // QUICHE_QUIC_CORE_QUIC_TYPES_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket.h b/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket.h
index 04f84357dab..258de080118 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket.h
@@ -163,10 +163,14 @@ class QUIC_EXPORT_PRIVATE QuicUdpSocketApi {
public:
// Creates a non-blocking udp socket, sets the receive/send buffer and enable
// receiving of self ip addresses on read.
- // Return kQuicInvalidSocketFd if failed.
+ // If address_family == AF_INET6 and ipv6_only is true, receiving of IPv4 self
+ // addresses is disabled. This is only necessary for IPv6 sockets on iOS - all
+ // other platforms can ignore this parameter. Return kQuicInvalidSocketFd if
+ // failed.
QuicUdpSocketFd Create(int address_family,
int receive_buffer_size,
- int send_buffer_size);
+ int send_buffer_size,
+ bool ipv6_only = false);
// Closes |fd|. No-op if |fd| equals to kQuicInvalidSocketFd.
void Destroy(QuicUdpSocketFd fd);
@@ -238,7 +242,8 @@ class QUIC_EXPORT_PRIVATE QuicUdpSocketApi {
bool SetupSocket(QuicUdpSocketFd fd,
int address_family,
int receive_buffer_size,
- int send_buffer_size);
+ int send_buffer_size,
+ bool ipv6_only);
bool EnableReceiveSelfIpAddressForV4(QuicUdpSocketFd fd);
bool EnableReceiveSelfIpAddressForV6(QuicUdpSocketFd fd);
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_posix.cc b/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_posix.cc
index b6c58cdb1d3..c5ab345f433 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_posix.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_posix.cc
@@ -239,7 +239,8 @@ bool NextCmsg(msghdr* hdr,
QuicUdpSocketFd QuicUdpSocketApi::Create(int address_family,
int receive_buffer_size,
- int send_buffer_size) {
+ int send_buffer_size,
+ bool ipv6_only) {
// DCHECK here so the program exits early(before reading packets) in debug
// mode. This should have been a static_assert, however it can't be done on
// ios/osx because CMSG_SPACE isn't a constant expression there.
@@ -250,7 +251,8 @@ QuicUdpSocketFd QuicUdpSocketApi::Create(int address_family,
return kQuicInvalidSocketFd;
}
- if (!SetupSocket(fd, address_family, receive_buffer_size, send_buffer_size)) {
+ if (!SetupSocket(fd, address_family, receive_buffer_size, send_buffer_size,
+ ipv6_only)) {
Destroy(fd);
return kQuicInvalidSocketFd;
}
@@ -261,7 +263,8 @@ QuicUdpSocketFd QuicUdpSocketApi::Create(int address_family,
bool QuicUdpSocketApi::SetupSocket(QuicUdpSocketFd fd,
int address_family,
int receive_buffer_size,
- int send_buffer_size) {
+ int send_buffer_size,
+ bool ipv6_only) {
// Receive buffer size.
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &receive_buffer_size,
sizeof(receive_buffer_size)) != 0) {
@@ -276,14 +279,20 @@ bool QuicUdpSocketApi::SetupSocket(QuicUdpSocketFd fd,
return false;
}
- if (!EnableReceiveSelfIpAddressForV4(fd)) {
- QUIC_LOG_FIRST_N(ERROR, 100) << "Failed to enable receiving of self v4 ip";
- return false;
+ if (!(address_family == AF_INET6 && ipv6_only)) {
+ if (!EnableReceiveSelfIpAddressForV4(fd)) {
+ QUIC_LOG_FIRST_N(ERROR, 100)
+ << "Failed to enable receiving of self v4 ip";
+ return false;
+ }
}
- if (address_family == AF_INET6 && !EnableReceiveSelfIpAddressForV6(fd)) {
- QUIC_LOG_FIRST_N(ERROR, 100) << "Failed to enable receiving of self v6 ip";
- return false;
+ if (address_family == AF_INET6) {
+ if (!EnableReceiveSelfIpAddressForV6(fd)) {
+ QUIC_LOG_FIRST_N(ERROR, 100)
+ << "Failed to enable receiving of self v6 ip";
+ return false;
+ }
}
return true;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_test.cc
index e43fb10c40b..f54b0edd073 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_test.cc
@@ -3,6 +3,11 @@
// found in the LICENSE file.
#include "net/third_party/quiche/src/quic/core/quic_udp_socket.h"
+#include <sys/socket.h>
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
#include "net/third_party/quiche/src/quic/core/quic_constants.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
@@ -15,33 +20,49 @@ struct ReadBuffers {
char control_buffer[512];
char packet_buffer[1536];
};
+
+// Allows IPv6-specific testing.
+struct TestParameters {
+ // If true, the test will only use IPv6. If false, IPv4 will be used if
+ // possible, with IPv6 used as a fallback.
+ bool force_ipv6;
+ // The value of ipv6_only to be used in QuicUdpSocketApi::Create calls.
+ bool ipv6_only;
+};
} // namespace
-class QuicUdpSocketTest : public QuicTest {
+class QuicUdpSocketTest : public QuicTestWithParam<TestParameters> {
protected:
void SetUp() override {
- // Try creating AF_INET socket, if it fails because of unsupported address
- // family then tests are being run under IPv6-only environment, initialize
- // address family to use for running the test under as AF_INET6 otherwise
- // initialize it as AF_INET.
- address_family_ = AF_INET;
- fd_client_ =
- api_.Create(address_family_,
- /*receive_buffer_size =*/kDefaultSocketReceiveBuffer,
- /*send_buffer_size =*/kDefaultSocketReceiveBuffer);
+ const TestParameters& parameters = GetParam();
+ if (!parameters.force_ipv6) {
+ // Try creating AF_INET socket, if it fails because of unsupported address
+ // family then tests are being run under IPv6-only environment, initialize
+ // address family to use for running the test under as AF_INET6 otherwise
+ // initialize it as AF_INET.
+ address_family_ = AF_INET;
+ fd_client_ =
+ api_.Create(address_family_,
+ /*receive_buffer_size =*/kDefaultSocketReceiveBuffer,
+ /*send_buffer_size =*/kDefaultSocketReceiveBuffer,
+ /*ipv6_only =*/parameters.ipv6_only);
+ }
if (fd_client_ == kQuicInvalidSocketFd) {
+ // Either AF_INET is unsupported, or force_ipv6 is true.
address_family_ = AF_INET6;
fd_client_ =
api_.Create(address_family_,
/*receive_buffer_size =*/kDefaultSocketReceiveBuffer,
- /*send_buffer_size =*/kDefaultSocketReceiveBuffer);
+ /*send_buffer_size =*/kDefaultSocketReceiveBuffer,
+ /*ipv6_only =*/parameters.ipv6_only);
}
ASSERT_NE(fd_client_, kQuicInvalidSocketFd);
fd_server_ =
api_.Create(address_family_,
/*receive_buffer_size =*/kDefaultSocketReceiveBuffer,
- /*send_buffer_size =*/kDefaultSocketReceiveBuffer);
+ /*send_buffer_size =*/kDefaultSocketReceiveBuffer,
+ /*ipv6_only =*/parameters.ipv6_only);
ASSERT_NE(fd_server_, kQuicInvalidSocketFd);
ASSERT_TRUE(
@@ -114,8 +135,8 @@ class QuicUdpSocketTest : public QuicTest {
}
QuicUdpSocketApi api_;
- QuicUdpSocketFd fd_client_;
- QuicUdpSocketFd fd_server_;
+ QuicUdpSocketFd fd_client_ = kQuicInvalidSocketFd;
+ QuicUdpSocketFd fd_server_ = kQuicInvalidSocketFd;
QuicSocketAddress server_address_;
int address_family_;
char client_packet_buffer_[kEthernetMTU] = {0};
@@ -123,7 +144,22 @@ class QuicUdpSocketTest : public QuicTest {
char server_control_buffer_[512] = {0};
};
-TEST_F(QuicUdpSocketTest, ReadPacketResultReset) {
+INSTANTIATE_TEST_SUITE_P(
+ PlatformIndependent,
+ QuicUdpSocketTest,
+ testing::Values(TestParameters{/*force_ipv6 =*/false, /*ipv6_only =*/false},
+ TestParameters{/*force_ipv6 =*/false, /*ipv6_only =*/true},
+ TestParameters{/*force_ipv6 =*/true, /*ipv6_only =*/true}));
+
+#ifndef TARGET_OS_IPHONE
+// IPv6 on iOS is known to fail without ipv6_only, so should not be tested.
+INSTANTIATE_TEST_SUITE_P(NonIos,
+ QuicUdpSocketTest,
+ testing::Values(TestParameters{/*force_ipv6 =*/true,
+ /*ipv6_only =*/false}));
+#endif
+
+TEST_P(QuicUdpSocketTest, ReadPacketResultReset) {
QuicUdpSocketApi::ReadPacketResult result;
result.packet_info.SetDroppedPackets(100);
result.packet_buffer.buffer_len = 100;
@@ -137,7 +173,7 @@ TEST_F(QuicUdpSocketTest, ReadPacketResultReset) {
EXPECT_EQ(200u, result.packet_buffer.buffer_len);
}
-TEST_F(QuicUdpSocketTest, ReadPacketOnly) {
+TEST_P(QuicUdpSocketTest, ReadPacketOnly) {
const size_t kPacketSize = 512;
memset(client_packet_buffer_, '-', kPacketSize);
ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize),
@@ -150,7 +186,7 @@ TEST_F(QuicUdpSocketTest, ReadPacketOnly) {
ASSERT_EQ(0, ComparePacketBuffers(kPacketSize));
}
-TEST_F(QuicUdpSocketTest, ReadTruncated) {
+TEST_P(QuicUdpSocketTest, ReadTruncated) {
const size_t kPacketSize = kDefaultMaxPacketSize + 1;
memset(client_packet_buffer_, '*', kPacketSize);
ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize),
@@ -161,7 +197,7 @@ TEST_F(QuicUdpSocketTest, ReadTruncated) {
ASSERT_FALSE(read_result.ok);
}
-TEST_F(QuicUdpSocketTest, ReadDroppedPackets) {
+TEST_P(QuicUdpSocketTest, ReadDroppedPackets) {
const size_t kPacketSize = kDefaultMaxPacketSize;
memset(client_packet_buffer_, '-', kPacketSize);
ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize),
@@ -193,7 +229,7 @@ TEST_F(QuicUdpSocketTest, ReadDroppedPackets) {
}
}
-TEST_F(QuicUdpSocketTest, ReadSelfIp) {
+TEST_P(QuicUdpSocketTest, ReadSelfIp) {
const QuicUdpPacketInfoBit self_ip_bit =
(address_family_ == AF_INET) ? QuicUdpPacketInfoBit::V4_SELF_IP
: QuicUdpPacketInfoBit::V6_SELF_IP;
@@ -214,7 +250,7 @@ TEST_F(QuicUdpSocketTest, ReadSelfIp) {
: read_result.packet_info.self_v6_ip());
}
-TEST_F(QuicUdpSocketTest, ReadReceiveTimestamp) {
+TEST_P(QuicUdpSocketTest, ReadReceiveTimestamp) {
const size_t kPacketSize = kDefaultMaxPacketSize;
memset(client_packet_buffer_, '-', kPacketSize);
ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize),
@@ -249,7 +285,7 @@ TEST_F(QuicUdpSocketTest, ReadReceiveTimestamp) {
QuicWallTime::FromUNIXSeconds(1577836800).IsBefore(recv_timestamp));
}
-TEST_F(QuicUdpSocketTest, Ttl) {
+TEST_P(QuicUdpSocketTest, Ttl) {
const size_t kPacketSize = 512;
memset(client_packet_buffer_, '$', kPacketSize);
ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize),
@@ -282,7 +318,7 @@ TEST_F(QuicUdpSocketTest, Ttl) {
EXPECT_EQ(13, read_result.packet_info.ttl());
}
-TEST_F(QuicUdpSocketTest, ReadMultiplePackets) {
+TEST_P(QuicUdpSocketTest, ReadMultiplePackets) {
const QuicUdpPacketInfoBit self_ip_bit =
(address_family_ == AF_INET) ? QuicUdpPacketInfoBit::V4_SELF_IP
: QuicUdpPacketInfoBit::V6_SELF_IP;
@@ -335,7 +371,7 @@ TEST_F(QuicUdpSocketTest, ReadMultiplePackets) {
}
}
-TEST_F(QuicUdpSocketTest, ReadMultiplePacketsSomeTruncated) {
+TEST_P(QuicUdpSocketTest, ReadMultiplePacketsSomeTruncated) {
const QuicUdpPacketInfoBit self_ip_bit =
(address_family_ == AF_INET) ? QuicUdpPacketInfoBit::V4_SELF_IP
: QuicUdpPacketInfoBit::V6_SELF_IP;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc
index 8276f1c287c..f06d0746e40 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc
@@ -28,6 +28,7 @@ QuicUnackedPacketMap::QuicUnackedPacketMap(Perspective perspective)
: perspective_(perspective),
least_unacked_(FirstSendingPacketNumber()),
bytes_in_flight_(0),
+ bytes_in_flight_per_packet_number_space_{0, 0, 0},
packets_in_flight_(0),
last_inflight_packet_sent_time_(QuicTime::Zero()),
last_inflight_packets_sent_time_{{QuicTime::Zero()},
@@ -72,6 +73,7 @@ void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* packet,
const PacketNumberSpace packet_number_space =
GetPacketNumberSpace(info.encryption_level);
bytes_in_flight_ += bytes_sent;
+ bytes_in_flight_per_packet_number_space_[packet_number_space] += bytes_sent;
++packets_in_flight_;
info.in_flight = true;
largest_sent_retransmittable_packets_[packet_number_space] = packet_number;
@@ -195,6 +197,27 @@ void QuicUnackedPacketMap::RemoveFromInFlight(QuicTransmissionInfo* info) {
QUIC_BUG_IF(packets_in_flight_ == 0);
bytes_in_flight_ -= info->bytes_sent;
--packets_in_flight_;
+
+ const PacketNumberSpace packet_number_space =
+ GetPacketNumberSpace(info->encryption_level);
+ if (bytes_in_flight_per_packet_number_space_[packet_number_space] <
+ info->bytes_sent) {
+ QUIC_BUG << "bytes_in_flight: "
+ << bytes_in_flight_per_packet_number_space_[packet_number_space]
+ << " is smaller than bytes_sent: " << info->bytes_sent
+ << " for packet number space: "
+ << PacketNumberSpaceToString(packet_number_space);
+ bytes_in_flight_per_packet_number_space_[packet_number_space] = 0;
+ } else {
+ bytes_in_flight_per_packet_number_space_[packet_number_space] -=
+ info->bytes_sent;
+ }
+ if (GetQuicReloadableFlag(quic_fix_last_inflight_packets_sent_time) &&
+ bytes_in_flight_per_packet_number_space_[packet_number_space] == 0) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_fix_last_inflight_packets_sent_time);
+ last_inflight_packets_sent_time_[packet_number_space] = QuicTime::Zero();
+ }
+
info->in_flight = false;
}
}
@@ -230,7 +253,12 @@ QuicUnackedPacketMap::NeuterUnencryptedPackets() {
}
}
if (supports_multiple_packet_number_spaces_) {
- last_inflight_packets_sent_time_[INITIAL_DATA] = QuicTime::Zero();
+ if (GetQuicReloadableFlag(quic_fix_last_inflight_packets_sent_time)) {
+ DCHECK_EQ(QuicTime::Zero(),
+ last_inflight_packets_sent_time_[INITIAL_DATA]);
+ } else {
+ last_inflight_packets_sent_time_[INITIAL_DATA] = QuicTime::Zero();
+ }
}
return neutered_packets;
}
@@ -254,7 +282,12 @@ QuicUnackedPacketMap::NeuterHandshakePackets() {
}
}
if (supports_multiple_packet_number_spaces()) {
- last_inflight_packets_sent_time_[HANDSHAKE_DATA] = QuicTime::Zero();
+ if (GetQuicReloadableFlag(quic_fix_last_inflight_packets_sent_time)) {
+ DCHECK_EQ(QuicTime::Zero(),
+ last_inflight_packets_sent_time_[HANDSHAKE_DATA]);
+ } else {
+ last_inflight_packets_sent_time_[HANDSHAKE_DATA] = QuicTime::Zero();
+ }
}
return neutered_packets;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h
index bcf5061927a..43e900802f4 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h
@@ -281,6 +281,9 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap {
QuicPacketNumber least_unacked_;
QuicByteCount bytes_in_flight_;
+ // Bytes in flight per packet number space.
+ QuicByteCount
+ bytes_in_flight_per_packet_number_space_[NUM_PACKET_NUMBER_SPACES];
QuicPacketCount packets_in_flight_;
// Time that the last inflight packet was sent.
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc b/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc
index 60354f332fa..de4350390b0 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc
@@ -6,6 +6,7 @@
#include <algorithm>
#include <cstdint>
+#include <cstring>
#include <string>
#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
@@ -335,8 +336,7 @@ bool QuicUtils::ContainsFrameType(const QuicFrames& frames,
SentPacketState QuicUtils::RetransmissionTypeToPacketState(
TransmissionType retransmission_type) {
switch (retransmission_type) {
- case ALL_UNACKED_RETRANSMISSION:
- case ALL_INITIAL_RETRANSMISSION:
+ case ALL_ZERO_RTT_RETRANSMISSION:
return UNACKABLE;
case HANDSHAKE_RETRANSMISSION:
return HANDSHAKE_RETRANSMITTED;
@@ -351,8 +351,7 @@ SentPacketState QuicUtils::RetransmissionTypeToPacketState(
case PROBING_RETRANSMISSION:
return PROBE_RETRANSMITTED;
default:
- QUIC_BUG << TransmissionTypeToString(retransmission_type)
- << " is not a retransmission_type";
+ QUIC_BUG << retransmission_type << " is not a retransmission_type";
return UNACKABLE;
}
}
@@ -429,15 +428,21 @@ bool QuicUtils::IsOutgoingStreamId(ParsedQuicVersion version,
}
// static
-bool QuicUtils::IsBidirectionalStreamId(QuicStreamId id) {
+bool QuicUtils::IsBidirectionalStreamId(QuicStreamId id,
+ ParsedQuicVersion version) {
+ DCHECK(!GetQuicReloadableFlag(quic_fix_gquic_stream_type) ||
+ version.HasIetfQuicFrames());
return id % 4 < 2;
}
// static
StreamType QuicUtils::GetStreamType(QuicStreamId id,
Perspective perspective,
- bool peer_initiated) {
- if (IsBidirectionalStreamId(id)) {
+ bool peer_initiated,
+ ParsedQuicVersion version) {
+ DCHECK(!GetQuicReloadableFlag(quic_fix_gquic_stream_type) ||
+ version.HasIetfQuicFrames());
+ if (IsBidirectionalStreamId(id, version)) {
return BIDIRECTIONAL;
}
@@ -491,11 +496,37 @@ QuicStreamId QuicUtils::GetFirstUnidirectionalStreamId(
// static
QuicConnectionId QuicUtils::CreateReplacementConnectionId(
- QuicConnectionId connection_id) {
- const uint64_t connection_id_hash = FNV1a_64_Hash(
+ const QuicConnectionId& connection_id) {
+ return CreateReplacementConnectionId(connection_id,
+ kQuicDefaultConnectionIdLength);
+}
+
+// static
+QuicConnectionId QuicUtils::CreateReplacementConnectionId(
+ const QuicConnectionId& connection_id,
+ uint8_t expected_connection_id_length) {
+ if (expected_connection_id_length == 0) {
+ return EmptyQuicConnectionId();
+ }
+ const uint64_t connection_id_hash64 = FNV1a_64_Hash(
+ quiche::QuicheStringPiece(connection_id.data(), connection_id.length()));
+ if (expected_connection_id_length <= sizeof(uint64_t)) {
+ return QuicConnectionId(
+ reinterpret_cast<const char*>(&connection_id_hash64),
+ expected_connection_id_length);
+ }
+ char new_connection_id_data[255] = {};
+ const QuicUint128 connection_id_hash128 = FNV1a_128_Hash(
quiche::QuicheStringPiece(connection_id.data(), connection_id.length()));
- return QuicConnectionId(reinterpret_cast<const char*>(&connection_id_hash),
- sizeof(connection_id_hash));
+ static_assert(sizeof(connection_id_hash64) + sizeof(connection_id_hash128) <=
+ sizeof(new_connection_id_data),
+ "bad size");
+ memcpy(new_connection_id_data, &connection_id_hash64,
+ sizeof(connection_id_hash64));
+ memcpy(new_connection_id_data + sizeof(connection_id_hash64),
+ &connection_id_hash128, sizeof(connection_id_hash128));
+ return QuicConnectionId(new_connection_id_data,
+ expected_connection_id_length);
}
// static
@@ -603,7 +634,7 @@ PacketNumberSpace QuicUtils::GetPacketNumberSpace(
return APPLICATION_DATA;
default:
QUIC_BUG << "Try to get packet number space of encryption level: "
- << EncryptionLevelToString(encryption_level);
+ << encryption_level;
return NUM_PACKET_NUMBER_SPACES;
}
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_utils.h b/chromium/net/third_party/quiche/src/quic/core/quic_utils.h
index eec9a5f25df..9e190e0b386 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_utils.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_utils.h
@@ -146,14 +146,16 @@ class QUIC_EXPORT_PRIVATE QuicUtils {
// Returns true if |id| is considered as bidirectional stream ID. Only used in
// v99.
- static bool IsBidirectionalStreamId(QuicStreamId id);
+ static bool IsBidirectionalStreamId(QuicStreamId id,
+ ParsedQuicVersion version);
// Returns stream type. Either |perspective| or |peer_initiated| would be
// enough together with |id|. This method enforces that the three parameters
// are consistent. Only used in v99.
static StreamType GetStreamType(QuicStreamId id,
Perspective perspective,
- bool peer_initiated);
+ bool peer_initiated,
+ ParsedQuicVersion version);
// Returns the delta between consecutive stream IDs of the same type.
static QuicStreamId StreamIdDelta(QuicTransportVersion version);
@@ -168,11 +170,19 @@ class QUIC_EXPORT_PRIVATE QuicUtils {
QuicTransportVersion version,
Perspective perspective);
- // Generates a 64bit connection ID derived from the input connection ID.
+ // Generates a connection ID of length |expected_connection_id_length|
+ // derived from |connection_id|.
// This is guaranteed to be deterministic (calling this method with two
// connection IDs that are equal is guaranteed to produce the same result).
static QuicConnectionId CreateReplacementConnectionId(
- QuicConnectionId connection_id);
+ const QuicConnectionId& connection_id,
+ uint8_t expected_connection_id_length);
+
+ // Generates a 64bit connection ID derived from |connection_id|.
+ // This is guaranteed to be deterministic (calling this method with two
+ // connection IDs that are equal is guaranteed to produce the same result).
+ static QuicConnectionId CreateReplacementConnectionId(
+ const QuicConnectionId& connection_id);
// Generates a random 64bit connection ID.
static QuicConnectionId CreateRandomConnectionId();
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_utils_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_utils_test.cc
index 5b2186acde4..041cd9856a1 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_utils_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_utils_test.cc
@@ -125,8 +125,7 @@ TEST_F(QuicUtilsTest, RetransmissionTypeToPacketState) {
EXPECT_EQ(HANDSHAKE_RETRANSMITTED, state);
} else if (i == LOSS_RETRANSMISSION) {
EXPECT_EQ(LOST, state);
- } else if (i == ALL_UNACKED_RETRANSMISSION ||
- i == ALL_INITIAL_RETRANSMISSION) {
+ } else if (i == ALL_ZERO_RTT_RETRANSMISSION) {
EXPECT_EQ(UNACKABLE, state);
} else if (i == TLP_RETRANSMISSION) {
EXPECT_EQ(TLP_RETRANSMITTED, state);
@@ -180,6 +179,23 @@ TEST_F(QuicUtilsTest, ReplacementConnectionIdIsDeterministic) {
EXPECT_EQ(connection_id72a, connection_id72b);
EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id72a),
QuicUtils::CreateReplacementConnectionId(connection_id72b));
+ // Test variant with custom length.
+ EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id64a, 7),
+ QuicUtils::CreateReplacementConnectionId(connection_id64b, 7));
+ EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id64a, 9),
+ QuicUtils::CreateReplacementConnectionId(connection_id64b, 9));
+ EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id64a, 16),
+ QuicUtils::CreateReplacementConnectionId(connection_id64b, 16));
+ EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id72a, 7),
+ QuicUtils::CreateReplacementConnectionId(connection_id72b, 7));
+ EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id72a, 9),
+ QuicUtils::CreateReplacementConnectionId(connection_id72b, 9));
+ EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id72a, 16),
+ QuicUtils::CreateReplacementConnectionId(connection_id72b, 16));
+ EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id72a, 32),
+ QuicUtils::CreateReplacementConnectionId(connection_id72b, 32));
+ EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id72a, 255),
+ QuicUtils::CreateReplacementConnectionId(connection_id72b, 255));
}
TEST_F(QuicUtilsTest, ReplacementConnectionIdLengthIsCorrect) {
@@ -191,6 +207,22 @@ TEST_F(QuicUtilsTest, ReplacementConnectionIdLengthIsCorrect) {
QuicUtils::CreateReplacementConnectionId(connection_id);
EXPECT_EQ(kQuicDefaultConnectionIdLength,
replacement_connection_id.length());
+ // Test variant with custom length.
+ QuicConnectionId replacement_connection_id7 =
+ QuicUtils::CreateReplacementConnectionId(connection_id, 7);
+ EXPECT_EQ(7, replacement_connection_id7.length());
+ QuicConnectionId replacement_connection_id9 =
+ QuicUtils::CreateReplacementConnectionId(connection_id, 9);
+ EXPECT_EQ(9, replacement_connection_id9.length());
+ QuicConnectionId replacement_connection_id16 =
+ QuicUtils::CreateReplacementConnectionId(connection_id, 16);
+ EXPECT_EQ(16, replacement_connection_id16.length());
+ QuicConnectionId replacement_connection_id32 =
+ QuicUtils::CreateReplacementConnectionId(connection_id, 32);
+ EXPECT_EQ(32, replacement_connection_id32.length());
+ QuicConnectionId replacement_connection_id255 =
+ QuicUtils::CreateReplacementConnectionId(connection_id, 255);
+ EXPECT_EQ(255, replacement_connection_id255.length());
}
}
@@ -205,6 +237,17 @@ TEST_F(QuicUtilsTest, ReplacementConnectionIdHasEntropy) {
EXPECT_NE(connection_id_i, connection_id_j);
EXPECT_NE(QuicUtils::CreateReplacementConnectionId(connection_id_i),
QuicUtils::CreateReplacementConnectionId(connection_id_j));
+ // Test variant with custom length.
+ EXPECT_NE(QuicUtils::CreateReplacementConnectionId(connection_id_i, 7),
+ QuicUtils::CreateReplacementConnectionId(connection_id_j, 7));
+ EXPECT_NE(QuicUtils::CreateReplacementConnectionId(connection_id_i, 9),
+ QuicUtils::CreateReplacementConnectionId(connection_id_j, 9));
+ EXPECT_NE(QuicUtils::CreateReplacementConnectionId(connection_id_i, 16),
+ QuicUtils::CreateReplacementConnectionId(connection_id_j, 16));
+ EXPECT_NE(QuicUtils::CreateReplacementConnectionId(connection_id_i, 32),
+ QuicUtils::CreateReplacementConnectionId(connection_id_j, 32));
+ EXPECT_NE(QuicUtils::CreateReplacementConnectionId(connection_id_i, 255),
+ QuicUtils::CreateReplacementConnectionId(connection_id_j, 255));
}
}
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc
index 0a014bebe78..90c49823d99 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc
@@ -15,18 +15,20 @@ namespace quic {
QuicVersionManager::QuicVersionManager(
ParsedQuicVersionVector supported_versions)
- : enable_version_draft_27_(
- GetQuicReloadableFlag(quic_enable_version_draft_27)),
- enable_version_draft_25_(
- GetQuicReloadableFlag(quic_enable_version_draft_25_v3)),
+ : enable_version_draft_29_(
+ GetQuicReloadableFlag(quic_enable_version_draft_29)),
+ disable_version_draft_27_(
+ GetQuicReloadableFlag(quic_disable_version_draft_27)),
+ disable_version_draft_25_(
+ GetQuicReloadableFlag(quic_disable_version_draft_25)),
disable_version_q050_(GetQuicReloadableFlag(quic_disable_version_q050)),
- enable_version_t050_(GetQuicReloadableFlag(quic_enable_version_t050_v2)),
+ disable_version_t050_(GetQuicReloadableFlag(quic_disable_version_t050)),
disable_version_q049_(GetQuicReloadableFlag(quic_disable_version_q049)),
disable_version_q048_(GetQuicReloadableFlag(quic_disable_version_q048)),
disable_version_q046_(GetQuicReloadableFlag(quic_disable_version_q046)),
disable_version_q043_(GetQuicReloadableFlag(quic_disable_version_q043)),
allowed_supported_versions_(std::move(supported_versions)) {
- static_assert(SupportedVersions().size() == 8u,
+ static_assert(SupportedVersions().size() == 9u,
"Supported versions out of sync");
RefilterSupportedVersions();
}
@@ -56,16 +58,18 @@ const std::vector<std::string>& QuicVersionManager::GetSupportedAlpns() {
}
void QuicVersionManager::MaybeRefilterSupportedVersions() {
- static_assert(SupportedVersions().size() == 8u,
+ static_assert(SupportedVersions().size() == 9u,
"Supported versions out of sync");
- if (enable_version_draft_27_ !=
- GetQuicReloadableFlag(quic_enable_version_draft_27) ||
- enable_version_draft_25_ !=
- GetQuicReloadableFlag(quic_enable_version_draft_25_v3) ||
+ if (enable_version_draft_29_ !=
+ GetQuicReloadableFlag(quic_enable_version_draft_29) ||
+ disable_version_draft_27_ !=
+ GetQuicReloadableFlag(quic_disable_version_draft_27) ||
+ disable_version_draft_25_ !=
+ GetQuicReloadableFlag(quic_disable_version_draft_25) ||
disable_version_q050_ !=
GetQuicReloadableFlag(quic_disable_version_q050) ||
- enable_version_t050_ !=
- GetQuicReloadableFlag(quic_enable_version_t050_v2) ||
+ disable_version_t050_ !=
+ GetQuicReloadableFlag(quic_disable_version_t050) ||
disable_version_q049_ !=
GetQuicReloadableFlag(quic_disable_version_q049) ||
disable_version_q048_ !=
@@ -74,12 +78,14 @@ void QuicVersionManager::MaybeRefilterSupportedVersions() {
GetQuicReloadableFlag(quic_disable_version_q046) ||
disable_version_q043_ !=
GetQuicReloadableFlag(quic_disable_version_q043)) {
- enable_version_draft_27_ =
- GetQuicReloadableFlag(quic_enable_version_draft_27);
- enable_version_draft_25_ =
- GetQuicReloadableFlag(quic_enable_version_draft_25_v3);
+ enable_version_draft_29_ =
+ GetQuicReloadableFlag(quic_enable_version_draft_29);
+ disable_version_draft_27_ =
+ GetQuicReloadableFlag(quic_disable_version_draft_27);
+ disable_version_draft_25_ =
+ GetQuicReloadableFlag(quic_disable_version_draft_25);
disable_version_q050_ = GetQuicReloadableFlag(quic_disable_version_q050);
- enable_version_t050_ = GetQuicReloadableFlag(quic_enable_version_t050_v2);
+ disable_version_t050_ = GetQuicReloadableFlag(quic_disable_version_t050);
disable_version_q049_ = GetQuicReloadableFlag(quic_disable_version_q049);
disable_version_q048_ = GetQuicReloadableFlag(quic_disable_version_q048);
disable_version_q046_ = GetQuicReloadableFlag(quic_disable_version_q046);
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h
index c5111edf260..e6bb8f6b6bd 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h
@@ -52,14 +52,16 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager {
private:
// Cached value of reloadable flags.
- // quic_enable_version_draft_27 flag
- bool enable_version_draft_27_;
- // quic_enable_version_draft_25_v3 flag
- bool enable_version_draft_25_;
+ // quic_enable_version_draft_29 flag
+ bool enable_version_draft_29_;
+ // quic_disable_version_draft_27 flag
+ bool disable_version_draft_27_;
+ // quic_disable_version_draft_25 flag
+ bool disable_version_draft_25_;
// quic_disable_version_q050 flag
bool disable_version_q050_;
- // quic_enable_version_t050_v2 flag
- bool enable_version_t050_;
+ // quic_disable_version_t050 flag
+ bool disable_version_t050_;
// quic_disable_version_q049 flag
bool disable_version_q049_;
// quic_disable_version_q048 flag
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc
index 3a8e98ff520..4687b791fd9 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc
@@ -18,11 +18,12 @@ namespace {
class QuicVersionManagerTest : public QuicTest {};
TEST_F(QuicVersionManagerTest, QuicVersionManager) {
- static_assert(SupportedVersions().size() == 8u,
+ static_assert(SupportedVersions().size() == 9u,
"Supported versions out of sync");
- SetQuicReloadableFlag(quic_enable_version_draft_27, false);
- SetQuicReloadableFlag(quic_enable_version_draft_25_v3, false);
- SetQuicReloadableFlag(quic_enable_version_t050_v2, false);
+ SetQuicReloadableFlag(quic_enable_version_draft_29, false);
+ SetQuicReloadableFlag(quic_disable_version_draft_27, true);
+ SetQuicReloadableFlag(quic_disable_version_draft_25, true);
+ SetQuicReloadableFlag(quic_disable_version_t050, false);
SetQuicReloadableFlag(quic_disable_version_q050, false);
SetQuicReloadableFlag(quic_disable_version_q049, false);
SetQuicReloadableFlag(quic_disable_version_q048, false);
@@ -32,6 +33,8 @@ TEST_F(QuicVersionManagerTest, QuicVersionManager) {
ParsedQuicVersionVector expected_parsed_versions;
expected_parsed_versions.push_back(
+ ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50));
+ expected_parsed_versions.push_back(
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50));
expected_parsed_versions.push_back(
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49));
@@ -43,59 +46,56 @@ TEST_F(QuicVersionManagerTest, QuicVersionManager) {
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43));
EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions());
- EXPECT_EQ(expected_parsed_versions,
- manager.GetSupportedVersionsWithQuicCrypto());
EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()),
manager.GetSupportedVersions());
EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
manager.GetSupportedVersionsWithQuicCrypto());
- EXPECT_THAT(
- manager.GetSupportedAlpns(),
- ElementsAre("h3-Q050", "h3-Q049", "h3-Q048", "h3-Q046", "h3-Q043"));
+ EXPECT_THAT(manager.GetSupportedAlpns(),
+ ElementsAre("h3-T050", "h3-Q050", "h3-Q049", "h3-Q048", "h3-Q046",
+ "h3-Q043"));
- SetQuicReloadableFlag(quic_enable_version_draft_27, true);
- expected_parsed_versions.insert(
- expected_parsed_versions.begin(),
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27));
+ SetQuicReloadableFlag(quic_enable_version_draft_29, true);
+ expected_parsed_versions.insert(expected_parsed_versions.begin(),
+ ParsedQuicVersion::Draft29());
EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions());
- EXPECT_EQ(expected_parsed_versions.size() - 1,
+ EXPECT_EQ(expected_parsed_versions.size() - 2,
manager.GetSupportedVersionsWithQuicCrypto().size());
EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()),
manager.GetSupportedVersions());
EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
manager.GetSupportedVersionsWithQuicCrypto());
EXPECT_THAT(manager.GetSupportedAlpns(),
- ElementsAre("h3-27", "h3-Q050", "h3-Q049", "h3-Q048", "h3-Q046",
- "h3-Q043"));
+ ElementsAre("h3-29", "h3-T050", "h3-Q050", "h3-Q049", "h3-Q048",
+ "h3-Q046", "h3-Q043"));
- SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true);
+ SetQuicReloadableFlag(quic_disable_version_draft_27, false);
expected_parsed_versions.insert(
expected_parsed_versions.begin() + 1,
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25));
+ ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27));
EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions());
- EXPECT_EQ(expected_parsed_versions.size() - 2,
+ EXPECT_EQ(expected_parsed_versions.size() - 3,
manager.GetSupportedVersionsWithQuicCrypto().size());
+ EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()),
+ manager.GetSupportedVersions());
EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
manager.GetSupportedVersionsWithQuicCrypto());
EXPECT_THAT(manager.GetSupportedAlpns(),
- ElementsAre("h3-27", "h3-25", "h3-Q050", "h3-Q049", "h3-Q048",
- "h3-Q046", "h3-Q043"));
+ ElementsAre("h3-29", "h3-27", "h3-T050", "h3-Q050", "h3-Q049",
+ "h3-Q048", "h3-Q046", "h3-Q043"));
- SetQuicReloadableFlag(quic_enable_version_t050_v2, true);
+ SetQuicReloadableFlag(quic_disable_version_draft_25, false);
expected_parsed_versions.insert(
expected_parsed_versions.begin() + 2,
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50));
+ ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25));
EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions());
- EXPECT_EQ(expected_parsed_versions.size() - 3,
+ EXPECT_EQ(expected_parsed_versions.size() - 4,
manager.GetSupportedVersionsWithQuicCrypto().size());
- EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()),
- manager.GetSupportedVersions());
EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
manager.GetSupportedVersionsWithQuicCrypto());
EXPECT_THAT(manager.GetSupportedAlpns(),
- ElementsAre("h3-27", "h3-25", "h3-T050", "h3-Q050", "h3-Q049",
- "h3-Q048", "h3-Q046", "h3-Q043"));
+ ElementsAre("h3-29", "h3-27", "h3-25", "h3-T050", "h3-Q050",
+ "h3-Q049", "h3-Q048", "h3-Q046", "h3-Q043"));
}
} // namespace
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc b/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc
index bf93e8383d2..461a4882e2b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc
@@ -39,6 +39,35 @@ QuicVersionLabel CreateRandomVersionLabelForNegotiation() {
return result;
}
+void SetVersionFlag(const ParsedQuicVersion& version, bool should_enable) {
+ static_assert(SupportedVersions().size() == 9u,
+ "Supported versions out of sync");
+ const bool enable = should_enable;
+ const bool disable = !should_enable;
+ if (version == ParsedQuicVersion::Draft29()) {
+ SetQuicReloadableFlag(quic_enable_version_draft_29, enable);
+ } else if (version == ParsedQuicVersion::Draft27()) {
+ SetQuicReloadableFlag(quic_disable_version_draft_27, disable);
+ } else if (version == ParsedQuicVersion::Draft25()) {
+ SetQuicReloadableFlag(quic_disable_version_draft_25, disable);
+ } else if (version == ParsedQuicVersion::T050()) {
+ SetQuicReloadableFlag(quic_disable_version_t050, disable);
+ } else if (version == ParsedQuicVersion::Q050()) {
+ SetQuicReloadableFlag(quic_disable_version_q050, disable);
+ } else if (version == ParsedQuicVersion::Q049()) {
+ SetQuicReloadableFlag(quic_disable_version_q049, disable);
+ } else if (version == ParsedQuicVersion::Q048()) {
+ SetQuicReloadableFlag(quic_disable_version_q048, disable);
+ } else if (version == ParsedQuicVersion::Q046()) {
+ SetQuicReloadableFlag(quic_disable_version_q046, disable);
+ } else if (version == ParsedQuicVersion::Q043()) {
+ SetQuicReloadableFlag(quic_disable_version_q043, disable);
+ } else {
+ QUIC_BUG << "Cannot " << (should_enable ? "en" : "dis") << "able version "
+ << version;
+ }
+}
+
} // namespace
bool ParsedQuicVersion::IsKnown() const {
@@ -158,6 +187,11 @@ bool ParsedQuicVersion::HasVarIntTransportParams() const {
return transport_version >= QUIC_VERSION_IETF_DRAFT_27;
}
+bool ParsedQuicVersion::AuthenticatesHandshakeConnectionIds() const {
+ DCHECK(IsKnown());
+ return transport_version > QUIC_VERSION_IETF_DRAFT_27;
+}
+
bool ParsedQuicVersion::UsesTls() const {
DCHECK(IsKnown());
return handshake_protocol == PROTOCOL_TLS1_3;
@@ -211,7 +245,7 @@ QuicVersionLabel CreateQuicVersionLabel(ParsedQuicVersion parsed_version) {
<< parsed_version.handshake_protocol;
return 0;
}
- static_assert(SupportedVersions().size() == 8u,
+ static_assert(SupportedVersions().size() == 9u,
"Supported versions out of sync");
switch (parsed_version.transport_version) {
case QUIC_VERSION_43:
@@ -236,6 +270,12 @@ QuicVersionLabel CreateQuicVersionLabel(ParsedQuicVersion parsed_version) {
}
QUIC_BUG << "QUIC_VERSION_IETF_DRAFT_27 requires TLS";
return 0;
+ case QUIC_VERSION_IETF_DRAFT_29:
+ if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3) {
+ return MakeVersionLabel(0xff, 0x00, 0x00, 29);
+ }
+ QUIC_BUG << "QUIC_VERSION_IETF_DRAFT_29 requires TLS";
+ return 0;
case QUIC_VERSION_RESERVED_FOR_NEGOTIATION:
return CreateRandomVersionLabelForNegotiation();
default:
@@ -391,15 +431,20 @@ ParsedQuicVersionVector FilterSupportedVersions(
ParsedQuicVersionVector versions) {
ParsedQuicVersionVector filtered_versions;
filtered_versions.reserve(versions.size());
- for (ParsedQuicVersion version : versions) {
- if (version.transport_version == QUIC_VERSION_IETF_DRAFT_27) {
+ for (const ParsedQuicVersion& version : versions) {
+ if (version.transport_version == QUIC_VERSION_IETF_DRAFT_29) {
+ QUIC_BUG_IF(version.handshake_protocol != PROTOCOL_TLS1_3);
+ if (GetQuicReloadableFlag(quic_enable_version_draft_29)) {
+ filtered_versions.push_back(version);
+ }
+ } else if (version.transport_version == QUIC_VERSION_IETF_DRAFT_27) {
QUIC_BUG_IF(version.handshake_protocol != PROTOCOL_TLS1_3);
- if (GetQuicReloadableFlag(quic_enable_version_draft_27)) {
+ if (!GetQuicReloadableFlag(quic_disable_version_draft_27)) {
filtered_versions.push_back(version);
}
} else if (version.transport_version == QUIC_VERSION_IETF_DRAFT_25) {
QUIC_BUG_IF(version.handshake_protocol != PROTOCOL_TLS1_3);
- if (GetQuicReloadableFlag(quic_enable_version_draft_25_v3)) {
+ if (!GetQuicReloadableFlag(quic_disable_version_draft_25)) {
filtered_versions.push_back(version);
}
} else if (version.transport_version == QUIC_VERSION_50) {
@@ -408,7 +453,7 @@ ParsedQuicVersionVector FilterSupportedVersions(
filtered_versions.push_back(version);
}
} else {
- if (GetQuicReloadableFlag(quic_enable_version_t050_v2)) {
+ if (!GetQuicReloadableFlag(quic_disable_version_t050)) {
filtered_versions.push_back(version);
}
}
@@ -518,7 +563,7 @@ HandshakeProtocol QuicVersionLabelToHandshakeProtocol(
return #x
std::string QuicVersionToString(QuicTransportVersion transport_version) {
- static_assert(SupportedTransportVersions().size() == 7u,
+ static_assert(SupportedTransportVersions().size() == 8u,
"Supported versions out of sync");
switch (transport_version) {
RETURN_STRING_LITERAL(QUIC_VERSION_43);
@@ -528,6 +573,7 @@ std::string QuicVersionToString(QuicTransportVersion transport_version) {
RETURN_STRING_LITERAL(QUIC_VERSION_50);
RETURN_STRING_LITERAL(QUIC_VERSION_IETF_DRAFT_25);
RETURN_STRING_LITERAL(QUIC_VERSION_IETF_DRAFT_27);
+ RETURN_STRING_LITERAL(QUIC_VERSION_IETF_DRAFT_29);
RETURN_STRING_LITERAL(QUIC_VERSION_UNSUPPORTED);
RETURN_STRING_LITERAL(QUIC_VERSION_RESERVED_FOR_NEGOTIATION);
}
@@ -621,21 +667,25 @@ bool QuicVersionLabelUses4BitConnectionIdLength(
}
ParsedQuicVersion UnsupportedQuicVersion() {
- return ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED);
+ return ParsedQuicVersion::Unsupported();
}
ParsedQuicVersion QuicVersionReservedForNegotiation() {
- return ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO,
- QUIC_VERSION_RESERVED_FOR_NEGOTIATION);
+ return ParsedQuicVersion::ReservedForNegotiation();
+}
+
+ParsedQuicVersion LegacyVersionForEncapsulation() {
+ return ParsedQuicVersion::Q043();
}
std::string AlpnForVersion(ParsedQuicVersion parsed_version) {
if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3) {
- if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_25) {
- return "h3-25";
- }
- if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_27) {
+ if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_29) {
+ return "h3-29";
+ } else if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_27) {
return "h3-27";
+ } else if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_25) {
+ return "h3-25";
}
}
return "h3-" + ParsedQuicVersionToString(parsed_version);
@@ -643,32 +693,21 @@ std::string AlpnForVersion(ParsedQuicVersion parsed_version) {
void QuicVersionInitializeSupportForIetfDraft() {
// Enable necessary flags.
+ SetQuicReloadableFlag(quic_enable_tls_resumption, true);
+ SetQuicReloadableFlag(quic_enable_zero_rtt_for_tls, true);
}
-void QuicEnableVersion(ParsedQuicVersion parsed_version) {
- static_assert(SupportedVersions().size() == 8u,
- "Supported versions out of sync");
- if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_27) {
- QUIC_BUG_IF(parsed_version.handshake_protocol != PROTOCOL_TLS1_3);
- SetQuicReloadableFlag(quic_enable_version_draft_27, true);
- } else if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_25) {
- QUIC_BUG_IF(parsed_version.handshake_protocol != PROTOCOL_TLS1_3);
- SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true);
- } else if (parsed_version.transport_version == QUIC_VERSION_50) {
- if (parsed_version.handshake_protocol == PROTOCOL_QUIC_CRYPTO) {
- SetQuicReloadableFlag(quic_disable_version_q050, false);
- } else {
- SetQuicReloadableFlag(quic_enable_version_t050_v2, true);
- }
- } else if (parsed_version.transport_version == QUIC_VERSION_49) {
- SetQuicReloadableFlag(quic_disable_version_q049, false);
- } else if (parsed_version.transport_version == QUIC_VERSION_48) {
- SetQuicReloadableFlag(quic_disable_version_q048, false);
- } else if (parsed_version.transport_version == QUIC_VERSION_46) {
- SetQuicReloadableFlag(quic_disable_version_q046, false);
- } else if (parsed_version.transport_version == QUIC_VERSION_43) {
- SetQuicReloadableFlag(quic_disable_version_q043, false);
- }
+void QuicEnableVersion(const ParsedQuicVersion& version) {
+ SetVersionFlag(version, /*should_enable=*/true);
+}
+
+void QuicDisableVersion(const ParsedQuicVersion& version) {
+ SetVersionFlag(version, /*should_enable=*/false);
+}
+
+bool QuicVersionIsEnabled(const ParsedQuicVersion& version) {
+ ParsedQuicVersionVector current = CurrentSupportedVersions();
+ return std::find(current.begin(), current.end(), version) != current.end();
}
#undef RETURN_STRING_LITERAL // undef for jumbo builds
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions.h b/chromium/net/third_party/quiche/src/quic/core/quic_versions.h
index 5f3a9689198..341d39896cb 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_versions.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions.h
@@ -4,13 +4,21 @@
// Definitions and utility functions related to handling of QUIC versions.
//
-// QUIC version is a four-byte tag that can be represented in memory as a
-// QuicVersionLabel type (which is an alias to uint32_t). In actuality, all
-// versions supported by this implementation have the following format:
-// [QT]0\d\d
-// e.g. Q046. Q or T distinguishes the type of handshake used (Q for QUIC
-// Crypto handshake, T for TLS-based handshake), and the two digits at the end
-// is the actual numeric value of transport version used by the code.
+// QUIC versions are encoded over the wire as an opaque 32bit field. The wire
+// encoding is represented in memory as a QuicVersionLabel type (which is an
+// alias to uint32_t). Conceptual versions are represented in memory as
+// ParsedQuicVersion.
+//
+// We currently support two kinds of QUIC versions, GoogleQUIC and IETF QUIC.
+//
+// All GoogleQUIC versions use a wire encoding that matches the following regex
+// when converted to ASCII: "[QT]0\d\d" (e.g. Q050). Q or T distinguishes the
+// type of handshake used (Q for the QUIC_CRYPTO handshake, T for the QUIC+TLS
+// handshake), and the two digits at the end contain the numeric value of
+// the transport version used.
+//
+// All IETF QUIC versions use the wire encoding described in:
+// https://tools.ietf.org/html/draft-ietf-quic-transport
#ifndef QUICHE_QUIC_CORE_QUIC_VERSIONS_H_
#define QUICHE_QUIC_CORE_QUIC_VERSIONS_H_
@@ -25,11 +33,12 @@
namespace quic {
-// The available versions of QUIC. The numeric value of the enum is guaranteed
-// to match the number in the name. The versions not currently supported are
-// documented in comments.
-//
-// See go/new-quic-version for more details on how to roll out new versions.
+// The list of existing QUIC transport versions. Note that QUIC versions are
+// sent over the wire as an encoding of ParsedQuicVersion, which requires a
+// QUIC transport version and handshake protocol. For transport versions of the
+// form QUIC_VERSION_XX where XX is decimal, the enum numeric value is
+// guaranteed to match the name. Older deprecated transport versions are
+// documented in comments below.
enum QuicTransportVersion {
// Special case to indicate unknown/unsupported QUIC version.
QUIC_VERSION_UNSUPPORTED = 0,
@@ -110,6 +119,8 @@ enum QuicTransportVersion {
QUIC_VERSION_50 = 50, // Header protection and initial obfuscators.
QUIC_VERSION_IETF_DRAFT_25 = 70, // draft-ietf-quic-transport-25.
QUIC_VERSION_IETF_DRAFT_27 = 71, // draft-ietf-quic-transport-27.
+ // Number 72 used to represent draft-ietf-quic-transport-28.
+ QUIC_VERSION_IETF_DRAFT_29 = 73, // draft-ietf-quic-transport-29.
// Version 99 was a dumping ground for IETF QUIC changes which were not yet
// yet ready for production between 2018-02 and 2020-02.
@@ -123,13 +134,10 @@ enum QuicTransportVersion {
};
// This array contains QUIC transport versions which we currently support.
-// This should be ordered such that the highest supported version is the first
-// element, with subsequent elements in descending order (versions can be
-// skipped as necessary).
-//
-// See go/new-quic-version for more details on how to roll out new versions.
-constexpr std::array<QuicTransportVersion, 7> SupportedTransportVersions() {
- return {QUIC_VERSION_IETF_DRAFT_27,
+// DEPRECATED. Use SupportedVersions() instead.
+constexpr std::array<QuicTransportVersion, 8> SupportedTransportVersions() {
+ return {QUIC_VERSION_IETF_DRAFT_29,
+ QUIC_VERSION_IETF_DRAFT_27,
QUIC_VERSION_IETF_DRAFT_25,
QUIC_VERSION_50,
QUIC_VERSION_49,
@@ -191,7 +199,8 @@ QUIC_EXPORT_PRIVATE constexpr bool ParsedQuicVersionIsValid(
case PROTOCOL_QUIC_CRYPTO:
return transport_version != QUIC_VERSION_UNSUPPORTED &&
transport_version != QUIC_VERSION_IETF_DRAFT_25 &&
- transport_version != QUIC_VERSION_IETF_DRAFT_27;
+ transport_version != QUIC_VERSION_IETF_DRAFT_27 &&
+ transport_version != QUIC_VERSION_IETF_DRAFT_29;
case PROTOCOL_TLS1_3:
// The TLS handshake is only deployable if CRYPTO frames are also used.
// We explicitly removed support for T048 and T049 to reduce test load.
@@ -242,6 +251,51 @@ struct QUIC_EXPORT_PRIVATE ParsedQuicVersion {
transport_version != other.transport_version;
}
+ static constexpr ParsedQuicVersion Draft29() {
+ return ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_29);
+ }
+
+ static constexpr ParsedQuicVersion Draft27() {
+ return ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27);
+ }
+
+ static constexpr ParsedQuicVersion Draft25() {
+ return ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25);
+ }
+
+ static constexpr ParsedQuicVersion T050() {
+ return ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50);
+ }
+
+ static constexpr ParsedQuicVersion Q050() {
+ return ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50);
+ }
+
+ static constexpr ParsedQuicVersion Q049() {
+ return ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49);
+ }
+
+ static constexpr ParsedQuicVersion Q048() {
+ return ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48);
+ }
+
+ static constexpr ParsedQuicVersion Q046() {
+ return ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46);
+ }
+
+ static constexpr ParsedQuicVersion Q043() {
+ return ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43);
+ }
+
+ static constexpr ParsedQuicVersion Unsupported() {
+ return ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED);
+ }
+
+ static constexpr ParsedQuicVersion ReservedForNegotiation() {
+ return ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO,
+ QUIC_VERSION_RESERVED_FOR_NEGOTIATION);
+ }
+
// Returns whether our codebase understands this version. This should only be
// called on valid versions, see ParsedQuicVersionIsValid. Assuming the
// version is valid, IsKnown returns whether the version is not
@@ -331,6 +385,10 @@ struct QUIC_EXPORT_PRIVATE ParsedQuicVersion {
// encoding transport parameter types and lengths.
bool HasVarIntTransportParams() const;
+ // Returns true if this version uses transport parameters to authenticate all
+ // the connection IDs used during the handshake.
+ bool AuthenticatesHandshakeConnectionIds() const;
+
// Returns whether this version uses PROTOCOL_TLS1_3.
bool UsesTls() const;
@@ -342,6 +400,10 @@ QUIC_EXPORT_PRIVATE ParsedQuicVersion UnsupportedQuicVersion();
QUIC_EXPORT_PRIVATE ParsedQuicVersion QuicVersionReservedForNegotiation();
+// Outer version used when encapsulating other packets using the Legacy Version
+// Encapsulation feature.
+QUIC_EXPORT_PRIVATE ParsedQuicVersion LegacyVersionForEncapsulation();
+
QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
const ParsedQuicVersion& version);
@@ -365,16 +427,13 @@ constexpr std::array<HandshakeProtocol, 2> SupportedHandshakeProtocols() {
return {PROTOCOL_TLS1_3, PROTOCOL_QUIC_CRYPTO};
}
-constexpr std::array<ParsedQuicVersion, 8> SupportedVersions() {
+constexpr std::array<ParsedQuicVersion, 9> SupportedVersions() {
return {
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27),
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25),
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50),
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50),
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49),
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48),
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46),
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43),
+ ParsedQuicVersion::Draft29(), ParsedQuicVersion::Draft27(),
+ ParsedQuicVersion::Draft25(), ParsedQuicVersion::T050(),
+ ParsedQuicVersion::Q050(), ParsedQuicVersion::Q049(),
+ ParsedQuicVersion::Q048(), ParsedQuicVersion::Q046(),
+ ParsedQuicVersion::Q043(),
};
}
@@ -604,8 +663,14 @@ QUIC_EXPORT_PRIVATE std::string AlpnForVersion(
// correct flags.
QUIC_EXPORT_PRIVATE void QuicVersionInitializeSupportForIetfDraft();
-// Enables the flags required to support this version of QUIC.
-QUIC_EXPORT_PRIVATE void QuicEnableVersion(ParsedQuicVersion parsed_version);
+// Configures the flags required to enable support for this version of QUIC.
+QUIC_EXPORT_PRIVATE void QuicEnableVersion(const ParsedQuicVersion& version);
+
+// Configures the flags required to disable support for this version of QUIC.
+QUIC_EXPORT_PRIVATE void QuicDisableVersion(const ParsedQuicVersion& version);
+
+// Returns whether support for this version of QUIC is currently enabled.
+QUIC_EXPORT_PRIVATE bool QuicVersionIsEnabled(const ParsedQuicVersion& version);
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc
index 3a07221ab94..c7ebb82a4ed 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc
@@ -84,10 +84,8 @@ TEST_F(QuicVersionsTest, KnownAndValid) {
}
TEST_F(QuicVersionsTest, Features) {
- ParsedQuicVersion parsed_version_q043 =
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43);
- ParsedQuicVersion parsed_version_draft_27 =
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27);
+ ParsedQuicVersion parsed_version_q043 = ParsedQuicVersion::Q043();
+ ParsedQuicVersion parsed_version_draft_27 = ParsedQuicVersion::Draft27();
EXPECT_TRUE(parsed_version_q043.IsKnown());
EXPECT_FALSE(parsed_version_q043.KnowsWhichDecrypterToUse());
@@ -208,35 +206,28 @@ TEST_F(QuicVersionsTest, QuicVersionLabelToHandshakeProtocol) {
}
TEST_F(QuicVersionsTest, ParseQuicVersionLabel) {
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43),
+ EXPECT_EQ(ParsedQuicVersion::Q043(),
ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '3')));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46),
+ EXPECT_EQ(ParsedQuicVersion::Q046(),
ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '6')));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48),
+ EXPECT_EQ(ParsedQuicVersion::Q048(),
ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '8')));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50),
+ EXPECT_EQ(ParsedQuicVersion::Q050(),
ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '5', '0')));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50),
+ EXPECT_EQ(ParsedQuicVersion::T050(),
ParseQuicVersionLabel(MakeVersionLabel('T', '0', '5', '0')));
}
TEST_F(QuicVersionsTest, ParseQuicVersionString) {
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43),
- ParseQuicVersionString("Q043"));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46),
+ EXPECT_EQ(ParsedQuicVersion::Q043(), ParseQuicVersionString("Q043"));
+ EXPECT_EQ(ParsedQuicVersion::Q046(),
ParseQuicVersionString("QUIC_VERSION_46"));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46),
- ParseQuicVersionString("46"));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46),
- ParseQuicVersionString("Q046"));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48),
- ParseQuicVersionString("Q048"));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50),
- ParseQuicVersionString("Q050"));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50),
- ParseQuicVersionString("50"));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50),
- ParseQuicVersionString("h3-Q050"));
+ EXPECT_EQ(ParsedQuicVersion::Q046(), ParseQuicVersionString("46"));
+ EXPECT_EQ(ParsedQuicVersion::Q046(), ParseQuicVersionString("Q046"));
+ EXPECT_EQ(ParsedQuicVersion::Q048(), ParseQuicVersionString("Q048"));
+ EXPECT_EQ(ParsedQuicVersion::Q050(), ParseQuicVersionString("Q050"));
+ EXPECT_EQ(ParsedQuicVersion::Q050(), ParseQuicVersionString("50"));
+ EXPECT_EQ(ParsedQuicVersion::Q050(), ParseQuicVersionString("h3-Q050"));
EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString(""));
EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("Q 46"));
@@ -244,18 +235,14 @@ TEST_F(QuicVersionsTest, ParseQuicVersionString) {
EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("99"));
EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("70"));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50),
- ParseQuicVersionString("T050"));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50),
- ParseQuicVersionString("h3-T050"));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27),
- ParseQuicVersionString("ff00001b"));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27),
- ParseQuicVersionString("h3-27"));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25),
- ParseQuicVersionString("ff000019"));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25),
- ParseQuicVersionString("h3-25"));
+ EXPECT_EQ(ParsedQuicVersion::T050(), ParseQuicVersionString("T050"));
+ EXPECT_EQ(ParsedQuicVersion::T050(), ParseQuicVersionString("h3-T050"));
+ EXPECT_EQ(ParsedQuicVersion::Draft29(), ParseQuicVersionString("ff00001d"));
+ EXPECT_EQ(ParsedQuicVersion::Draft29(), ParseQuicVersionString("h3-29"));
+ EXPECT_EQ(ParsedQuicVersion::Draft27(), ParseQuicVersionString("ff00001b"));
+ EXPECT_EQ(ParsedQuicVersion::Draft27(), ParseQuicVersionString("h3-27"));
+ EXPECT_EQ(ParsedQuicVersion::Draft25(), ParseQuicVersionString("ff000019"));
+ EXPECT_EQ(ParsedQuicVersion::Draft25(), ParseQuicVersionString("h3-25"));
}
TEST_F(QuicVersionsTest, ParseQuicVersionVectorString) {
@@ -266,6 +253,7 @@ TEST_F(QuicVersionsTest, ParseQuicVersionVectorString) {
QUIC_VERSION_IETF_DRAFT_25);
ParsedQuicVersion version_draft_27(PROTOCOL_TLS1_3,
QUIC_VERSION_IETF_DRAFT_27);
+ ParsedQuicVersion version_draft_29 = ParsedQuicVersion::Draft29();
EXPECT_THAT(ParseQuicVersionVectorString(""), IsEmpty());
@@ -286,6 +274,8 @@ TEST_F(QuicVersionsTest, ParseQuicVersionVectorString) {
ElementsAre(version_draft_25, version_draft_27));
EXPECT_THAT(ParseQuicVersionVectorString("h3-27,h3-25"),
ElementsAre(version_draft_27, version_draft_25));
+ EXPECT_THAT(ParseQuicVersionVectorString("h3-29,h3-27"),
+ ElementsAre(version_draft_29, version_draft_27));
EXPECT_THAT(ParseQuicVersionVectorString("h3-27,50"),
ElementsAre(version_draft_27, version_q050));
@@ -332,22 +322,17 @@ TEST_F(QuicVersionsTest, ParseQuicVersionVectorString) {
TEST_F(QuicVersionsTest, CreateQuicVersionLabel) {
EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '3'),
- CreateQuicVersionLabel(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43)));
+ CreateQuicVersionLabel(ParsedQuicVersion::Q043()));
EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '6'),
- CreateQuicVersionLabel(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46)));
+ CreateQuicVersionLabel(ParsedQuicVersion::Q046()));
EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '8'),
- CreateQuicVersionLabel(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48)));
+ CreateQuicVersionLabel(ParsedQuicVersion::Q048()));
EXPECT_EQ(MakeVersionLabel('Q', '0', '5', '0'),
- CreateQuicVersionLabel(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50)));
+ CreateQuicVersionLabel(ParsedQuicVersion::Q050()));
// Test a TLS version:
EXPECT_EQ(MakeVersionLabel('T', '0', '5', '0'),
- CreateQuicVersionLabel(
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50)));
+ CreateQuicVersionLabel(ParsedQuicVersion::T050()));
// Make sure the negotiation reserved version is in the IETF reserved space.
EXPECT_EQ(MakeVersionLabel(0xda, 0x5a, 0x3a, 0x3a) & 0x0f0f0f0f,
@@ -442,97 +427,29 @@ TEST_F(QuicVersionsTest, ParsedQuicVersionToString) {
}
TEST_F(QuicVersionsTest, FilterSupportedVersionsAllVersions) {
- static_assert(SupportedVersions().size() == 8u,
- "Supported versions out of sync");
- SetQuicReloadableFlag(quic_enable_version_draft_27, true);
- SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true);
- SetQuicReloadableFlag(quic_enable_version_t050_v2, true);
- SetQuicReloadableFlag(quic_disable_version_q050, false);
- SetQuicReloadableFlag(quic_disable_version_q049, false);
- SetQuicReloadableFlag(quic_disable_version_q048, false);
- SetQuicReloadableFlag(quic_disable_version_q046, false);
- SetQuicReloadableFlag(quic_disable_version_q043, false);
-
- ParsedQuicVersionVector expected_parsed_versions;
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43));
-
- ASSERT_EQ(expected_parsed_versions,
- FilterSupportedVersions(AllSupportedVersions()));
- ASSERT_EQ(expected_parsed_versions, AllSupportedVersions());
-}
-
-TEST_F(QuicVersionsTest, FilterSupportedVersionsNo99) {
- static_assert(SupportedVersions().size() == 8u,
- "Supported versions out of sync");
- SetQuicReloadableFlag(quic_enable_version_draft_27, false);
- SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true);
- SetQuicReloadableFlag(quic_enable_version_t050_v2, true);
- SetQuicReloadableFlag(quic_disable_version_q050, false);
- SetQuicReloadableFlag(quic_disable_version_q049, false);
- SetQuicReloadableFlag(quic_disable_version_q048, false);
- SetQuicReloadableFlag(quic_disable_version_q046, false);
- SetQuicReloadableFlag(quic_disable_version_q043, false);
-
+ for (const ParsedQuicVersion& version : AllSupportedVersions()) {
+ QuicEnableVersion(version);
+ }
ParsedQuicVersionVector expected_parsed_versions;
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43));
-
- ASSERT_EQ(expected_parsed_versions,
+ for (const ParsedQuicVersion& version : SupportedVersions()) {
+ expected_parsed_versions.push_back(version);
+ }
+ EXPECT_EQ(expected_parsed_versions,
FilterSupportedVersions(AllSupportedVersions()));
+ EXPECT_EQ(expected_parsed_versions, AllSupportedVersions());
}
-TEST_F(QuicVersionsTest, FilterSupportedVersionsNoFlags) {
- static_assert(SupportedVersions().size() == 8u,
- "Supported versions out of sync");
- SetQuicReloadableFlag(quic_enable_version_draft_27, false);
- SetQuicReloadableFlag(quic_enable_version_draft_25_v3, false);
- SetQuicReloadableFlag(quic_enable_version_t050_v2, false);
- SetQuicReloadableFlag(quic_disable_version_q050, false);
- SetQuicReloadableFlag(quic_disable_version_q049, false);
- SetQuicReloadableFlag(quic_disable_version_q048, false);
- SetQuicReloadableFlag(quic_disable_version_q046, false);
- SetQuicReloadableFlag(quic_disable_version_q043, false);
-
+TEST_F(QuicVersionsTest, FilterSupportedVersionsWithoutFirstVersion) {
+ for (const ParsedQuicVersion& version : AllSupportedVersions()) {
+ QuicEnableVersion(version);
+ }
+ QuicDisableVersion(AllSupportedVersions().front());
ParsedQuicVersionVector expected_parsed_versions;
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43));
-
- ASSERT_EQ(expected_parsed_versions,
+ for (const ParsedQuicVersion& version : SupportedVersions()) {
+ expected_parsed_versions.push_back(version);
+ }
+ expected_parsed_versions.erase(expected_parsed_versions.begin());
+ EXPECT_EQ(expected_parsed_versions,
FilterSupportedVersions(AllSupportedVersions()));
}
@@ -540,10 +457,11 @@ TEST_F(QuicVersionsTest, LookUpVersionByIndex) {
QuicTransportVersionVector all_versions = {QUIC_VERSION_43};
int version_count = all_versions.size();
for (int i = -5; i <= version_count + 1; ++i) {
+ QuicTransportVersionVector index = VersionOfIndex(all_versions, i);
if (i >= 0 && i < version_count) {
- EXPECT_EQ(all_versions[i], VersionOfIndex(all_versions, i)[0]);
+ EXPECT_EQ(all_versions[i], index[0]);
} else {
- EXPECT_EQ(QUIC_VERSION_UNSUPPORTED, VersionOfIndex(all_versions, i)[0]);
+ EXPECT_EQ(QUIC_VERSION_UNSUPPORTED, index[0]);
}
}
}
@@ -552,11 +470,11 @@ TEST_F(QuicVersionsTest, LookUpParsedVersionByIndex) {
ParsedQuicVersionVector all_versions = AllSupportedVersions();
int version_count = all_versions.size();
for (int i = -5; i <= version_count + 1; ++i) {
+ ParsedQuicVersionVector index = ParsedVersionOfIndex(all_versions, i);
if (i >= 0 && i < version_count) {
- EXPECT_EQ(all_versions[i], ParsedVersionOfIndex(all_versions, i)[0]);
+ EXPECT_EQ(all_versions[i], index[0]);
} else {
- EXPECT_EQ(UnsupportedQuicVersion(),
- ParsedVersionOfIndex(all_versions, i)[0]);
+ EXPECT_EQ(UnsupportedQuicVersion(), index[0]);
}
}
}
@@ -575,7 +493,7 @@ TEST_F(QuicVersionsTest, ParsedVersionsToTransportVersions) {
// yet a typo was made in doing the #defines and it was caught
// only in some test far removed from here... Better safe than sorry.
TEST_F(QuicVersionsTest, CheckTransportVersionNumbersForTypos) {
- static_assert(SupportedTransportVersions().size() == 7u,
+ static_assert(SupportedTransportVersions().size() == 8u,
"Supported versions out of sync");
EXPECT_EQ(QUIC_VERSION_43, 43);
EXPECT_EQ(QUIC_VERSION_46, 46);
@@ -584,23 +502,18 @@ TEST_F(QuicVersionsTest, CheckTransportVersionNumbersForTypos) {
EXPECT_EQ(QUIC_VERSION_50, 50);
EXPECT_EQ(QUIC_VERSION_IETF_DRAFT_25, 70);
EXPECT_EQ(QUIC_VERSION_IETF_DRAFT_27, 71);
+ EXPECT_EQ(QUIC_VERSION_IETF_DRAFT_29, 73);
}
TEST_F(QuicVersionsTest, AlpnForVersion) {
- static_assert(SupportedVersions().size() == 8u,
+ static_assert(SupportedVersions().size() == 9u,
"Supported versions out of sync");
- ParsedQuicVersion parsed_version_q048 =
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48);
- ParsedQuicVersion parsed_version_q049 =
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49);
- ParsedQuicVersion parsed_version_q050 =
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50);
- ParsedQuicVersion parsed_version_t050 =
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50);
- ParsedQuicVersion parsed_version_draft_25 =
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25);
- ParsedQuicVersion parsed_version_draft_27 =
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27);
+ ParsedQuicVersion parsed_version_q048 = ParsedQuicVersion::Q048();
+ ParsedQuicVersion parsed_version_q049 = ParsedQuicVersion::Q049();
+ ParsedQuicVersion parsed_version_q050 = ParsedQuicVersion::Q050();
+ ParsedQuicVersion parsed_version_t050 = ParsedQuicVersion::T050();
+ ParsedQuicVersion parsed_version_draft_25 = ParsedQuicVersion::Draft25();
+ ParsedQuicVersion parsed_version_draft_27 = ParsedQuicVersion::Draft27();
EXPECT_EQ("h3-Q048", AlpnForVersion(parsed_version_q048));
EXPECT_EQ("h3-Q049", AlpnForVersion(parsed_version_q049));
@@ -608,54 +521,16 @@ TEST_F(QuicVersionsTest, AlpnForVersion) {
EXPECT_EQ("h3-T050", AlpnForVersion(parsed_version_t050));
EXPECT_EQ("h3-25", AlpnForVersion(parsed_version_draft_25));
EXPECT_EQ("h3-27", AlpnForVersion(parsed_version_draft_27));
+ EXPECT_EQ("h3-29", AlpnForVersion(ParsedQuicVersion::Draft29()));
}
-TEST_F(QuicVersionsTest, QuicEnableVersion) {
- static_assert(SupportedVersions().size() == 8u,
- "Supported versions out of sync");
- ParsedQuicVersion parsed_version_draft_27 =
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27);
- ParsedQuicVersion parsed_version_draft_25 =
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25);
- ParsedQuicVersion parsed_version_q050 =
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50);
- ParsedQuicVersion parsed_version_t050 =
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50);
-
- {
- QuicFlagSaver flag_saver;
- SetQuicReloadableFlag(quic_enable_version_draft_27, false);
- QuicEnableVersion(parsed_version_draft_27);
- EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_draft_27));
- }
-
- {
- QuicFlagSaver flag_saver;
- SetQuicReloadableFlag(quic_enable_version_draft_25_v3, false);
- QuicEnableVersion(parsed_version_draft_25);
- EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_draft_25_v3));
- }
-
- {
- QuicFlagSaver flag_saver;
- SetQuicReloadableFlag(quic_disable_version_q050, true);
- QuicEnableVersion(parsed_version_q050);
- EXPECT_FALSE(GetQuicReloadableFlag(quic_disable_version_q050));
- }
-
- {
- QuicFlagSaver flag_saver;
- SetQuicReloadableFlag(quic_enable_version_t050_v2, false);
- QuicEnableVersion(parsed_version_t050);
- EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_t050_v2));
- }
-
- {
+TEST_F(QuicVersionsTest, QuicVersionEnabling) {
+ for (const ParsedQuicVersion& version : AllSupportedVersions()) {
QuicFlagSaver flag_saver;
- for (const ParsedQuicVersion& version : SupportedVersions()) {
- QuicEnableVersion(version);
- }
- ASSERT_EQ(AllSupportedVersions(), CurrentSupportedVersions());
+ QuicDisableVersion(version);
+ EXPECT_FALSE(QuicVersionIsEnabled(version));
+ QuicEnableVersion(version);
+ EXPECT_TRUE(QuicVersionIsEnabled(version));
}
}
@@ -676,7 +551,8 @@ TEST_F(QuicVersionsTest, SupportedVersionsHasCorrectList) {
SupportedTransportVersions()) {
SCOPED_TRACE(index);
if (ParsedQuicVersionIsValid(handshake_protocol, transport_version)) {
- EXPECT_EQ(SupportedVersions()[index],
+ ParsedQuicVersion version = SupportedVersions()[index];
+ EXPECT_EQ(version,
ParsedQuicVersion(handshake_protocol, transport_version));
index++;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.h b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.h
index 1762566d70a..b50d2e236ab 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.h
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.h
@@ -9,6 +9,7 @@
#include <string>
#include <vector>
#include "third_party/boringssl/src/include/openssl/ssl.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h"
#include "net/third_party/quiche/src/quic/core/quic_framer.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_stream_sequencer.h"
@@ -151,6 +152,9 @@ class QUIC_NO_EXPORT TlsChloExtractor
bool OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& /*frame*/) override {
return true;
}
+ bool OnAckFrequencyFrame(const QuicAckFrequencyFrame& /*frame*/) override {
+ return true;
+ }
void OnPacketComplete() override {}
bool IsValidStatelessResetToken(QuicUint128 /*token*/) const override {
return true;
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor_test.cc
index ba57ad02bb9..955e58c0ee6 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor_test.cc
@@ -48,8 +48,9 @@ class TlsChloExtractorTest : public QuicTestWithParam<ParsedQuicVersion> {
void ValidateChloDetails() {
EXPECT_TRUE(tls_chlo_extractor_.HasParsedFullChlo());
- ASSERT_EQ(tls_chlo_extractor_.alpns().size(), 1u);
- EXPECT_EQ(tls_chlo_extractor_.alpns()[0], AlpnForVersion(version_));
+ std::vector<std::string> alpns = tls_chlo_extractor_.alpns();
+ ASSERT_EQ(alpns.size(), 1u);
+ EXPECT_EQ(alpns[0], AlpnForVersion(version_));
EXPECT_EQ(tls_chlo_extractor_.server_name(), TestHostname());
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc
index d4e8ed023b1..23a74e4fc28 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc
@@ -12,6 +12,7 @@
#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h"
#include "net/third_party/quiche/src/quic/core/quic_session.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
@@ -67,6 +68,7 @@ TlsClientHandshaker::TlsClientHandshaker(
pre_shared_key_(crypto_config->pre_shared_key()),
crypto_negotiated_params_(new QuicCryptoNegotiatedParameters),
has_application_state_(has_application_state),
+ attempting_zero_rtt_(crypto_config->early_data_enabled_for_tls()),
tls_connection_(crypto_config->ssl_ctx(), this) {}
TlsClientHandshaker::~TlsClientHandshaker() {
@@ -114,17 +116,16 @@ bool TlsClientHandshaker::CryptoConnect() {
}
// Set a session to resume, if there is one.
+ std::unique_ptr<QuicResumptionState> cached_state;
if (session_cache_) {
- std::unique_ptr<QuicResumptionState> cached_state =
- session_cache_->Lookup(server_id_, SSL_get_SSL_CTX(ssl()));
- if (cached_state) {
- SSL_set_session(ssl(), cached_state->tls_session.get());
- if (GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls) &&
- VersionHasIetfQuicFrames(session()->transport_version()) &&
- SSL_SESSION_early_data_capable(cached_state->tls_session.get())) {
- if (!PrepareZeroRttConfig(cached_state.get())) {
- return false;
- }
+ cached_state = session_cache_->Lookup(server_id_, SSL_get_SSL_CTX(ssl()));
+ }
+ if (cached_state) {
+ SSL_set_session(ssl(), cached_state->tls_session.get());
+ if (attempting_zero_rtt_ &&
+ SSL_SESSION_early_data_capable(cached_state->tls_session.get())) {
+ if (!PrepareZeroRttConfig(cached_state.get())) {
+ return false;
}
}
}
@@ -137,8 +138,8 @@ bool TlsClientHandshaker::CryptoConnect() {
bool TlsClientHandshaker::PrepareZeroRttConfig(
QuicResumptionState* cached_state) {
std::string error_details;
- if (session()->config()->ProcessTransportParameters(
- *(cached_state->transport_params), SERVER,
+ if (handshaker_delegate()->ProcessTransportParameters(
+ *(cached_state->transport_params),
/*is_resumption = */ true, &error_details) != QUIC_NO_ERROR) {
QUIC_BUG << "Unable to parse cached transport parameters.";
CloseConnection(QUIC_HANDSHAKE_FAILED,
@@ -148,7 +149,7 @@ bool TlsClientHandshaker::PrepareZeroRttConfig(
session()->OnConfigNegotiated();
if (has_application_state_) {
- if (!session()->SetApplicationState(cached_state->application_state)) {
+ if (!session()->ResumeApplicationState(cached_state->application_state)) {
QUIC_BUG << "Unable to parse cached application state.";
CloseConnection(QUIC_HANDSHAKE_FAILED,
"Client failed to parse cached application state.");
@@ -204,7 +205,7 @@ bool TlsClientHandshaker::SetTransportParameters() {
params.version =
CreateQuicVersionLabel(session()->supported_versions().front());
- if (!session()->config()->FillTransportParameters(&params)) {
+ if (!handshaker_delegate()->FillTransportParameters(&params)) {
return false;
}
if (GetQuicRestartFlag(quic_google_transport_param_send_new)) {
@@ -216,6 +217,9 @@ bool TlsClientHandshaker::SetTransportParameters() {
params.google_quic_params->SetStringPiece(kUAID, user_agent_id_);
}
+ // Notify QuicConnectionDebugVisitor.
+ session()->connection()->OnTransportParametersSent(params);
+
std::vector<uint8_t> param_bytes;
return SerializeTransportParameters(session()->connection()->version(),
params, &param_bytes) &&
@@ -244,6 +248,10 @@ bool TlsClientHandshaker::ProcessTransportParameters(
return false;
}
+ // Notify QuicConnectionDebugVisitor.
+ session()->connection()->OnTransportParametersReceived(
+ *received_transport_params_);
+
// When interoperating with non-Google implementations that do not send
// the version extension, set it to what we expect.
if (received_transport_params_->version == 0) {
@@ -264,8 +272,8 @@ bool TlsClientHandshaker::ProcessTransportParameters(
received_transport_params_->supported_versions,
session()->connection()->server_supported_versions(),
error_details) != QUIC_NO_ERROR ||
- session()->config()->ProcessTransportParameters(
- *received_transport_params_, SERVER, /* is_resumption = */ false,
+ handshaker_delegate()->ProcessTransportParameters(
+ *received_transport_params_, /* is_resumption = */ false,
error_details) != QUIC_NO_ERROR) {
DCHECK(!error_details->empty());
return false;
@@ -378,9 +386,12 @@ void TlsClientHandshaker::SetWriteSecret(
if (state_ == STATE_CONNECTION_CLOSED) {
return;
}
- if (level == ENCRYPTION_FORWARD_SECURE) {
+ if (level == ENCRYPTION_FORWARD_SECURE || level == ENCRYPTION_ZERO_RTT) {
encryption_established_ = true;
}
+ if (level == ENCRYPTION_FORWARD_SECURE) {
+ handshaker_delegate()->DiscardOldEncryptionKey(ENCRYPTION_ZERO_RTT);
+ }
TlsHandshaker::SetWriteSecret(level, cipher, write_secret);
}
@@ -421,6 +432,10 @@ void TlsClientHandshaker::AdvanceHandshake() {
}
int ssl_error = SSL_get_error(ssl(), rv);
bool should_close = true;
+ if (ssl_error == SSL_ERROR_EARLY_DATA_REJECTED) {
+ HandleZeroRttReject();
+ return;
+ }
switch (state_) {
// TODO(b/153726130): handle the case where the server rejects early data.
case STATE_HANDSHAKE_RUNNING:
@@ -449,6 +464,15 @@ void TlsClientHandshaker::CloseConnection(QuicErrorCode error,
}
void TlsClientHandshaker::FinishHandshake() {
+ if (SSL_in_early_data(ssl())) {
+ // SSL_do_handshake returns after sending the ClientHello if the session is
+ // 0-RTT-capable, which means that FinishHandshake will get called twice -
+ // the first time after sending the ClientHello, and the second time after
+ // the handshake is complete. If we're in the first time FinishHandshake is
+ // called, we can't do any end-of-handshake processing, so we return early
+ // from this function.
+ return;
+ }
QUIC_LOG(INFO) << "Client: handshake finished";
state_ = STATE_HANDSHAKE_COMPLETE;
// Fill crypto_negotiated_params_:
@@ -498,6 +522,17 @@ void TlsClientHandshaker::FinishHandshake() {
handshaker_delegate()->OnOneRttKeysAvailable();
}
+void TlsClientHandshaker::HandleZeroRttReject() {
+ QUIC_LOG(INFO) << "0-RTT handshake attempted but was rejected by the server";
+ DCHECK(session_cache_);
+ // Disable encrytion to block outgoing data until 1-RTT keys are available.
+ encryption_established_ = false;
+ handshaker_delegate()->OnZeroRttRejected();
+ SSL_reset_early_data_reject(ssl());
+ session_cache_->ClearEarlyData(server_id_);
+ AdvanceHandshake();
+}
+
enum ssl_verify_result_t TlsClientHandshaker::VerifyCert(uint8_t* out_alert) {
if (verify_result_ != ssl_verify_retry ||
state_ == STATE_CERT_VERIFY_PENDING) {
@@ -584,7 +619,7 @@ void TlsClientHandshaker::WriteMessage(EncryptionLevel level,
TlsHandshaker::WriteMessage(level, data);
}
-void TlsClientHandshaker::OnApplicationState(
+void TlsClientHandshaker::SetServerApplicationStateForResumption(
std::unique_ptr<ApplicationState> application_state) {
DCHECK_EQ(STATE_HANDSHAKE_COMPLETE, state_);
received_application_state_ = std::move(application_state);
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h
index cc601219dfa..573c055c48c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h
@@ -71,7 +71,7 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker
void WriteMessage(EncryptionLevel level,
quiche::QuicheStringPiece data) override;
- void OnApplicationState(
+ void SetServerApplicationStateForResumption(
std::unique_ptr<ApplicationState> application_state) override;
void AllowEmptyAlpnForTests() { allow_empty_alpn_for_tests_ = true; }
@@ -124,6 +124,7 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker
bool SetTransportParameters();
bool ProcessTransportParameters(std::string* error_details);
void FinishHandshake();
+ void HandleZeroRttReject();
// Called when server completes handshake (i.e., either handshake done is
// received or 1-RTT packet gets acknowledged).
@@ -175,6 +176,7 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker
bool allow_invalid_sni_for_tests_ = false;
const bool has_application_state_;
+ bool attempting_zero_rtt_;
TlsClientConnection tls_connection_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc
index 68c413fbb63..47989a75f5e 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc
@@ -8,13 +8,18 @@
#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_server_id.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
#include "net/third_party/quiche/src/quic/test_tools/simple_session_cache.h"
@@ -167,13 +172,13 @@ class TlsClientHandshakerTest : public QuicTestWithParam<ParsedQuicVersion> {
TlsClientHandshakerTest()
: supported_versions_({GetParam()}),
server_id_(kServerHostname, kServerPort, false),
- crypto_config_(std::make_unique<QuicCryptoClientConfig>(
- std::make_unique<TestProofVerifier>(),
- std::make_unique<test::SimpleSessionCache>())),
server_compressed_certs_cache_(
QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) {
SetQuicReloadableFlag(quic_enable_tls_resumption, true);
SetQuicReloadableFlag(quic_enable_zero_rtt_for_tls, true);
+ crypto_config_ = std::make_unique<QuicCryptoClientConfig>(
+ std::make_unique<TestProofVerifier>(),
+ std::make_unique<test::SimpleSessionCache>());
server_crypto_config_ = crypto_test_utils::CryptoServerConfigForTesting();
CreateConnection();
}
@@ -342,6 +347,72 @@ TEST_P(TlsClientHandshakerTest, Resumption) {
EXPECT_TRUE(stream()->IsResumption());
}
+TEST_P(TlsClientHandshakerTest, ZeroRttResumption) {
+ // Finish establishing the first connection:
+ CompleteCryptoHandshake();
+
+ EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol());
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->one_rtt_keys_available());
+ EXPECT_FALSE(stream()->IsResumption());
+
+ // Create a second connection
+ CreateConnection();
+ CompleteCryptoHandshake();
+
+ // TODO(b/152551499): Add a test that checks we have keys after calling
+ // stream()->CryptoConnect().
+ EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol());
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->one_rtt_keys_available());
+ EXPECT_TRUE(stream()->IsResumption());
+ EXPECT_TRUE(stream()->EarlyDataAccepted());
+}
+
+// TODO(b/152551499): Also test resumption getting rejected.
+TEST_P(TlsClientHandshakerTest, ZeroRttRejection) {
+ // Finish establishing the first connection:
+ CompleteCryptoHandshake();
+
+ EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol());
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->one_rtt_keys_available());
+ EXPECT_FALSE(stream()->IsResumption());
+
+ // Create a second connection, but disable 0-RTT on the server.
+ SSL_CTX_set_early_data_enabled(server_crypto_config_->ssl_ctx(), false);
+ CreateConnection();
+
+ // 4 packets will be sent in this connection: initial handshake packet, 0-RTT
+ // packet containing SETTINGS, handshake packet upon 0-RTT rejection, 0-RTT
+ // packet retransmission.
+ EXPECT_CALL(*connection_,
+ OnPacketSent(ENCRYPTION_INITIAL, NOT_RETRANSMISSION));
+ if (VersionUsesHttp3(session_->transport_version())) {
+ EXPECT_CALL(*connection_,
+ OnPacketSent(ENCRYPTION_ZERO_RTT, NOT_RETRANSMISSION));
+ }
+ EXPECT_CALL(*connection_,
+ OnPacketSent(ENCRYPTION_HANDSHAKE, NOT_RETRANSMISSION));
+ if (VersionUsesHttp3(session_->transport_version())) {
+ // TODO(b/158027651): change transmission type to
+ // ALL_ZERO_RTT_RETRANSMISSION.
+ EXPECT_CALL(*connection_,
+ OnPacketSent(ENCRYPTION_FORWARD_SECURE, LOSS_RETRANSMISSION));
+ }
+
+ CompleteCryptoHandshake();
+
+ QuicFramer* framer = QuicConnectionPeer::GetFramer(connection_);
+ EXPECT_EQ(nullptr, QuicFramerPeer::GetEncrypter(framer, ENCRYPTION_ZERO_RTT));
+
+ EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol());
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->one_rtt_keys_available());
+ EXPECT_TRUE(stream()->IsResumption());
+ EXPECT_FALSE(stream()->EarlyDataAccepted());
+}
+
TEST_P(TlsClientHandshakerTest, ClientSendsNoSNI) {
// Reconfigure client to sent an empty server hostname. The crypto config also
// needs to be recreated to use a FakeProofVerifier since the server's cert
@@ -423,7 +494,6 @@ TEST_P(TlsClientHandshakerTest, BadTransportParams) {
if (!connection_->version().UsesHttp3()) {
return;
}
- SetQuicReloadableFlag(quic_notify_handshaker_on_connection_close, true);
// Finish establishing the first connection:
CompleteCryptoHandshake();
@@ -438,7 +508,8 @@ TEST_P(TlsClientHandshakerTest, BadTransportParams) {
config.SetMaxBidirectionalStreamsToSend(
config.GetMaxBidirectionalStreamsToSend() - 1);
- EXPECT_CALL(*connection_, CloseConnection(QUIC_MAX_STREAMS_ERROR, _, _))
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED, _, _))
.WillOnce(testing::Invoke(connection_,
&MockQuicConnection::ReallyCloseConnection));
// Close connection will be called again in the handshaker, but this will be
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc
index 5a2bd6400aa..caf9a9c6b1b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc
@@ -192,6 +192,8 @@ class TestQuicCryptoStream : public QuicCryptoStream {
HandshakeState GetHandshakeState() const override {
return handshaker()->GetHandshakeState();
}
+ void SetServerApplicationStateForResumption(
+ std::unique_ptr<ApplicationState> /*application_state*/) override {}
const std::vector<std::pair<std::string, EncryptionLevel>>& pending_writes() {
return pending_writes_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc
index 5bd5b3d642d..69b523723d8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc
@@ -13,7 +13,9 @@
#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
namespace quic {
@@ -123,8 +125,15 @@ void TlsServerHandshaker::SendServerConfigUpdate(
}
bool TlsServerHandshaker::IsZeroRtt() const {
- // TODO(nharper): Support 0-RTT with TLS 1.3 in QUIC.
- return false;
+ return SSL_early_data_accepted(ssl());
+}
+
+bool TlsServerHandshaker::IsResumption() const {
+ return SSL_session_reused(ssl());
+}
+
+bool TlsServerHandshaker::ResumptionAttempted() const {
+ return ticket_received_;
}
int TlsServerHandshaker::NumServerConfigUpdateMessagesSent() const {
@@ -137,11 +146,6 @@ TlsServerHandshaker::PreviousCachedNetworkParams() const {
return nullptr;
}
-bool TlsServerHandshaker::ZeroRttAttempted() const {
- // TODO(nharper): Support 0-RTT with TLS 1.3 in QUIC.
- return false;
-}
-
void TlsServerHandshaker::SetPreviousCachedNetworkParams(
CachedNetworkParameters /*cached_network_params*/) {}
@@ -194,6 +198,11 @@ HandshakeState TlsServerHandshaker::GetHandshakeState() const {
return HANDSHAKE_START;
}
+void TlsServerHandshaker::SetServerApplicationStateForResumption(
+ std::unique_ptr<ApplicationState> state) {
+ application_state_ = std::move(state);
+}
+
size_t TlsServerHandshaker::BufferSizeLimitForLevel(
EncryptionLevel level) const {
return TlsHandshaker::BufferSizeLimitForLevel(level);
@@ -201,19 +210,6 @@ size_t TlsServerHandshaker::BufferSizeLimitForLevel(
void TlsServerHandshaker::OverrideQuicConfigDefaults(QuicConfig* /*config*/) {}
-bool TlsServerHandshaker::SetReadSecret(
- EncryptionLevel level,
- const SSL_CIPHER* cipher,
- const std::vector<uint8_t>& read_secret) {
- if (level != ENCRYPTION_FORWARD_SECURE || one_rtt_keys_available_) {
- return TlsHandshaker::SetReadSecret(level, cipher, read_secret);
- }
- // Delay setting read secret for ENCRYPTION_FORWARD_SECURE until handshake
- // completes.
- app_data_read_secret_ = read_secret;
- return true;
-}
-
void TlsServerHandshaker::AdvanceHandshake() {
if (state_ == STATE_CONNECTION_CLOSED) {
QUIC_LOG(INFO) << "TlsServerHandshaker received handshake message after "
@@ -248,8 +244,8 @@ void TlsServerHandshaker::AdvanceHandshake() {
should_close = true;
}
if (should_close && state_ != STATE_CONNECTION_CLOSED) {
- QUIC_LOG(WARNING) << "SSL_do_handshake failed; SSL_get_error returns "
- << ssl_error << ", state_ = " << state_;
+ QUIC_VLOG(1) << "SSL_do_handshake failed; SSL_get_error returns "
+ << ssl_error << ", state_ = " << state_;
ERR_print_errors_fp(stderr);
CloseConnection(QUIC_HANDSHAKE_FAILED,
"Server observed TLS handshake failure");
@@ -284,6 +280,9 @@ bool TlsServerHandshaker::ProcessTransportParameters(
return false;
}
+ // Notify QuicConnectionDebugVisitor.
+ session()->connection()->OnTransportParametersReceived(client_params);
+
// When interoperating with non-Google implementations that do not send
// the version extension, set it to what we expect.
if (client_params.version == 0) {
@@ -294,12 +293,26 @@ bool TlsServerHandshaker::ProcessTransportParameters(
if (CryptoUtils::ValidateClientHelloVersion(
client_params.version, session()->connection()->version(),
session()->supported_versions(), error_details) != QUIC_NO_ERROR ||
- session()->config()->ProcessTransportParameters(
- client_params, CLIENT, /* is_resumption = */ false, error_details) !=
+ handshaker_delegate()->ProcessTransportParameters(
+ client_params, /* is_resumption = */ false, error_details) !=
QUIC_NO_ERROR) {
return false;
}
ProcessAdditionalTransportParameters(client_params);
+ if (GetQuicReloadableFlag(quic_save_user_agent_in_quic_session) &&
+ !session()->user_agent_id().has_value()) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_save_user_agent_in_quic_session, 2, 3);
+
+ if (client_params.user_agent_id.has_value()) {
+ session()->SetUserAgentId(client_params.user_agent_id.value());
+ } else if (client_params.google_quic_params) {
+ quiche::QuicheStringPiece user_agent_id;
+ client_params.google_quic_params->GetStringPiece(kUAID, &user_agent_id);
+ if (!user_agent_id.empty()) {
+ session()->SetUserAgentId(user_agent_id.data());
+ }
+ }
+ }
return true;
}
@@ -312,12 +325,13 @@ bool TlsServerHandshaker::SetTransportParameters() {
server_params.version =
CreateQuicVersionLabel(session()->connection()->version());
- if (!session()->config()->FillTransportParameters(&server_params)) {
+ if (!handshaker_delegate()->FillTransportParameters(&server_params)) {
return false;
}
- // TODO(nharper): Provide an actual value for the stateless reset token.
- server_params.stateless_reset_token.resize(16);
+ // Notify QuicConnectionDebugVisitor.
+ session()->connection()->OnTransportParametersSent(server_params);
+
std::vector<uint8_t> server_params_bytes;
if (!SerializeTransportParameters(session()->connection()->version(),
server_params, &server_params_bytes) ||
@@ -325,6 +339,17 @@ bool TlsServerHandshaker::SetTransportParameters() {
server_params_bytes.size()) != 1) {
return false;
}
+ if (application_state_) {
+ std::vector<uint8_t> early_data_context;
+ if (!SerializeTransportParametersForTicket(
+ server_params, *application_state_, &early_data_context)) {
+ QUIC_BUG << "Failed to serialize Transport Parameters for ticket.";
+ return false;
+ }
+ SSL_set_quic_early_data_context(ssl(), early_data_context.data(),
+ early_data_context.size());
+ application_state_.reset(nullptr);
+ }
return true;
}
@@ -332,8 +357,7 @@ void TlsServerHandshaker::SetWriteSecret(
EncryptionLevel level,
const SSL_CIPHER* cipher,
const std::vector<uint8_t>& write_secret) {
- if (GetQuicReloadableFlag(quic_notify_handshaker_on_connection_close) &&
- state_ == STATE_CONNECTION_CLOSED) {
+ if (state_ == STATE_CONNECTION_CLOSED) {
return;
}
if (level == ENCRYPTION_FORWARD_SECURE) {
@@ -349,6 +373,16 @@ void TlsServerHandshaker::SetWriteSecret(
}
void TlsServerHandshaker::FinishHandshake() {
+ if (SSL_in_early_data(ssl())) {
+ // If the server accepts early data, SSL_do_handshake returns success twice:
+ // once after processing the ClientHello and sending the server's first
+ // flight, and then again after the handshake is complete. This results in
+ // FinishHandshake getting called twice. On the first call to
+ // FinishHandshake, we don't have any confirmation that the client is live,
+ // so all end of handshake processing is deferred until the handshake is
+ // actually complete.
+ return;
+ }
if (!valid_alpn_received_) {
QUIC_DLOG(ERROR)
<< "Server: handshake finished without receiving a known ALPN";
@@ -363,21 +397,10 @@ void TlsServerHandshaker::FinishHandshake() {
state_ = STATE_HANDSHAKE_COMPLETE;
one_rtt_keys_available_ = true;
- const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl());
-
- if (!app_data_read_secret_.empty()) {
- if (!SetReadSecret(ENCRYPTION_FORWARD_SECURE, cipher,
- app_data_read_secret_)) {
- QUIC_BUG << "Failed to set forward secure read key.";
- CloseConnection(QUIC_HANDSHAKE_FAILED, "Failed to set app data read key");
- return;
- }
- app_data_read_secret_.clear();
- }
-
handshaker_delegate()->OnOneRttKeysAvailable();
handshaker_delegate()->DiscardOldEncryptionKey(ENCRYPTION_HANDSHAKE);
handshaker_delegate()->DiscardOldDecryptionKey(ENCRYPTION_HANDSHAKE);
+ handshaker_delegate()->DiscardOldDecryptionKey(ENCRYPTION_ZERO_RTT);
}
ssl_private_key_result_t TlsServerHandshaker::PrivateKeySign(
@@ -446,6 +469,7 @@ ssl_ticket_aead_result_t TlsServerHandshaker::SessionTicketOpen(
DCHECK(proof_source_->GetTicketCrypter());
if (!ticket_decryption_callback_) {
+ ticket_received_ = true;
ticket_decryption_callback_ = new DecryptCallback(this);
proof_source_->GetTicketCrypter()->Decrypt(
in, std::unique_ptr<DecryptCallback>(ticket_decryption_callback_));
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h
index c62dbbbe47c..13b734e3a78 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h
@@ -40,9 +40,10 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
void SendServerConfigUpdate(
const CachedNetworkParameters* cached_network_params) override;
bool IsZeroRtt() const override;
+ bool IsResumption() const override;
+ bool ResumptionAttempted() const override;
int NumServerConfigUpdateMessagesSent() const override;
const CachedNetworkParameters* PreviousCachedNetworkParams() const override;
- bool ZeroRttAttempted() const override;
void SetPreviousCachedNetworkParams(
CachedNetworkParameters cached_network_params) override;
void OnPacketDecrypted(EncryptionLevel level) override;
@@ -60,6 +61,8 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
const override;
CryptoMessageParser* crypto_message_parser() override;
HandshakeState GetHandshakeState() const override;
+ void SetServerApplicationStateForResumption(
+ std::unique_ptr<ApplicationState> state) override;
size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
void SetWriteSecret(EncryptionLevel level,
const SSL_CIPHER* cipher,
@@ -81,13 +84,6 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
virtual void ProcessAdditionalTransportParameters(
const TransportParameters& /*params*/) {}
- // Override of TlsHandshaker::SetReadSecret so that setting the read secret
- // for ENCRYPTION_FORWARD_SECURE can be delayed until the handshake is
- // complete.
- bool SetReadSecret(EncryptionLevel level,
- const SSL_CIPHER* cipher,
- const std::vector<uint8_t>& read_secret) override;
-
// Called when a new message is received on the crypto stream and is available
// for the TLS stack to read.
void AdvanceHandshake() override;
@@ -181,19 +177,21 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
// |decrypted_session_ticket_| contains the decrypted session ticket after the
// callback has run but before it is passed to BoringSSL.
std::vector<uint8_t> decrypted_session_ticket_;
+ // |ticket_received_| tracks whether we received a resumption ticket from the
+ // client. It does not matter whether we were able to decrypt said ticket or
+ // if we actually resumed a session with it - the presence of this ticket
+ // indicates that the client attempted a resumption.
+ bool ticket_received_ = false;
std::string hostname_;
std::string cert_verify_sig_;
std::unique_ptr<ProofSource::Details> proof_source_details_;
+ std::unique_ptr<ApplicationState> application_state_;
+
// Pre-shared key used during the handshake.
std::string pre_shared_key_;
- // Used to hold the ENCRYPTION_FORWARD_SECURE read secret until the handshake
- // is complete. This is temporary until
- // https://bugs.chromium.org/p/boringssl/issues/detail?id=303 is resolved.
- std::vector<uint8_t> app_data_read_secret_;
-
bool encryption_established_ = false;
bool one_rtt_keys_available_ = false;
bool valid_alpn_received_ = false;
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc
index a71338c5f5b..70550fcb21d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc
@@ -47,9 +47,12 @@ class TlsServerHandshakerTest : public QuicTest {
TlsServerHandshakerTest()
: server_compressed_certs_cache_(
QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
- server_id_(kServerHostname, kServerPort, false),
- client_crypto_config_(crypto_test_utils::ProofVerifierForTesting(),
- std::make_unique<test::SimpleSessionCache>()) {
+ server_id_(kServerHostname, kServerPort, false) {
+ SetQuicReloadableFlag(quic_enable_tls_resumption, true);
+ SetQuicReloadableFlag(quic_enable_zero_rtt_for_tls, true);
+ client_crypto_config_ = std::make_unique<QuicCryptoClientConfig>(
+ crypto_test_utils::ProofVerifierForTesting(),
+ std::make_unique<test::SimpleSessionCache>());
InitializeServerConfig();
InitializeServer();
InitializeFakeClient();
@@ -65,7 +68,6 @@ class TlsServerHandshakerTest : public QuicTest {
}
void InitializeServerConfig() {
- SetQuicReloadableFlag(quic_enable_tls_resumption, true);
auto ticket_crypter = std::make_unique<TestTicketCrypter>();
ticket_crypter_ = ticket_crypter.get();
auto proof_source = std::make_unique<FakeProofSource>();
@@ -126,7 +128,7 @@ class TlsServerHandshakerTest : public QuicTest {
CreateClientSessionForTest(
server_id_, QuicTime::Delta::FromSeconds(100000), supported_versions_,
helpers_.back().get(), alarm_factories_.back().get(),
- &client_crypto_config_, &client_connection_, &client_session);
+ client_crypto_config_.get(), &client_connection_, &client_session);
const std::string default_alpn =
AlpnForVersion(client_connection_->version());
ON_CALL(*client_session, GetAlpnsToOffer())
@@ -212,7 +214,7 @@ class TlsServerHandshakerTest : public QuicTest {
// Client state.
PacketSavingConnection* client_connection_;
- QuicCryptoClientConfig client_crypto_config_;
+ std::unique_ptr<QuicCryptoClientConfig> client_crypto_config_;
std::unique_ptr<TestQuicSpdyClientSession> client_session_;
crypto_test_utils::FakeClientOptions client_options_;
@@ -383,6 +385,8 @@ TEST_F(TlsServerHandshakerTest, Resumption) {
CompleteCryptoHandshake();
ExpectHandshakeSuccessful();
EXPECT_FALSE(client_stream()->IsResumption());
+ EXPECT_FALSE(server_stream()->IsResumption());
+ EXPECT_FALSE(server_stream()->ResumptionAttempted());
// Now do another handshake
InitializeServer();
@@ -390,6 +394,8 @@ TEST_F(TlsServerHandshakerTest, Resumption) {
CompleteCryptoHandshake();
ExpectHandshakeSuccessful();
EXPECT_TRUE(client_stream()->IsResumption());
+ EXPECT_TRUE(server_stream()->IsResumption());
+ EXPECT_TRUE(server_stream()->ResumptionAttempted());
}
TEST_F(TlsServerHandshakerTest, ResumptionWithAsyncDecryptCallback) {
@@ -411,6 +417,8 @@ TEST_F(TlsServerHandshakerTest, ResumptionWithAsyncDecryptCallback) {
CompleteCryptoHandshake();
ExpectHandshakeSuccessful();
EXPECT_TRUE(client_stream()->IsResumption());
+ EXPECT_TRUE(server_stream()->IsResumption());
+ EXPECT_TRUE(server_stream()->ResumptionAttempted());
}
TEST_F(TlsServerHandshakerTest, ResumptionWithFailingDecryptCallback) {
@@ -426,6 +434,8 @@ TEST_F(TlsServerHandshakerTest, ResumptionWithFailingDecryptCallback) {
CompleteCryptoHandshake();
ExpectHandshakeSuccessful();
EXPECT_FALSE(client_stream()->IsResumption());
+ EXPECT_FALSE(server_stream()->IsResumption());
+ EXPECT_TRUE(server_stream()->ResumptionAttempted());
}
TEST_F(TlsServerHandshakerTest, ResumptionWithFailingAsyncDecryptCallback) {
@@ -448,6 +458,8 @@ TEST_F(TlsServerHandshakerTest, ResumptionWithFailingAsyncDecryptCallback) {
CompleteCryptoHandshake();
ExpectHandshakeSuccessful();
EXPECT_FALSE(client_stream()->IsResumption());
+ EXPECT_FALSE(server_stream()->IsResumption());
+ EXPECT_TRUE(server_stream()->ResumptionAttempted());
}
TEST_F(TlsServerHandshakerTest, HandshakeFailsWithFailingProofSource) {
@@ -462,6 +474,53 @@ TEST_F(TlsServerHandshakerTest, HandshakeFailsWithFailingProofSource) {
EXPECT_EQ(moved_messages_counts_.second, 0u);
}
+TEST_F(TlsServerHandshakerTest, ZeroRttResumption) {
+ std::vector<uint8_t> application_state = {0, 1, 2, 3};
+
+ // Do the first handshake
+ server_stream()->SetServerApplicationStateForResumption(
+ std::make_unique<ApplicationState>(application_state));
+ InitializeFakeClient();
+ CompleteCryptoHandshake();
+ ExpectHandshakeSuccessful();
+ EXPECT_FALSE(client_stream()->IsResumption());
+ EXPECT_FALSE(server_stream()->IsZeroRtt());
+
+ // Now do another handshake
+ InitializeServer();
+ server_stream()->SetServerApplicationStateForResumption(
+ std::make_unique<ApplicationState>(application_state));
+ InitializeFakeClient();
+ CompleteCryptoHandshake();
+ ExpectHandshakeSuccessful();
+ EXPECT_TRUE(client_stream()->IsResumption());
+ EXPECT_TRUE(server_stream()->IsZeroRtt());
+}
+
+TEST_F(TlsServerHandshakerTest, ZeroRttRejectOnApplicationStateChange) {
+ std::vector<uint8_t> original_application_state = {1, 2};
+ std::vector<uint8_t> new_application_state = {3, 4};
+
+ // Do the first handshake
+ server_stream()->SetServerApplicationStateForResumption(
+ std::make_unique<ApplicationState>(original_application_state));
+ InitializeFakeClient();
+ CompleteCryptoHandshake();
+ ExpectHandshakeSuccessful();
+ EXPECT_FALSE(client_stream()->IsResumption());
+ EXPECT_FALSE(server_stream()->IsZeroRtt());
+
+ // Do another handshake, but change the application state
+ InitializeServer();
+ server_stream()->SetServerApplicationStateForResumption(
+ std::make_unique<ApplicationState>(new_application_state));
+ InitializeFakeClient();
+ CompleteCryptoHandshake();
+ ExpectHandshakeSuccessful();
+ EXPECT_TRUE(client_stream()->IsResumption());
+ EXPECT_FALSE(server_stream()->IsZeroRtt());
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc
index 6951b2cea3f..2f33594e042 100644
--- a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc
@@ -17,7 +17,8 @@ UberQuicStreamIdManager::UberQuicStreamIdManager(
QuicStreamCount max_open_outgoing_unidirectional_streams,
QuicStreamCount max_open_incoming_bidirectional_streams,
QuicStreamCount max_open_incoming_unidirectional_streams)
- : bidirectional_stream_id_manager_(delegate,
+ : version_(version),
+ bidirectional_stream_id_manager_(delegate,
/*unidirectional=*/false,
perspective,
version,
@@ -69,7 +70,7 @@ QuicStreamId UberQuicStreamIdManager::GetNextOutgoingUnidirectionalStreamId() {
bool UberQuicStreamIdManager::MaybeIncreaseLargestPeerStreamId(
QuicStreamId id,
std::string* error_details) {
- if (QuicUtils::IsBidirectionalStreamId(id)) {
+ if (QuicUtils::IsBidirectionalStreamId(id, version_)) {
return bidirectional_stream_id_manager_.MaybeIncreaseLargestPeerStreamId(
id, error_details);
}
@@ -78,7 +79,7 @@ bool UberQuicStreamIdManager::MaybeIncreaseLargestPeerStreamId(
}
void UberQuicStreamIdManager::OnStreamClosed(QuicStreamId id) {
- if (QuicUtils::IsBidirectionalStreamId(id)) {
+ if (QuicUtils::IsBidirectionalStreamId(id, version_)) {
bidirectional_stream_id_manager_.OnStreamClosed(id);
return;
}
@@ -97,7 +98,7 @@ bool UberQuicStreamIdManager::OnStreamsBlockedFrame(
}
bool UberQuicStreamIdManager::IsAvailableStream(QuicStreamId id) const {
- if (QuicUtils::IsBidirectionalStreamId(id)) {
+ if (QuicUtils::IsBidirectionalStreamId(id, version_)) {
return bidirectional_stream_id_manager_.IsAvailableStream(id);
}
return unidirectional_stream_id_manager_.IsAvailableStream(id);
@@ -162,4 +163,14 @@ UberQuicStreamIdManager::advertised_max_incoming_unidirectional_streams()
return unidirectional_stream_id_manager_.incoming_advertised_max_streams();
}
+QuicStreamCount UberQuicStreamIdManager::outgoing_bidirectional_stream_count()
+ const {
+ return bidirectional_stream_id_manager_.outgoing_stream_count();
+}
+
+QuicStreamCount UberQuicStreamIdManager::outgoing_unidirectional_stream_count()
+ const {
+ return unidirectional_stream_id_manager_.outgoing_stream_count();
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h
index b1fc1260987..0e03b42c8d6 100644
--- a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h
@@ -87,10 +87,14 @@ class QUIC_EXPORT_PRIVATE UberQuicStreamIdManager {
QuicStreamCount advertised_max_incoming_bidirectional_streams() const;
QuicStreamCount advertised_max_incoming_unidirectional_streams() const;
+ QuicStreamCount outgoing_bidirectional_stream_count() const;
+ QuicStreamCount outgoing_unidirectional_stream_count() const;
+
private:
friend class test::QuicSessionPeer;
friend class test::UberQuicStreamIdManagerPeer;
+ ParsedQuicVersion version_;
// Manages stream IDs of bidirectional streams.
QuicStreamIdManager bidirectional_stream_id_manager_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc
index 7cae0a6e1de..b3dfedcf71f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc
@@ -287,18 +287,32 @@ TEST_P(UberQuicStreamIdManagerTest, OnStreamsBlockedFrame) {
QuicStreamsBlockedFrame frame(kInvalidControlFrameId, stream_count,
/*unidirectional=*/false);
- EXPECT_CALL(delegate_,
- SendMaxStreams(manager_.max_incoming_bidirectional_streams(),
- frame.unidirectional));
+ if (GetQuicReloadableFlag(quic_stop_sending_duplicate_max_streams)) {
+ EXPECT_CALL(delegate_,
+ SendMaxStreams(manager_.max_incoming_bidirectional_streams(),
+ frame.unidirectional))
+ .Times(0);
+ } else {
+ EXPECT_CALL(delegate_,
+ SendMaxStreams(manager_.max_incoming_bidirectional_streams(),
+ frame.unidirectional));
+ }
EXPECT_TRUE(manager_.OnStreamsBlockedFrame(frame, nullptr));
stream_count = manager_.advertised_max_incoming_unidirectional_streams() - 1;
frame.stream_count = stream_count;
frame.unidirectional = true;
- EXPECT_CALL(delegate_,
- SendMaxStreams(manager_.max_incoming_unidirectional_streams(),
- frame.unidirectional));
+ if (GetQuicReloadableFlag(quic_stop_sending_duplicate_max_streams)) {
+ EXPECT_CALL(delegate_,
+ SendMaxStreams(manager_.max_incoming_unidirectional_streams(),
+ frame.unidirectional))
+ .Times(0);
+ } else {
+ EXPECT_CALL(delegate_,
+ SendMaxStreams(manager_.max_incoming_unidirectional_streams(),
+ frame.unidirectional));
+ }
EXPECT_TRUE(manager_.OnStreamsBlockedFrame(frame, nullptr));
}
diff --git a/chromium/net/third_party/quiche/src/quic/masque/masque_encapsulated_epoll_client.cc b/chromium/net/third_party/quiche/src/quic/masque/masque_encapsulated_epoll_client.cc
index 7c9749aa374..1f3986284ac 100644
--- a/chromium/net/third_party/quiche/src/quic/masque/masque_encapsulated_epoll_client.cc
+++ b/chromium/net/third_party/quiche/src/quic/masque/masque_encapsulated_epoll_client.cc
@@ -47,10 +47,10 @@ class MasquePacketWriter : public QuicPacketWriter {
bool SupportsReleaseTime() const override { return false; }
bool IsBatchMode() const override { return false; }
- char* GetNextWriteLocation(
+ QuicPacketBuffer GetNextWriteLocation(
const QuicIpAddress& /*self_address*/,
const QuicSocketAddress& /*peer_address*/) override {
- return nullptr;
+ return {nullptr, nullptr};
}
WriteResult Flush() override { return WriteResult(WRITE_STATUS_OK, 0); }
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.cc
index 52ba763118f..98d8a51faa7 100644
--- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.cc
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.cc
@@ -94,8 +94,7 @@ void QboneClientSession::OnProofVerifyDetailsAvailable(
const ProofVerifyDetails& verify_details) {}
bool QboneClientSession::HasActiveRequests() const {
- return (stream_map().size() - num_incoming_static_streams() -
- num_outgoing_static_streams()) > 0;
+ return (stream_map().size() - num_static_streams()) > 0;
}
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_test.cc
index cdb611c9209..91be62a3c6c 100644
--- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_test.cc
@@ -139,13 +139,6 @@ class QuicQboneDispatcher : public QuicDispatcher {
return session;
}
- QuicConnectionId GenerateNewServerConnectionId(
- ParsedQuicVersion version,
- QuicConnectionId connection_id) const override {
- char connection_id_bytes[kQuicDefaultConnectionIdLength] = {};
- return QuicConnectionId(connection_id_bytes, sizeof(connection_id_bytes));
- }
-
private:
QbonePacketWriter* writer_;
};
@@ -248,7 +241,7 @@ TEST_P(QboneClientTest, SendDataFromClient) {
crypto_test_utils::ProofVerifierForTesting());
ASSERT_TRUE(client.Initialize());
ASSERT_TRUE(client.Connect());
- ASSERT_TRUE(client.WaitForCryptoHandshakeConfirmed());
+ ASSERT_TRUE(client.WaitForOneRttKeysAvailable());
client.SendData(TestPacketIn("hello"));
client.SendData(TestPacketIn("world"));
client.WaitForWriteToFlush();
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc
index 10edaf6650d..976847de5f1 100644
--- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc
@@ -131,9 +131,10 @@ class DummyPacketWriter : public QuicPacketWriter {
bool IsBatchMode() const override { return false; }
- char* GetNextWriteLocation(const QuicIpAddress& self_address,
- const QuicSocketAddress& peer_address) override {
- return nullptr;
+ QuicPacketBuffer GetNextWriteLocation(
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address) override {
+ return {nullptr, nullptr};
}
WriteResult Flush() override { return WriteResult(WRITE_STATUS_OK, 0); }
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/counting_packet_filter.h b/chromium/net/third_party/quiche/src/quic/quartc/counting_packet_filter.h
deleted file mode 100644
index 4c7c27041ba..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/counting_packet_filter.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_QUARTC_COUNTING_PACKET_FILTER_H_
-#define QUICHE_QUIC_QUARTC_COUNTING_PACKET_FILTER_H_
-
-#include <string>
-
-#include "net/third_party/quiche/src/quic/test_tools/simulator/packet_filter.h"
-#include "net/third_party/quiche/src/quic/test_tools/simulator/port.h"
-#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h"
-
-namespace quic {
-namespace simulator {
-
-// Simple packet filter which drops the first N packets it observes.
-class CountingPacketFilter : public simulator::PacketFilter {
- public:
- CountingPacketFilter(simulator::Simulator* simulator,
- const std::string& name,
- simulator::Endpoint* endpoint)
- : PacketFilter(simulator, name, endpoint) {}
-
- void set_packets_to_drop(int count) { packets_to_drop_ = count; }
-
- protected:
- bool FilterPacket(const simulator::Packet& /*packet*/) override {
- if (packets_to_drop_ > 0) {
- --packets_to_drop_;
- return false;
- }
- return true;
- }
-
- private:
- int packets_to_drop_ = 0;
-};
-
-} // namespace simulator
-} // namespace quic
-
-#endif // QUICHE_QUIC_QUARTC_COUNTING_PACKET_FILTER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.cc
deleted file mode 100644
index da74858d69b..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h"
-
-namespace quic {
-
-QuartcConnectionHelper::QuartcConnectionHelper(const QuicClock* clock,
- QuicRandom* random)
- : clock_(clock), random_(random) {}
-
-const QuicClock* QuartcConnectionHelper::GetClock() const {
- return clock_;
-}
-
-QuicRandom* QuartcConnectionHelper::GetRandomGenerator() {
- return random_;
-}
-
-QuicBufferAllocator* QuartcConnectionHelper::GetStreamSendBufferAllocator() {
- return &buffer_allocator_;
-}
-
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h
deleted file mode 100644
index 72cc707aced..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_QUARTC_QUARTC_CONNECTION_HELPER_H_
-#define QUICHE_QUIC_QUARTC_QUARTC_CONNECTION_HELPER_H_
-
-#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
-#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h"
-#include "net/third_party/quiche/src/quic/core/quic_clock.h"
-#include "net/third_party/quiche/src/quic/core/quic_connection.h"
-#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
-
-namespace quic {
-
-// Simple implementation of QuicConnectionHelperInterface for Quartc.
-class QuartcConnectionHelper : public QuicConnectionHelperInterface {
- public:
- QuartcConnectionHelper(const QuicClock* clock, QuicRandom* random);
-
- // QuicConnectionHelperInterface overrides.
- const QuicClock* GetClock() const override;
- QuicRandom* GetRandomGenerator() override;
- QuicBufferAllocator* GetStreamSendBufferAllocator() override;
-
- private:
- const QuicClock* clock_;
- QuicRandom* random_;
- SimpleBufferAllocator buffer_allocator_;
-};
-
-} // namespace quic
-
-#endif // QUICHE_QUIC_QUARTC_QUARTC_CONNECTION_HELPER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc
deleted file mode 100644
index 14645f83da0..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h"
-
-#include <utility>
-
-#include "net/third_party/quiche/src/quic/core/quic_utils.h"
-
-namespace quic {
-
-void DummyProofSource::GetProof(const QuicSocketAddress& server_address,
- const QuicSocketAddress& client_address,
- const std::string& hostname,
- const std::string& /*server_config*/,
- QuicTransportVersion /*transport_version*/,
- quiche::QuicheStringPiece /*chlo_hash*/,
- std::unique_ptr<Callback> callback) {
- QuicReferenceCountedPointer<ProofSource::Chain> chain =
- GetCertChain(server_address, client_address, hostname);
- QuicCryptoProof proof;
- proof.signature = "Dummy signature";
- proof.leaf_cert_scts = "Dummy timestamp";
- callback->Run(true, chain, proof, nullptr /* details */);
-}
-
-QuicReferenceCountedPointer<DummyProofSource::Chain>
-DummyProofSource::GetCertChain(const QuicSocketAddress& /*server_address*/,
- const QuicSocketAddress& /*client_address*/,
- const std::string& /*hostname*/) {
- std::vector<std::string> certs;
- certs.push_back(kDummyCertName);
- return QuicReferenceCountedPointer<ProofSource::Chain>(
- new ProofSource::Chain(certs));
-}
-
-void DummyProofSource::ComputeTlsSignature(
- const QuicSocketAddress& /*server_address*/,
- const QuicSocketAddress& /*client_address*/,
- const std::string& /*hostname*/,
- uint16_t /*signature_algorithm*/,
- quiche::QuicheStringPiece /*in*/,
- std::unique_ptr<SignatureCallback> callback) {
- callback->Run(true, "Dummy signature", /*details=*/nullptr);
-}
-
-QuicAsyncStatus InsecureProofVerifier::VerifyProof(
- const std::string& /*hostname*/,
- const uint16_t /*port*/,
- const std::string& /*server_config*/,
- QuicTransportVersion /*transport_version*/,
- quiche::QuicheStringPiece /*chlo_hash*/,
- const std::vector<std::string>& /*certs*/,
- const std::string& /*cert_sct*/,
- const std::string& /*signature*/,
- const ProofVerifyContext* /*context*/,
- std::string* /*error_details*/,
- std::unique_ptr<ProofVerifyDetails>* /*verify_details*/,
- std::unique_ptr<ProofVerifierCallback> /*callback*/) {
- return QUIC_SUCCESS;
-}
-
-QuicAsyncStatus InsecureProofVerifier::VerifyCertChain(
- const std::string& /*hostname*/,
- const uint16_t /*port*/,
- const std::vector<std::string>& /*certs*/,
- const std::string& /*ocsp_response*/,
- const std::string& /*cert_sct*/,
- const ProofVerifyContext* /*context*/,
- std::string* /*error_details*/,
- std::unique_ptr<ProofVerifyDetails>* /*details*/,
- std::unique_ptr<ProofVerifierCallback> /*callback*/) {
- return QUIC_SUCCESS;
-}
-
-std::unique_ptr<ProofVerifyContext>
-InsecureProofVerifier::CreateDefaultContext() {
- return nullptr;
-}
-
-bool QuartcCryptoServerStreamHelper::CanAcceptClientHello(
- const CryptoHandshakeMessage& /*message*/,
- const QuicSocketAddress& /*client_address*/,
- const QuicSocketAddress& /*peer_address*/,
- const QuicSocketAddress& /*self_address*/,
- std::string* /*error_details*/) const {
- return true;
-}
-
-std::unique_ptr<QuicCryptoClientConfig> CreateCryptoClientConfig(
- quiche::QuicheStringPiece pre_shared_key) {
- auto config = std::make_unique<QuicCryptoClientConfig>(
- std::make_unique<InsecureProofVerifier>());
- config->set_pad_inchoate_hello(false);
- config->set_pad_full_hello(false);
- if (!pre_shared_key.empty()) {
- config->set_pre_shared_key(pre_shared_key);
- }
- return config;
-}
-
-CryptoServerConfig CreateCryptoServerConfig(
- QuicRandom* random,
- const QuicClock* clock,
- quiche::QuicheStringPiece pre_shared_key) {
- CryptoServerConfig crypto_server_config;
-
- // Generate a random source address token secret. For long-running servers
- // it's better to not regenerate it for each connection to enable zero-RTT
- // handshakes, but for transient clients it does not matter.
- char source_address_token_secret[kInputKeyingMaterialLength];
- random->RandBytes(source_address_token_secret, kInputKeyingMaterialLength);
- auto config = std::make_unique<QuicCryptoServerConfig>(
- std::string(source_address_token_secret, kInputKeyingMaterialLength),
- random, std::make_unique<DummyProofSource>(),
- KeyExchangeSource::Default());
-
- // We run QUIC over ICE, and ICE is verifying remote side with STUN pings.
- // We disable source address token validation in order to allow for 0-rtt
- // setup (plus source ip addresses are changing even during the connection
- // when ICE is used).
- config->set_validate_source_address_token(false);
-
- // Effectively disables the anti-amplification measures (we don't need
- // them because we use ICE, and we need to disable them because we disable
- // padding of crypto packets).
- // This multiplier must be large enough so that the crypto handshake packet
- // (approx. 300 bytes) multiplied by this multiplier is larger than a fully
- // sized packet (currently 1200 bytes).
- // 1500 is a bit extreme: if you can imagine sending a 1 byte packet, and
- // your largest MTU would be below 1500 bytes, 1500*1 >=
- // any_packet_that_you_can_imagine_sending.
- // (again, we hardcode packet size to 1200, so we are not dealing with jumbo
- // frames).
- config->set_chlo_multiplier(1500);
-
- // We are sending small client hello, we must not validate its size.
- config->set_validate_chlo_size(false);
-
- // Provide server with serialized config string to prove ownership.
- QuicCryptoServerConfig::ConfigOptions options;
- // The |message| is used to handle the return value of AddDefaultConfig
- // which is raw pointer of the CryptoHandshakeMessage.
- std::unique_ptr<CryptoHandshakeMessage> message(
- config->AddDefaultConfig(random, clock, options));
- config->set_pad_rej(false);
- config->set_pad_shlo(false);
- if (!pre_shared_key.empty()) {
- config->set_pre_shared_key(pre_shared_key);
- }
- crypto_server_config.config = std::move(config);
- const QuicData& data = message->GetSerialized();
-
- crypto_server_config.serialized_crypto_config =
- std::string(data.data(), data.length());
- return crypto_server_config;
-}
-
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h
deleted file mode 100644
index 806786f2f3d..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_QUARTC_QUARTC_CRYPTO_HELPERS_H_
-#define QUICHE_QUIC_QUARTC_QUARTC_CRYPTO_HELPERS_H_
-
-#include <string>
-
-#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
-#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h"
-#include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h"
-#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h"
-#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
-#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
-#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h"
-#include "net/third_party/quiche/src/quic/core/quic_versions.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
-
-namespace quic {
-
-// Never, ever, change this certificate name. You will break 0-rtt handshake if
-// you do.
-static constexpr char kDummyCertName[] = "Dummy cert";
-
-struct CryptoServerConfig {
- std::unique_ptr<QuicCryptoServerConfig> config;
- std::string serialized_crypto_config;
-};
-
-// Length of HKDF input keying material, equal to its number of bytes.
-// https://tools.ietf.org/html/rfc5869#section-2.2.
-// TODO(zhihuang): Verify that input keying material length is correct.
-constexpr size_t kInputKeyingMaterialLength = 32;
-
-// Used by QuicCryptoServerConfig to provide dummy proof credentials.
-// TODO(zhihuang): Remove when secure P2P QUIC handshake is possible.
-class DummyProofSource : public ProofSource {
- public:
- DummyProofSource() {}
- ~DummyProofSource() override {}
-
- // ProofSource overrides.
- void GetProof(const QuicSocketAddress& server_address,
- const QuicSocketAddress& client_address,
- const std::string& hostname,
- const std::string& server_config,
- QuicTransportVersion transport_version,
- quiche::QuicheStringPiece chlo_hash,
- std::unique_ptr<Callback> callback) override;
-
- QuicReferenceCountedPointer<Chain> GetCertChain(
- const QuicSocketAddress& server_address,
- const QuicSocketAddress& client_address,
- const std::string& hostname) override;
-
- void ComputeTlsSignature(
- const QuicSocketAddress& server_address,
- const QuicSocketAddress& client_address,
- const std::string& hostname,
- uint16_t signature_algorithm,
- quiche::QuicheStringPiece in,
- std::unique_ptr<SignatureCallback> callback) override;
-
- TicketCrypter* GetTicketCrypter() override { return nullptr; }
-};
-
-// Used by QuicCryptoClientConfig to ignore the peer's credentials
-// and establish an insecure QUIC connection.
-// TODO(zhihuang): Remove when secure P2P QUIC handshake is possible.
-class InsecureProofVerifier : public ProofVerifier {
- public:
- InsecureProofVerifier() {}
- ~InsecureProofVerifier() override {}
-
- // ProofVerifier overrides.
- QuicAsyncStatus VerifyProof(
- const std::string& hostname,
- const uint16_t port,
- const std::string& server_config,
- QuicTransportVersion transport_version,
- quiche::QuicheStringPiece chlo_hash,
- const std::vector<std::string>& certs,
- const std::string& cert_sct,
- const std::string& signature,
- const ProofVerifyContext* context,
- std::string* error_details,
- std::unique_ptr<ProofVerifyDetails>* verify_details,
- std::unique_ptr<ProofVerifierCallback> callback) override;
-
- QuicAsyncStatus VerifyCertChain(
- const std::string& hostname,
- const uint16_t port,
- const std::vector<std::string>& certs,
- const std::string& ocsp_response,
- const std::string& cert_sct,
- const ProofVerifyContext* context,
- std::string* error_details,
- std::unique_ptr<ProofVerifyDetails>* details,
- std::unique_ptr<ProofVerifierCallback> callback) override;
-
- std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override;
-};
-
-// Implementation of the server-side crypto stream helper.
-class QuartcCryptoServerStreamHelper
- : public QuicCryptoServerStreamBase::Helper {
- public:
- bool CanAcceptClientHello(const CryptoHandshakeMessage& message,
- const QuicSocketAddress& client_address,
- const QuicSocketAddress& peer_address,
- const QuicSocketAddress& self_address,
- std::string* error_details) const override;
-};
-
-std::unique_ptr<QuicCryptoClientConfig> CreateCryptoClientConfig(
- quiche::QuicheStringPiece pre_shared_key);
-
-CryptoServerConfig CreateCryptoServerConfig(
- QuicRandom* random,
- const QuicClock* clock,
- quiche::QuicheStringPiece pre_shared_key);
-
-} // namespace quic
-
-#endif // QUICHE_QUIC_QUARTC_QUARTC_CRYPTO_HELPERS_H_
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.cc
deleted file mode 100644
index c5c4c4a742f..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h"
-
-#include "net/third_party/quiche/src/quic/core/quic_utils.h"
-#include "net/third_party/quiche/src/quic/core/quic_versions.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_factory.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
-
-namespace quic {
-
-QuartcDispatcher::QuartcDispatcher(
- std::unique_ptr<QuicConfig> config,
- std::unique_ptr<QuicCryptoServerConfig> crypto_config,
- QuicVersionManager* version_manager,
- std::unique_ptr<QuicConnectionHelperInterface> helper,
- std::unique_ptr<QuicCryptoServerStreamBase::Helper> session_helper,
- std::unique_ptr<QuicAlarmFactory> alarm_factory,
- std::unique_ptr<QuartcPacketWriter> packet_writer,
- Delegate* delegate)
- : QuicDispatcher(
- config.get(),
- crypto_config.get(),
- version_manager,
- std::move(helper),
- std::move(session_helper),
- std::move(alarm_factory),
- QuicUtils::CreateZeroConnectionId(
- version_manager->GetSupportedVersions()[0].transport_version)
- .length()),
- owned_quic_config_(std::move(config)),
- owned_crypto_config_(std::move(crypto_config)),
- delegate_(delegate),
- packet_writer_(packet_writer.get()) {
- // Allow incoming packets to set our expected connection ID length.
- SetShouldUpdateExpectedServerConnectionIdLength(true);
- // Allow incoming packets with connection ID lengths shorter than allowed.
- SetAllowShortInitialServerConnectionIds(true);
- // QuicDispatcher takes ownership of the writer.
- QuicDispatcher::InitializeWithWriter(packet_writer.release());
- // NB: This must happen *after* InitializeWithWriter. It can call us back
- // with OnTransportCanWrite() immediately, and the dispatcher needs to be
- // fully initialized to handle that.
- packet_writer_->SetPacketTransportDelegate(this);
-}
-
-QuartcDispatcher::~QuartcDispatcher() {
- packet_writer_->SetPacketTransportDelegate(nullptr);
-}
-
-std::unique_ptr<QuicSession> QuartcDispatcher::CreateQuicSession(
- QuicConnectionId connection_id,
- const QuicSocketAddress& client_address,
- quiche::QuicheStringPiece /*alpn*/,
- const ParsedQuicVersion& version) {
- // Make our expected connection ID non-mutable since we have a connection.
- SetShouldUpdateExpectedServerConnectionIdLength(false);
- std::unique_ptr<QuicConnection> connection = CreateQuicConnection(
- connection_id, client_address, helper(), alarm_factory(), writer(),
- Perspective::IS_SERVER, ParsedQuicVersionVector{version});
- auto session = std::make_unique<QuartcServerSession>(
- std::move(connection), /*visitor=*/this, config(), GetSupportedVersions(),
- helper()->GetClock(), crypto_config(), compressed_certs_cache(),
- session_helper());
- delegate_->OnSessionCreated(session.get());
- return session;
-}
-
-void QuartcDispatcher::OnTransportCanWrite() {
- OnCanWrite();
-}
-
-void QuartcDispatcher::OnTransportReceived(const char* data, size_t data_len) {
- // QuartcPacketTransport does not surface real peer addresses, so the
- // dispatcher uses a dummy address when processing incoming packets. Note that
- // the dispatcher refuses to process anything with port 0.
- static const QuicSocketAddress* dummy_address =
- new QuicSocketAddress(QuicIpAddress::Any4(), /*port=*/1);
-
- QuicReceivedPacket packet(data, data_len, helper()->GetClock()->Now());
- ProcessPacket(/*self_address=*/*dummy_address,
- /*peer_address=*/*dummy_address, packet);
-}
-
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h
deleted file mode 100644
index ca4fe2d6147..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_QUARTC_QUARTC_DISPATCHER_H_
-#define QUICHE_QUIC_QUARTC_QUARTC_DISPATCHER_H_
-
-#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
-#include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h"
-#include "net/third_party/quiche/src/quic/core/quic_config.h"
-#include "net/third_party/quiche/src/quic/core/quic_connection.h"
-#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
-#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h"
-#include "net/third_party/quiche/src/quic/core/quic_dispatcher.h"
-#include "net/third_party/quiche/src/quic/core/quic_version_manager.h"
-#include "net/third_party/quiche/src/quic/core/quic_versions.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_session.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
-
-namespace quic {
-
-class QuartcDispatcher : public QuicDispatcher,
- QuartcPacketTransport::Delegate {
- public:
- class Delegate {
- public:
- virtual ~Delegate() = default;
- virtual void OnSessionCreated(QuartcSession* session) = 0;
- };
-
- QuartcDispatcher(
- std::unique_ptr<QuicConfig> config,
- std::unique_ptr<QuicCryptoServerConfig> crypto_config,
- QuicVersionManager* version_manager,
- std::unique_ptr<QuicConnectionHelperInterface> helper,
- std::unique_ptr<QuicCryptoServerStreamBase::Helper> session_helper,
- std::unique_ptr<QuicAlarmFactory> alarm_factory,
- std::unique_ptr<QuartcPacketWriter> packet_writer,
- Delegate* delegate);
- ~QuartcDispatcher() override;
-
- std::unique_ptr<QuicSession> CreateQuicSession(
- QuicConnectionId server_connection_id,
- const QuicSocketAddress& client_address,
- quiche::QuicheStringPiece alpn,
- const ParsedQuicVersion& version) override;
-
- // TODO(b/124399417): Override GenerateNewServerConnectionId and request a
- // zero-length connection id when the QUIC server perspective supports it.
-
- // QuartcPacketTransport::Delegate overrides.
- void OnTransportCanWrite() override;
- void OnTransportReceived(const char* data, size_t data_len) override;
-
- private:
- // Members owned by QuartcDispatcher but not QuicDispatcher.
- std::unique_ptr<QuicConfig> owned_quic_config_;
- std::unique_ptr<QuicCryptoServerConfig> owned_crypto_config_;
-
- // Delegate invoked when the dispatcher creates a new session.
- Delegate* delegate_;
-
- // The packet writer used by this dispatcher. Owned by the base class, but
- // the base class upcasts it to QuicPacketWriter (which prevents detaching the
- // transport delegate without a downcast).
- QuartcPacketWriter* packet_writer_;
-};
-
-} // namespace quic
-
-#endif // QUICHE_QUIC_QUARTC_QUARTC_DISPATCHER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.cc
deleted file mode 100644
index ca8fad6c9c4..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.cc
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h"
-
-#include <utility>
-
-#include "net/third_party/quiche/src/quic/core/quic_version_manager.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
-
-namespace quic {
-
-namespace {
-
-// Wrapper around a QuicAlarmFactory which delegates to the wrapped factory.
-// Usee to convert an unowned pointer into an owned pointer, so that the new
-// "owner" does not delete the underlying factory. Note that this is only valid
-// when the unowned pointer is already guaranteed to outlive the new "owner".
-class QuartcAlarmFactoryWrapper : public QuicAlarmFactory {
- public:
- explicit QuartcAlarmFactoryWrapper(QuicAlarmFactory* impl) : impl_(impl) {}
-
- QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override;
- QuicArenaScopedPtr<QuicAlarm> CreateAlarm(
- QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
- QuicConnectionArena* arena) override;
-
- private:
- QuicAlarmFactory* impl_;
-};
-
-QuicAlarm* QuartcAlarmFactoryWrapper::CreateAlarm(
- QuicAlarm::Delegate* delegate) {
- return impl_->CreateAlarm(delegate);
-}
-
-QuicArenaScopedPtr<QuicAlarm> QuartcAlarmFactoryWrapper::CreateAlarm(
- QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
- QuicConnectionArena* arena) {
- return impl_->CreateAlarm(std::move(delegate), arena);
-}
-
-} // namespace
-
-QuartcClientEndpoint::QuartcClientEndpoint(
- QuicAlarmFactory* alarm_factory,
- const QuicClock* clock,
- QuicRandom* random,
- QuartcEndpoint::Delegate* delegate,
- const QuartcSessionConfig& config,
- quiche::QuicheStringPiece serialized_server_config,
- std::unique_ptr<QuicVersionManager> version_manager)
- : alarm_factory_(alarm_factory),
- clock_(clock),
- delegate_(delegate),
- serialized_server_config_(serialized_server_config),
- version_manager_(version_manager ? std::move(version_manager)
- : std::make_unique<QuicVersionManager>(
- AllSupportedVersions())),
- create_session_alarm_(QuicWrapUnique(
- alarm_factory_->CreateAlarm(new CreateSessionDelegate(this)))),
- connection_helper_(
- std::make_unique<QuartcConnectionHelper>(clock_, random)),
- config_(config) {}
-
-void QuartcClientEndpoint::Connect(QuartcPacketTransport* packet_transport) {
- packet_transport_ = packet_transport;
- // For the first attempt to connect, use any version that the client supports.
- current_versions_ = version_manager_->GetSupportedVersions();
- create_session_alarm_->Set(clock_->Now());
-}
-
-void QuartcClientEndpoint::OnCreateSessionAlarm() {
- session_ = CreateQuartcClientSession(
- config_, clock_, alarm_factory_, connection_helper_.get(),
- current_versions_, serialized_server_config_, packet_transport_);
- session_->SetDelegate(this);
- delegate_->OnSessionCreated(session_.get());
-}
-
-void QuartcClientEndpoint::OnCryptoHandshakeComplete() {
- delegate_->OnCryptoHandshakeComplete();
-}
-
-void QuartcClientEndpoint::OnConnectionWritable() {
- delegate_->OnConnectionWritable();
-}
-
-void QuartcClientEndpoint::OnIncomingStream(QuartcStream* stream) {
- delegate_->OnIncomingStream(stream);
-}
-
-void QuartcClientEndpoint::OnCongestionControlChange(
- QuicBandwidth bandwidth_estimate,
- QuicBandwidth pacing_rate,
- QuicTime::Delta latest_rtt) {
- delegate_->OnCongestionControlChange(bandwidth_estimate, pacing_rate,
- latest_rtt);
-}
-
-void QuartcClientEndpoint::OnConnectionClosed(
- const QuicConnectionCloseFrame& frame,
- ConnectionCloseSource source) {
- // First, see if we can restart the session with a mutually-supported version.
- if (frame.quic_error_code == QUIC_INVALID_VERSION && session_ &&
- session_->connection() &&
- !session_->connection()->server_supported_versions().empty()) {
- for (const auto& client_version :
- version_manager_->GetSupportedVersions()) {
- if (QuicContainsValue(session_->connection()->server_supported_versions(),
- client_version)) {
- // Found a mutually-supported version. Reconnect using that version.
- current_versions_.clear();
- current_versions_.push_back(client_version);
- create_session_alarm_->Set(clock_->Now());
- return;
- }
- }
- }
-
- // Permanent version negotiation errors are forwarded to the |delegate_|,
- // along with all other errors.
- delegate_->OnConnectionClosed(frame, source);
-}
-
-void QuartcClientEndpoint::OnMessageReceived(
- quiche::QuicheStringPiece message) {
- delegate_->OnMessageReceived(message);
-}
-
-void QuartcClientEndpoint::OnMessageSent(int64_t datagram_id) {
- delegate_->OnMessageSent(datagram_id);
-}
-
-void QuartcClientEndpoint::OnMessageAcked(int64_t datagram_id,
- QuicTime receive_timestamp) {
- delegate_->OnMessageAcked(datagram_id, receive_timestamp);
-}
-
-void QuartcClientEndpoint::OnMessageLost(int64_t datagram_id) {
- delegate_->OnMessageLost(datagram_id);
-}
-
-QuartcServerEndpoint::QuartcServerEndpoint(
- QuicAlarmFactory* alarm_factory,
- const QuicClock* clock,
- QuicRandom* random,
- QuartcEndpoint::Delegate* delegate,
- const QuartcSessionConfig& config,
- std::unique_ptr<QuicVersionManager> version_manager)
- : alarm_factory_(alarm_factory),
- delegate_(delegate),
- config_(config),
- version_manager_(version_manager ? std::move(version_manager)
- : std::make_unique<QuicVersionManager>(
- AllSupportedVersions())),
- pre_connection_helper_(
- std::make_unique<QuartcConnectionHelper>(clock, random)),
- crypto_config_(
- CreateCryptoServerConfig(pre_connection_helper_->GetRandomGenerator(),
- clock,
- config.pre_shared_key)) {}
-
-void QuartcServerEndpoint::Connect(QuartcPacketTransport* packet_transport) {
- DCHECK(pre_connection_helper_ != nullptr);
- dispatcher_ = std::make_unique<QuartcDispatcher>(
- std::make_unique<QuicConfig>(CreateQuicConfig(config_)),
- std::move(crypto_config_.config), version_manager_.get(),
- std::move(pre_connection_helper_),
- std::make_unique<QuartcCryptoServerStreamHelper>(),
- std::make_unique<QuartcAlarmFactoryWrapper>(alarm_factory_),
- std::make_unique<QuartcPacketWriter>(packet_transport,
- config_.max_packet_size),
- this);
- // The dispatcher requires at least one call to |ProcessBufferedChlos| to
- // set the number of connections it is allowed to create.
- dispatcher_->ProcessBufferedChlos(/*max_connections_to_create=*/1);
-}
-
-void QuartcServerEndpoint::OnSessionCreated(QuartcSession* session) {
- session->SetDelegate(delegate_);
- delegate_->OnSessionCreated(session);
-}
-
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.h
deleted file mode 100644
index ea1a63f0e33..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.h
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_QUARTC_QUARTC_ENDPOINT_H_
-#define QUICHE_QUIC_QUARTC_QUARTC_ENDPOINT_H_
-
-#include <string>
-
-#include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h"
-#include "net/third_party/quiche/src/quic/core/quic_clock.h"
-#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_factory.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
-
-namespace quic {
-
-// Endpoint (client or server) in a peer-to-peer Quartc connection.
-class QuartcEndpoint {
- public:
- class Delegate : public QuartcSession::Delegate {
- public:
- virtual ~Delegate() = default;
-
- // Called when an endpoint creates a new session, before any packets are
- // processed or sent. The callee should perform any additional
- // configuration required, such as setting up congestion control, before
- // returning. |session| is owned by the endpoint, but remains safe to use
- // until another call to |OnSessionCreated| or |OnConnectionClosed| occurs,
- // at which point previous session may be destroyed.
- //
- // Callees must not change the |session|'s delegate. The Endpoint itself
- // manages the delegate and will forward calls.
- //
- // New calls to |OnSessionCreated| will only occur prior to
- // |OnConnectionWritable|, during initial connection negotiation.
- virtual void OnSessionCreated(QuartcSession* session) = 0;
- };
-
- virtual ~QuartcEndpoint() = default;
-
- // Connects the endpoint using the given session config. After |Connect| is
- // called, the endpoint will asynchronously create a session, then call
- // |Delegate::OnSessionCreated|.
- virtual void Connect(QuartcPacketTransport* packet_transport) = 0;
-};
-
-// Implementation of QuartcEndpoint which immediately (but asynchronously)
-// creates a session by scheduling a QuicAlarm. Only suitable for use with the
-// client perspective.
-class QuartcClientEndpoint : public QuartcEndpoint,
- public QuartcSession::Delegate {
- public:
- // |alarm_factory|, |clock|, and |delegate| are owned by the caller and must
- // outlive the endpoint.
- QuartcClientEndpoint(
- QuicAlarmFactory* alarm_factory,
- const QuicClock* clock,
- QuicRandom* random,
- QuartcEndpoint::Delegate* delegate,
- const QuartcSessionConfig& config,
- quiche::QuicheStringPiece serialized_server_config,
- std::unique_ptr<QuicVersionManager> version_manager = nullptr);
-
- void Connect(QuartcPacketTransport* packet_transport) override;
-
- // QuartcSession::Delegate overrides.
- void OnCryptoHandshakeComplete() override;
- void OnConnectionWritable() override;
- void OnIncomingStream(QuartcStream* stream) override;
- void OnCongestionControlChange(QuicBandwidth bandwidth_estimate,
- QuicBandwidth pacing_rate,
- QuicTime::Delta latest_rtt) override;
- void OnConnectionClosed(const QuicConnectionCloseFrame& frame,
- ConnectionCloseSource source) override;
- void OnMessageReceived(quiche::QuicheStringPiece message) override;
- void OnMessageSent(int64_t datagram_id) override;
- void OnMessageAcked(int64_t datagram_id, QuicTime receive_timestamp) override;
- void OnMessageLost(int64_t datagram_id) override;
-
- private:
- friend class CreateSessionDelegate;
- class CreateSessionDelegate : public QuicAlarm::Delegate {
- public:
- CreateSessionDelegate(QuartcClientEndpoint* endpoint)
- : endpoint_(endpoint) {}
-
- void OnAlarm() override { endpoint_->OnCreateSessionAlarm(); }
-
- private:
- QuartcClientEndpoint* endpoint_;
- };
-
- // Callback which occurs when |create_session_alarm_| fires.
- void OnCreateSessionAlarm();
-
- // Implementation of QuicAlarmFactory used by this endpoint. Unowned.
- QuicAlarmFactory* alarm_factory_;
-
- // Implementation of QuicClock used by this endpoint. Unowned.
- const QuicClock* clock_;
-
- // Delegate which receives callbacks for newly created sessions.
- QuartcEndpoint::Delegate* delegate_;
-
- // Server config. If valid, used to perform a 0-RTT connection.
- const std::string serialized_server_config_;
-
- // Version manager. May be injected to control version negotiation in tests.
- std::unique_ptr<QuicVersionManager> version_manager_;
-
- // Versions to be used when the next session is created. The session will
- // choose one of these versions for its connection attempt.
- //
- // If the connection does not succeed, the client session MAY try again using
- // another version from this list, or it MAY simply fail with a
- // QUIC_INVALID_VERSION error. The latter occurs when it is not possible to
- // upgrade a connection in-place (for example, if the way stream ids are
- // allocated changes between versions). This failure mode is handled by
- // narrowing |current_versions_| to one of that is mutually-supported and
- // reconnecting (with a new session).
- ParsedQuicVersionVector current_versions_;
-
- // Alarm for creating sessions asynchronously. The alarm is set when
- // Connect() is called. When it fires, the endpoint creates a session and
- // calls the delegate.
- std::unique_ptr<QuicAlarm> create_session_alarm_;
-
- // Helper used by QuicConnection.
- std::unique_ptr<QuicConnectionHelperInterface> connection_helper_;
-
- // Config to be used for new sessions.
- QuartcSessionConfig config_;
-
- // The currently-active session. Nullptr until |Connect| and
- // |Delegate::OnSessionCreated| are called.
- std::unique_ptr<QuartcSession> session_;
-
- QuartcPacketTransport* packet_transport_;
-};
-
-// Implementation of QuartcEndpoint which uses a QuartcDispatcher to listen for
-// an incoming CHLO and create a session when one arrives. Only suitable for
-// use with the server perspective.
-class QuartcServerEndpoint : public QuartcEndpoint,
- public QuartcDispatcher::Delegate {
- public:
- QuartcServerEndpoint(
- QuicAlarmFactory* alarm_factory,
- const QuicClock* clock,
- QuicRandom* random,
- QuartcEndpoint::Delegate* delegate,
- const QuartcSessionConfig& config,
- std::unique_ptr<QuicVersionManager> version_manager = nullptr);
-
- // Implements QuartcEndpoint.
- void Connect(QuartcPacketTransport* packet_transport) override;
-
- // Implements QuartcDispatcher::Delegate.
- void OnSessionCreated(QuartcSession* session) override;
-
- // Accessor to retrieve the server crypto config. May only be called after
- // Connect().
- quiche::QuicheStringPiece server_crypto_config() const {
- return crypto_config_.serialized_crypto_config;
- }
-
- const std::vector<ParsedQuicVersion> GetSupportedQuicVersions() const {
- return version_manager_->GetSupportedVersions();
- }
-
- private:
- // Implementation of QuicAlarmFactory used by this endpoint. Unowned.
- QuicAlarmFactory* alarm_factory_;
-
- // Delegate which receives callbacks for newly created sessions.
- QuartcEndpoint::Delegate* delegate_;
-
- // Config to be used for new sessions.
- QuartcSessionConfig config_;
-
- // Version manager. May be injected to control version negotiation in tests.
- std::unique_ptr<QuicVersionManager> version_manager_;
-
- // QuartcDispatcher waits for an incoming CHLO, then either rejects it or
- // creates a session to respond to it. The dispatcher owns all sessions it
- // creates.
- std::unique_ptr<QuartcDispatcher> dispatcher_;
-
- // This field is only available before connection was started.
- std::unique_ptr<QuartcConnectionHelper> pre_connection_helper_;
-
- // A configuration, containing public key, that may need to be passed to the
- // client to enable 0rtt.
- CryptoServerConfig crypto_config_;
-};
-
-} // namespace quic
-
-#endif // QUICHE_QUIC_QUARTC_QUARTC_ENDPOINT_H_
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint_test.cc
deleted file mode 100644
index d2f94202aa1..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint_test.cc
+++ /dev/null
@@ -1,251 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h"
-
-#include <utility>
-
-#include "net/third_party/quiche/src/quic/core/quic_versions.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_fakes.h"
-#include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
-#include "net/third_party/quiche/src/quic/test_tools/simulator/link.h"
-#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h"
-
-namespace quic {
-namespace {
-
-class QuartcEndpointTest : public QuicTest {
- protected:
- QuartcEndpointTest()
- : client_transport_(&simulator_,
- "client_transport",
- "server_transport",
- 10 * kDefaultMaxPacketSize),
- server_transport_(&simulator_,
- "server_transport",
- "client_transport",
- 10 * kDefaultMaxPacketSize),
- client_server_link_(&client_transport_,
- &server_transport_,
- QuicBandwidth::FromKBitsPerSecond(10000),
- QuicTime::Delta::FromMilliseconds(1)),
- server_endpoint_delegate_(&server_stream_delegate_,
- simulator_.GetClock()),
- server_endpoint_(std::make_unique<QuartcServerEndpoint>(
- simulator_.GetAlarmFactory(),
- simulator_.GetClock(),
- simulator_.GetRandomGenerator(),
- &server_endpoint_delegate_,
- QuartcSessionConfig())),
- client_endpoint_delegate_(&client_stream_delegate_,
- simulator_.GetClock()),
- client_endpoint_(std::make_unique<QuartcClientEndpoint>(
- simulator_.GetAlarmFactory(),
- simulator_.GetClock(),
- simulator_.GetRandomGenerator(),
- &client_endpoint_delegate_,
- QuartcSessionConfig(),
- /*serialized_server_config=*/"")) {
- // Make sure these versions are enabled since some tests use them.
- SetQuicReloadableFlag(quic_disable_version_q043, false);
- SetQuicReloadableFlag(quic_disable_version_q046, false);
- }
-
- simulator::Simulator simulator_;
-
- simulator::SimulatedQuartcPacketTransport client_transport_;
- simulator::SimulatedQuartcPacketTransport server_transport_;
- simulator::SymmetricLink client_server_link_;
-
- FakeQuartcStreamDelegate server_stream_delegate_;
- FakeQuartcEndpointDelegate server_endpoint_delegate_;
-
- std::unique_ptr<QuartcServerEndpoint> server_endpoint_;
-
- FakeQuartcStreamDelegate client_stream_delegate_;
- FakeQuartcEndpointDelegate client_endpoint_delegate_;
-
- std::unique_ptr<QuartcClientEndpoint> client_endpoint_;
-};
-
-// After calling Connect, the client endpoint must wait for an async callback.
-// The callback occurs after a finite amount of time and produces a session.
-TEST_F(QuartcEndpointTest, ClientCreatesSessionAsynchronously) {
- client_endpoint_->Connect(&client_transport_);
-
- EXPECT_EQ(client_endpoint_delegate_.session(), nullptr);
-
- EXPECT_TRUE(simulator_.RunUntil(
- [this] { return client_endpoint_delegate_.session() != nullptr; }));
-}
-
-// Tests that the server can negotiate for an older QUIC version if the client
-// attempts to connect using a newer version.
-TEST_F(QuartcEndpointTest,
- QUIC_TEST_DISABLED_IN_CHROME(ServerNegotiatesForOldVersion)) {
- // Reset the client endpoint to prefer version 46 but also be capable of
- // speaking version 43.
- ParsedQuicVersionVector client_versions;
- client_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46});
- client_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43});
- client_endpoint_ = std::make_unique<QuartcClientEndpoint>(
- simulator_.GetAlarmFactory(), simulator_.GetClock(),
- simulator_.GetRandomGenerator(), &client_endpoint_delegate_,
- QuartcSessionConfig(),
- /*serialized_server_config=*/"",
- std::make_unique<QuicVersionManager>(client_versions));
-
- // Reset the server endpoint to only speak version 43.
- ParsedQuicVersionVector server_versions;
- server_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43});
- server_endpoint_ = std::make_unique<QuartcServerEndpoint>(
- simulator_.GetAlarmFactory(), simulator_.GetClock(),
- simulator_.GetRandomGenerator(), &server_endpoint_delegate_,
- QuartcSessionConfig(),
- std::make_unique<QuicVersionManager>(server_versions));
-
- // The endpoints should be able to establish a connection using version 46.
- server_endpoint_->Connect(&server_transport_);
- client_endpoint_->Connect(&client_transport_);
-
- ASSERT_TRUE(simulator_.RunUntil([this] {
- return client_endpoint_delegate_.session() != nullptr &&
- client_endpoint_delegate_.session()->IsEncryptionEstablished() &&
- server_endpoint_delegate_.session() != nullptr &&
- server_endpoint_delegate_.session()->IsEncryptionEstablished();
- }));
- EXPECT_EQ(client_endpoint_delegate_.session()->connection()->version(),
- server_versions[0]);
- EXPECT_EQ(server_endpoint_delegate_.session()->connection()->version(),
- server_versions[0]);
-}
-
-// Tests that the server can accept connections from clients that use older
-// QUIC versions.
-TEST_F(QuartcEndpointTest,
- QUIC_TEST_DISABLED_IN_CHROME(ServerAcceptsOldVersion)) {
- // Reset the client endpoint to only speak version 43.
- ParsedQuicVersionVector client_versions;
- client_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43});
- client_endpoint_ = std::make_unique<QuartcClientEndpoint>(
- simulator_.GetAlarmFactory(), simulator_.GetClock(),
- simulator_.GetRandomGenerator(), &client_endpoint_delegate_,
- QuartcSessionConfig(),
- /*serialized_server_config=*/"",
- std::make_unique<QuicVersionManager>(client_versions));
-
- // Reset the server endpoint to prefer version 46 but also be capable of
- // speaking version 43.
- ParsedQuicVersionVector server_versions;
- server_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46});
- server_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43});
- server_endpoint_ = std::make_unique<QuartcServerEndpoint>(
- simulator_.GetAlarmFactory(), simulator_.GetClock(),
- simulator_.GetRandomGenerator(), &server_endpoint_delegate_,
- QuartcSessionConfig(),
- std::make_unique<QuicVersionManager>(server_versions));
-
- // The endpoints should be able to establish a connection using version 46.
- server_endpoint_->Connect(&server_transport_);
- client_endpoint_->Connect(&client_transport_);
-
- ASSERT_TRUE(simulator_.RunUntil([this] {
- return client_endpoint_delegate_.session() != nullptr &&
- client_endpoint_delegate_.session()->IsEncryptionEstablished() &&
- server_endpoint_delegate_.session() != nullptr &&
- server_endpoint_delegate_.session()->IsEncryptionEstablished();
- }));
- EXPECT_EQ(client_endpoint_delegate_.session()->connection()->version(),
- client_versions[0]);
- EXPECT_EQ(server_endpoint_delegate_.session()->connection()->version(),
- client_versions[0]);
-}
-
-// Tests that version negotiation fails when the client and server support
-// completely disjoint sets of versions.
-TEST_F(QuartcEndpointTest,
- QUIC_TEST_DISABLED_IN_CHROME(VersionNegotiationWithDisjointVersions)) {
- // Reset the client endpoint to only speak version 43.
- ParsedQuicVersionVector client_versions;
- client_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43});
- client_endpoint_ = std::make_unique<QuartcClientEndpoint>(
- simulator_.GetAlarmFactory(), simulator_.GetClock(),
- simulator_.GetRandomGenerator(), &client_endpoint_delegate_,
- QuartcSessionConfig(),
- /*serialized_server_config=*/"",
- std::make_unique<QuicVersionManager>(client_versions));
-
- // Reset the server endpoint to only speak version 46.
- ParsedQuicVersionVector server_versions;
- server_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46});
- server_endpoint_ = std::make_unique<QuartcServerEndpoint>(
- simulator_.GetAlarmFactory(), simulator_.GetClock(),
- simulator_.GetRandomGenerator(), &server_endpoint_delegate_,
- QuartcSessionConfig(),
- std::make_unique<QuicVersionManager>(server_versions));
-
- // The endpoints should be unable to establish a connection.
- server_endpoint_->Connect(&server_transport_);
- client_endpoint_->Connect(&client_transport_);
-
- // Note that the error is reported from the client and *not* the server. The
- // server sees an invalid version, sends a version negotiation packet, and
- // never gets a response, because the client stops sending when it can't find
- // a mutually supported versions.
- ASSERT_TRUE(simulator_.RunUntil([this] {
- return client_endpoint_delegate_.session() != nullptr &&
- client_endpoint_delegate_.session()->error() != QUIC_NO_ERROR;
- }));
- EXPECT_THAT(client_endpoint_delegate_.session()->error(),
- test::IsError(QUIC_INVALID_VERSION));
-}
-
-// Tests that the client endpoint can create a new session in order to continue
-// version negotiation.
-TEST_F(QuartcEndpointTest,
- QUIC_TEST_DISABLED_IN_CHROME(CreatesNewSessionWhenRequired)) {
- // Reset the client endpoint to prefer version 46 but also be capable of
- // speaking version 43.
- ParsedQuicVersionVector client_versions;
- client_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46});
- client_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43});
- client_endpoint_ = std::make_unique<QuartcClientEndpoint>(
- simulator_.GetAlarmFactory(), simulator_.GetClock(),
- simulator_.GetRandomGenerator(), &client_endpoint_delegate_,
- QuartcSessionConfig(),
- /*serialized_server_config=*/"",
- std::make_unique<QuicVersionManager>(client_versions));
-
- // Reset the server endpoint to only speak version 43.
- ParsedQuicVersionVector server_versions;
- server_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43});
- server_endpoint_ = std::make_unique<QuartcServerEndpoint>(
- simulator_.GetAlarmFactory(), simulator_.GetClock(),
- simulator_.GetRandomGenerator(), &server_endpoint_delegate_,
- QuartcSessionConfig(),
- std::make_unique<QuicVersionManager>(server_versions));
-
- // The endpoints should be able to establish a connection using version 46.
- server_endpoint_->Connect(&server_transport_);
- client_endpoint_->Connect(&client_transport_);
-
- ASSERT_TRUE(simulator_.RunUntil([this] {
- return client_endpoint_delegate_.session() != nullptr &&
- client_endpoint_delegate_.session()->IsEncryptionEstablished() &&
- server_endpoint_delegate_.session() != nullptr &&
- server_endpoint_delegate_.session()->IsEncryptionEstablished();
- }));
- EXPECT_EQ(client_endpoint_delegate_.session()->connection()->version(),
- server_versions[0]);
- EXPECT_EQ(server_endpoint_delegate_.session()->connection()->version(),
- server_versions[0]);
-
- EXPECT_EQ(2, client_endpoint_delegate_.num_sessions_created());
-}
-
-} // namespace
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc
deleted file mode 100644
index 280d936b25a..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc
+++ /dev/null
@@ -1,219 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/quartc/quartc_factory.h"
-
-#include <utility>
-
-#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
-#include "net/third_party/quiche/src/quic/core/quic_utils.h"
-#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h"
-#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
-#include "net/third_party/quiche/src/quic/core/uber_received_packet_manager.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_session.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
-
-namespace quic {
-
-std::unique_ptr<QuartcSession> CreateQuartcClientSession(
- const QuartcSessionConfig& quartc_session_config,
- const QuicClock* clock,
- QuicAlarmFactory* alarm_factory,
- QuicConnectionHelperInterface* connection_helper,
- const ParsedQuicVersionVector& supported_versions,
- quiche::QuicheStringPiece server_crypto_config,
- QuartcPacketTransport* packet_transport) {
- DCHECK(packet_transport);
-
- // QuartcSession will eventually own both |writer| and |quic_connection|.
- auto writer = std::make_unique<QuartcPacketWriter>(
- packet_transport, quartc_session_config.max_packet_size);
-
- // While the QuicConfig is not directly used by the connection, creating it
- // also sets flag values which must be set before creating the connection.
- QuicConfig quic_config = CreateQuicConfig(quartc_session_config);
-
- // |dummy_id| and |dummy_address| are used because Quartc network layer will
- // not use these two.
- QuicConnectionId dummy_id = QuicUtils::CreateZeroConnectionId(
- supported_versions[0].transport_version);
- QuicSocketAddress dummy_address(QuicIpAddress::Any4(), /*port=*/0);
- std::unique_ptr<QuicConnection> quic_connection = CreateQuicConnection(
- dummy_id, dummy_address, connection_helper, alarm_factory, writer.get(),
- Perspective::IS_CLIENT, supported_versions);
-
- // Quartc sets its own ack delay; get that ack delay and copy it over
- // to the QuicConfig so that it can be properly advertised to the peer
- // via transport parameter negotiation.
- quic_config.SetMaxAckDelayToSendMs(quic_connection->received_packet_manager()
- .max_ack_delay()
- .ToMilliseconds());
-
- return std::make_unique<QuartcClientSession>(
- std::move(quic_connection), quic_config, supported_versions, clock,
- std::move(writer),
- CreateCryptoClientConfig(quartc_session_config.pre_shared_key),
- server_crypto_config);
-}
-
-void ConfigureGlobalQuicSettings() {
- // Ensure that we don't drop data because QUIC streams refuse to buffer it.
- // TODO(b/120099046): Replace this with correct handling of WriteMemSlices().
- SetQuicFlag(FLAGS_quic_buffered_data_threshold,
- std::numeric_limits<int>::max());
-
- // Enable and request QUIC to include receive timestamps in ACK frames.
- SetQuicReloadableFlag(quic_send_timestamps, true);
-
- // Enable ACK_DECIMATION_WITH_REORDERING. It requires ack_decimation to be
- // false.
- SetQuicReloadableFlag(quic_enable_ack_decimation, false);
-
- // Note: flag settings have no effect for Exoblaze builds since
- // SetQuicReloadableFlag() gets stubbed out.
- SetQuicReloadableFlag(quic_unified_iw_options, true); // Enable IWXX opts.
- SetQuicReloadableFlag(quic_bbr_flexible_app_limited, true); // Enable BBR9.
-}
-
-QuicConfig CreateQuicConfig(const QuartcSessionConfig& quartc_session_config) {
- // TODO(b/124398962): Figure out a better way to initialize QUIC flags.
- // Creating a config shouldn't have global side-effects on flags. However,
- // this has the advantage of ensuring that flag values stay in sync with the
- // options requested by configs, so simply splitting the config and flag
- // settings doesn't seem preferable.
- ConfigureGlobalQuicSettings();
-
- QuicTagVector copt;
- copt.push_back(kNSTP);
-
- // Enable and request QUIC to include receive timestamps in ACK frames.
- copt.push_back(kSTMP);
-
- // Enable ACK_DECIMATION_WITH_REORDERING. It requires ack_decimation to be
- // false.
- copt.push_back(kAKD2);
-
- // Use unlimited decimation in order to reduce number of unbundled ACKs.
- copt.push_back(kAKDU);
-
- // Enable time-based loss detection.
- copt.push_back(kTIME);
-
- copt.push_back(kBBR3); // Stay in low-gain until in-flight < BDP.
- copt.push_back(kBBR5); // 40 RTT ack aggregation.
- copt.push_back(kBBR9); // Ignore app-limited if enough data is in flight.
- copt.push_back(kBBQ1); // 2.773 pacing gain in STARTUP.
- copt.push_back(kBBQ2); // 2.0 CWND gain in STARTUP.
- copt.push_back(k1RTT); // Exit STARTUP after 1 RTT with no gains.
- copt.push_back(kIW10); // 10-packet (14600 byte) initial cwnd.
-
- if (!quartc_session_config.enable_tail_loss_probe) {
- copt.push_back(kNTLP);
- }
-
- // TODO(b/112192153): Test and possible enable slower startup when pipe
- // filling is ready to use. Slower startup is kBBRS.
-
- QuicConfig quic_config;
-
- // Use the limits for the session & stream flow control. The default 16KB
- // limit leads to significantly undersending (not reaching BWE on the outgoing
- // bitrate) due to blocked frames, and it leads to high latency (and one-way
- // delay). Setting it to its limits is not going to cause issues (our streams
- // are small generally, and if we were to buffer 24MB it wouldn't be the end
- // of the world). We can consider setting different limits in future (e.g. 1MB
- // stream, 1.5MB session). It's worth noting that on 1mbps bitrate, limit of
- // 24MB can capture approx 4 minutes of the call, and the default increase in
- // size of the window (half of the window size) is approximately 2 minutes of
- // the call.
- quic_config.SetInitialSessionFlowControlWindowToSend(
- kSessionReceiveWindowLimit);
- quic_config.SetInitialStreamFlowControlWindowToSend(
- kStreamReceiveWindowLimit);
- quic_config.SetConnectionOptionsToSend(copt);
- quic_config.SetClientConnectionOptions(copt);
- if (quartc_session_config.max_time_before_crypto_handshake >
- QuicTime::Delta::Zero()) {
- quic_config.set_max_time_before_crypto_handshake(
- quartc_session_config.max_time_before_crypto_handshake);
- }
- if (quartc_session_config.max_idle_time_before_crypto_handshake >
- QuicTime::Delta::Zero()) {
- quic_config.set_max_idle_time_before_crypto_handshake(
- quartc_session_config.max_idle_time_before_crypto_handshake);
- }
- if (quartc_session_config.idle_network_timeout > QuicTime::Delta::Zero()) {
- quic_config.SetIdleNetworkTimeout(
- quartc_session_config.idle_network_timeout);
- }
-
- // The ICE transport provides a unique 5-tuple for each connection. Save
- // overhead by omitting the connection id.
- quic_config.SetBytesForConnectionIdToSend(0);
-
- // Allow up to 1000 incoming streams at once. Quartc streams typically contain
- // one audio or video frame and close immediately. However, when a video frame
- // becomes larger than one packet, there is some delay between the start and
- // end of each stream. The default maximum of 100 only leaves about 1 second
- // of headroom (Quartc sends ~30 video frames per second) before QUIC starts
- // to refuse incoming streams. Back-pressure should clear backlogs of
- // incomplete streams, but targets 1 second for recovery. Increasing the
- // number of open streams gives sufficient headroom to recover before QUIC
- // refuses new streams.
- quic_config.SetMaxBidirectionalStreamsToSend(1000);
-
- return quic_config;
-}
-
-std::unique_ptr<QuicConnection> CreateQuicConnection(
- QuicConnectionId connection_id,
- const QuicSocketAddress& peer_address,
- QuicConnectionHelperInterface* connection_helper,
- QuicAlarmFactory* alarm_factory,
- QuicPacketWriter* packet_writer,
- Perspective perspective,
- ParsedQuicVersionVector supported_versions) {
- auto quic_connection = std::make_unique<QuicConnection>(
- connection_id, peer_address, connection_helper, alarm_factory,
- packet_writer,
- /*owns_writer=*/false, perspective, supported_versions);
- quic_connection->SetMaxPacketLength(
- packet_writer->GetMaxPacketSize(peer_address));
-
- QuicSentPacketManager& sent_packet_manager =
- quic_connection->sent_packet_manager();
- UberReceivedPacketManager& received_packet_manager =
- quic_connection->received_packet_manager();
-
- // Default delayed ack time is 25ms.
- // If data packets are sent less often (e.g. because p-time was modified),
- // we would force acks to be sent every 25ms regardless, increasing
- // overhead. Since generally we guarantee a packet every 20ms, changing
- // this value should have miniscule effect on quality on good connections,
- // but on poor connections, changing this number significantly reduced the
- // number of ack-only packets.
- // The p-time can go up to as high as 120ms, and when it does, it's
- // when the low overhead is the most important thing. Ideally it should be
- // above 120ms, but it cannot be higher than 0.5*RTO, which equals to 100ms.
- received_packet_manager.set_max_ack_delay(
- QuicTime::Delta::FromMilliseconds(100));
- sent_packet_manager.set_peer_max_ack_delay(
- QuicTime::Delta::FromMilliseconds(100));
-
- quic_connection->set_fill_up_link_during_probing(true);
-
- // We start ack decimation after 15 packets. Typically, we would see
- // 1-2 crypto handshake packets, one media packet, and 10 probing packets.
- // We want to get acks for the probing packets as soon as possible,
- // but we can start using ack decimation right after first probing completes.
- // The default was to not start ack decimation for the first 100 packets.
- quic_connection->set_min_received_before_ack_decimation(15);
-
- return quic_connection;
-}
-
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.h
deleted file mode 100644
index 665b8e7111d..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_QUARTC_QUARTC_FACTORY_H_
-#define QUICHE_QUIC_QUARTC_QUARTC_FACTORY_H_
-
-#include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h"
-#include "net/third_party/quiche/src/quic/core/quic_connection.h"
-#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_session.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
-
-namespace quic {
-
-struct QuartcSessionConfig {
- // If a pre-shared cryptographic key is available for this session, specify it
- // here. This value will only be used if non-empty.
- std::string pre_shared_key;
-
- // The maximum size of the packet can be written with the packet writer.
- // 1200 bytes by default.
- QuicPacketLength max_packet_size = 1200;
-
- // Timeouts for the crypto handshake. Set them to higher values to
- // prevent closing the session before it started on a slow network.
- // Zero entries are ignored and QUIC defaults are used in that case.
- QuicTime::Delta max_idle_time_before_crypto_handshake =
- QuicTime::Delta::Zero();
- QuicTime::Delta max_time_before_crypto_handshake = QuicTime::Delta::Zero();
- QuicTime::Delta idle_network_timeout = QuicTime::Delta::Zero();
-
- // Tail loss probes (TLP) are enabled by default, but it may be useful to
- // disable them in tests. We can also consider disabling them in production
- // if we discover that tail loss probes add overhead in low bitrate audio.
- bool enable_tail_loss_probe = true;
-};
-
-// Creates a new QuartcClientSession using the given configuration.
-std::unique_ptr<QuartcSession> CreateQuartcClientSession(
- const QuartcSessionConfig& quartc_session_config,
- const QuicClock* clock,
- QuicAlarmFactory* alarm_factory,
- QuicConnectionHelperInterface* connection_helper,
- const ParsedQuicVersionVector& supported_versions,
- quiche::QuicheStringPiece server_crypto_config,
- QuartcPacketTransport* packet_transport);
-
-// Configures global settings, such as supported quic versions.
-// Must execute on QUIC thread.
-void ConfigureGlobalQuicSettings();
-
-// Must execute on QUIC thread.
-QuicConfig CreateQuicConfig(const QuartcSessionConfig& quartc_session_config);
-
-std::unique_ptr<QuicConnection> CreateQuicConnection(
- QuicConnectionId connection_id,
- const QuicSocketAddress& peer_address,
- QuicConnectionHelperInterface* connection_helper,
- QuicAlarmFactory* alarm_factory,
- QuicPacketWriter* packet_writer,
- Perspective perspective,
- ParsedQuicVersionVector supported_versions);
-
-} // namespace quic
-
-#endif // QUICHE_QUIC_QUARTC_QUARTC_FACTORY_H_
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_fakes.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_fakes.h
deleted file mode 100644
index 94bf1add1e7..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_fakes.h
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_QUARTC_QUARTC_FAKES_H_
-#define QUICHE_QUIC_QUARTC_QUARTC_FAKES_H_
-
-#include <string>
-
-#include "net/third_party/quiche/src/quic/core/quic_clock.h"
-#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
-#include "net/third_party/quiche/src/quic/core/quic_types.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_session.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_stream.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
-
-namespace quic {
-
-class FakeQuartcEndpointDelegate : public QuartcEndpoint::Delegate {
- public:
- explicit FakeQuartcEndpointDelegate(QuartcStream::Delegate* stream_delegate,
- const QuicClock* clock)
- : stream_delegate_(stream_delegate), clock_(clock) {}
-
- void OnSessionCreated(QuartcSession* session) override {
- CHECK_NE(session, nullptr);
- session_ = session;
- session_->StartCryptoHandshake();
- ++num_sessions_created_;
- }
-
- void OnConnectionWritable() override {
- QUIC_LOG(INFO) << "Connection writable!";
- if (!writable_time_.IsInitialized()) {
- writable_time_ = clock_->Now();
- }
- }
-
- // Called when peers have established forward-secure encryption
- void OnCryptoHandshakeComplete() override {
- QUIC_LOG(INFO) << "Crypto handshake complete!";
- crypto_handshake_time_ = clock_->Now();
- }
-
- // Called when connection closes locally, or remotely by peer.
- void OnConnectionClosed(const QuicConnectionCloseFrame& /*frame*/,
- ConnectionCloseSource /*source*/) override {
- connected_ = false;
- }
-
- // Called when an incoming QUIC stream is created.
- void OnIncomingStream(QuartcStream* quartc_stream) override {
- last_incoming_stream_ = quartc_stream;
- last_incoming_stream_->SetDelegate(stream_delegate_);
- }
-
- void OnMessageReceived(quiche::QuicheStringPiece message) override {
- incoming_messages_.emplace_back(message);
- }
-
- void OnMessageSent(int64_t datagram_id) override {
- sent_datagram_ids_.push_back(datagram_id);
- }
-
- void OnMessageAcked(int64_t datagram_id,
- QuicTime receive_timestamp) override {
- acked_datagram_id_to_receive_timestamp_.emplace(datagram_id,
- receive_timestamp);
- }
-
- void OnMessageLost(int64_t datagram_id) override {
- lost_datagram_ids_.push_back(datagram_id);
- }
-
- void OnCongestionControlChange(QuicBandwidth /*bandwidth_estimate*/,
- QuicBandwidth /*pacing_rate*/,
- QuicTime::Delta /*latest_rtt*/) override {}
-
- QuartcSession* session() { return session_; }
-
- int num_sessions_created() const { return num_sessions_created_; }
-
- QuartcStream* last_incoming_stream() const { return last_incoming_stream_; }
-
- // Returns all received messages.
- const std::vector<std::string>& incoming_messages() const {
- return incoming_messages_;
- }
-
- // Returns all sent datagram ids in the order sent.
- const std::vector<int64_t>& sent_datagram_ids() const {
- return sent_datagram_ids_;
- }
-
- // Returns all ACKEd datagram ids in the order ACKs were received.
- const std::map<int64_t, QuicTime>& acked_datagram_id_to_receive_timestamp()
- const {
- return acked_datagram_id_to_receive_timestamp_;
- }
-
- const std::vector<int64_t>& lost_datagram_ids() const {
- return lost_datagram_ids_;
- }
-
- bool connected() const { return connected_; }
- QuicTime writable_time() const { return writable_time_; }
- QuicTime crypto_handshake_time() const { return crypto_handshake_time_; }
-
- private:
- // Current session.
- QuartcSession* session_ = nullptr;
-
- // Number of new sessions created by the endpoint.
- int num_sessions_created_ = 0;
-
- QuartcStream* last_incoming_stream_;
- std::vector<std::string> incoming_messages_;
- std::vector<int64_t> sent_datagram_ids_;
- std::map<int64_t, QuicTime> acked_datagram_id_to_receive_timestamp_;
- std::vector<int64_t> lost_datagram_ids_;
- bool connected_ = true;
- QuartcStream::Delegate* stream_delegate_;
- QuicTime writable_time_ = QuicTime::Zero();
- QuicTime crypto_handshake_time_ = QuicTime::Zero();
- const QuicClock* clock_;
-};
-
-class FakeQuartcStreamDelegate : public QuartcStream::Delegate {
- public:
- size_t OnReceived(QuartcStream* stream,
- iovec* iov,
- size_t iov_length,
- bool /*fin*/) override {
- size_t bytes_consumed = 0;
- for (size_t i = 0; i < iov_length; ++i) {
- received_data_[stream->id()] += std::string(
- static_cast<const char*>(iov[i].iov_base), iov[i].iov_len);
- bytes_consumed += iov[i].iov_len;
- }
- return bytes_consumed;
- }
-
- void OnClose(QuartcStream* stream) override {
- errors_[stream->id()] = stream->stream_error();
- }
-
- void OnBufferChanged(QuartcStream* /*stream*/) override {}
-
- bool has_data() { return !received_data_.empty(); }
- std::map<QuicStreamId, std::string> data() { return received_data_; }
-
- QuicRstStreamErrorCode stream_error(QuicStreamId id) { return errors_[id]; }
-
- private:
- std::map<QuicStreamId, std::string> received_data_;
- std::map<QuicStreamId, QuicRstStreamErrorCode> errors_;
-};
-
-} // namespace quic
-
-#endif // QUICHE_QUIC_QUARTC_QUARTC_FAKES_H_
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_interval_counter.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_interval_counter.h
deleted file mode 100644
index fe3b083c695..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_interval_counter.h
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_QUARTC_QUARTC_INTERVAL_COUNTER_H_
-#define QUICHE_QUIC_QUARTC_QUARTC_INTERVAL_COUNTER_H_
-
-#include <stddef.h>
-#include <vector>
-
-#include "net/third_party/quiche/src/quic/core/quic_interval.h"
-#include "net/third_party/quiche/src/quic/core/quic_interval_set.h"
-
-namespace quic {
-
-// QuartcIntervalCounter counts the number of times each value appears within
-// a set of potentially overlapping intervals.
-//
-// QuartcIntervalCounter is not intended for widespread use. Consider replacing
-// it with a full interval-map if more use cases arise.
-//
-// QuartcIntervalCounter is only suitable for cases where the maximum count is
-// expected to remain low. (For example, counting the number of times the same
-// portions of stream data are lost.) It is inefficient when the maximum count
-// becomes high.
-template <typename T>
-class QuartcIntervalCounter {
- public:
- // Adds |interval| to the counter. The count associated with each value in
- // |interval| is incremented by one. |interval| may overlap with previous
- // intervals added to the counter.
- //
- // For each possible value:
- // - If the value is present in both |interval| and the counter, the count
- // associated with that value is incremented by one.
- // - If the value is present in |interval| but not counter, the count
- // associated with that value is set to one (incremented from zero).
- // - If the value is absent from |interval|, the count is unchanged.
- //
- // Time complexity is O(|MaxCount| * the complexity of adding an interval to a
- // QuicIntervalSet).
- void AddInterval(QuicInterval<T> interval);
-
- // Removes an interval from the counter. This method may be called to prune
- // irrelevant intervals from the counter. This is useful to prevent unbounded
- // growth.
- //
- // Time complexity is O(|MaxCount| * the complexity of removing an interval
- // from a QuicIntervalSet).
- void RemoveInterval(QuicInterval<T> interval);
-
- // Returns the maximum number of times any single value has appeared in
- // intervals added to the counter.
- //
- // Time complexity is constant.
- size_t MaxCount() const { return intervals_by_count_.size(); }
-
- // Returns the maximum number of times a particular value has appeared in
- // intervals added to the counter.
- //
- // Time complexity is O(|MaxCount| * log(number of non-contiguous intervals)).
- size_t Count(const T& value) const;
-
- private:
- // Each entry in this vector represents the intervals of values counted at
- // least i + 1 times, where i is the index of the entry.
- //
- // Whenever an interval is added to the counter, each value in the interval is
- // added to the first entry which does not already contain that value. If
- // part of an interval is already present in the last entry, a new entry is
- // added containing that part.
- //
- // Note that this means each value present in one of the interval sets will be
- // present in all previous sets.
- std::vector<QuicIntervalSet<T>> intervals_by_count_;
-};
-
-template <typename T>
-void QuartcIntervalCounter<T>::AddInterval(QuicInterval<T> interval) {
- // After the Nth iteration, |leftover| contains the parts of |interval| that
- // are already present in the first N entries. These parts of |interval| have
- // been added to the counter more than N times.
- QuicIntervalSet<T> leftover(interval);
- for (auto& intervals : intervals_by_count_) {
- QuicIntervalSet<T> tmp = leftover;
- leftover.Intersection(intervals);
- intervals.Union(tmp);
- }
-
- // Whatever ranges are still in |leftover| are already in all the entries
- // Add a new entry containing |leftover|.
- if (!leftover.Empty()) {
- intervals_by_count_.push_back(leftover);
- }
-}
-
-template <typename T>
-void QuartcIntervalCounter<T>::RemoveInterval(QuicInterval<T> interval) {
- // Remove the interval from each entry in the vector, popping any entries that
- // become empty.
- for (size_t i = intervals_by_count_.size(); i > 0; --i) {
- intervals_by_count_[i - 1].Difference(interval);
- if (intervals_by_count_[i - 1].Empty()) {
- intervals_by_count_.pop_back();
- }
- }
-}
-
-template <typename T>
-size_t QuartcIntervalCounter<T>::Count(const T& value) const {
- // The index of the last entry containing |value| gives its count.
- for (size_t i = intervals_by_count_.size(); i > 0; --i) {
- if (intervals_by_count_[i - 1].Contains(value)) {
- return i;
- }
- }
- return 0;
-}
-
-} // namespace quic
-
-#endif // QUICHE_QUIC_QUARTC_QUARTC_INTERVAL_COUNTER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_interval_counter_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_interval_counter_test.cc
deleted file mode 100644
index 028aaf2dab6..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_interval_counter_test.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/quartc/quartc_interval_counter.h"
-
-#include "net/third_party/quiche/src/quic/core/quic_interval.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
-
-namespace quic {
-namespace {
-
-class QuartcIntervalCounterTest : public QuicTest {
- protected:
- QuartcIntervalCounter<int> counter_;
-};
-
-void ExpectCount(const QuartcIntervalCounter<int>& counter,
- QuicInterval<int> interval,
- size_t count) {
- for (int i = interval.min(); i < interval.max(); ++i) {
- EXPECT_EQ(counter.Count(i), count) << "i=" << i;
- }
-}
-
-TEST_F(QuartcIntervalCounterTest, InitiallyEmpty) {
- EXPECT_EQ(counter_.MaxCount(), 0u);
-}
-
-TEST_F(QuartcIntervalCounterTest, SameInterval) {
- counter_.AddInterval(QuicInterval<int>(0, 6));
- EXPECT_EQ(counter_.MaxCount(), 1u);
- ExpectCount(counter_, QuicInterval<int>(0, 6), 1);
-
- counter_.AddInterval(QuicInterval<int>(0, 6));
- EXPECT_EQ(counter_.MaxCount(), 2u);
- ExpectCount(counter_, QuicInterval<int>(0, 6), 2);
-}
-
-TEST_F(QuartcIntervalCounterTest, DisjointIntervals) {
- counter_.AddInterval(QuicInterval<int>(0, 5));
- EXPECT_EQ(counter_.MaxCount(), 1u);
- ExpectCount(counter_, QuicInterval<int>(0, 5), 1);
- ExpectCount(counter_, QuicInterval<int>(5, 10), 0);
-
- counter_.AddInterval(QuicInterval<int>(5, 10));
- EXPECT_EQ(counter_.MaxCount(), 1u);
- ExpectCount(counter_, QuicInterval<int>(0, 5), 1);
- ExpectCount(counter_, QuicInterval<int>(5, 10), 1);
-}
-
-TEST_F(QuartcIntervalCounterTest, OverlappingIntervals) {
- counter_.AddInterval(QuicInterval<int>(0, 6));
- EXPECT_EQ(counter_.MaxCount(), 1u);
- ExpectCount(counter_, QuicInterval<int>(0, 6), 1);
- ExpectCount(counter_, QuicInterval<int>(6, 10), 0);
-
- counter_.AddInterval(QuicInterval<int>(5, 10));
- EXPECT_EQ(counter_.MaxCount(), 2u);
- ExpectCount(counter_, QuicInterval<int>(0, 5), 1);
- EXPECT_EQ(counter_.Count(5), 2u);
- ExpectCount(counter_, QuicInterval<int>(6, 10), 1);
-}
-
-TEST_F(QuartcIntervalCounterTest, IntervalsWithGapThenOverlap) {
- counter_.AddInterval(QuicInterval<int>(0, 4));
- EXPECT_EQ(counter_.MaxCount(), 1u);
- ExpectCount(counter_, QuicInterval<int>(0, 4), 1);
- ExpectCount(counter_, QuicInterval<int>(4, 10), 0);
-
- counter_.AddInterval(QuicInterval<int>(7, 10));
- EXPECT_EQ(counter_.MaxCount(), 1u);
- ExpectCount(counter_, QuicInterval<int>(0, 4), 1);
- ExpectCount(counter_, QuicInterval<int>(4, 7), 0);
- ExpectCount(counter_, QuicInterval<int>(7, 10), 1);
-
- counter_.AddInterval(QuicInterval<int>(3, 8));
- EXPECT_EQ(counter_.MaxCount(), 2u);
- ExpectCount(counter_, QuicInterval<int>(0, 3), 1);
- EXPECT_EQ(counter_.Count(3), 2u);
- ExpectCount(counter_, QuicInterval<int>(4, 7), 1);
- EXPECT_EQ(counter_.Count(7), 2u);
- ExpectCount(counter_, QuicInterval<int>(8, 10), 1);
-}
-
-TEST_F(QuartcIntervalCounterTest, RemoveIntervals) {
- counter_.AddInterval(QuicInterval<int>(0, 5));
- EXPECT_EQ(counter_.MaxCount(), 1u);
- ExpectCount(counter_, QuicInterval<int>(0, 5), 1);
-
- counter_.AddInterval(QuicInterval<int>(4, 10));
- EXPECT_EQ(counter_.MaxCount(), 2u);
- ExpectCount(counter_, QuicInterval<int>(0, 4), 1);
- EXPECT_EQ(counter_.Count(4), 2u);
- ExpectCount(counter_, QuicInterval<int>(5, 10), 1);
-
- counter_.RemoveInterval(QuicInterval<int>(0, 5));
- EXPECT_EQ(counter_.MaxCount(), 1u);
- ExpectCount(counter_, QuicInterval<int>(0, 5), 0);
- ExpectCount(counter_, QuicInterval<int>(5, 10), 1);
-
- counter_.RemoveInterval(QuicInterval<int>(5, 10));
- EXPECT_EQ(counter_.MaxCount(), 0u);
- ExpectCount(counter_, QuicInterval<int>(0, 10), 0);
-}
-
-} // namespace
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.cc
deleted file mode 100644
index 376fac02c8c..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.cc
+++ /dev/null
@@ -1,271 +0,0 @@
-// Copyright (c) 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h"
-
-#include <cstdint>
-#include <utility>
-
-#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h"
-#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
-
-namespace quic {
-
-QuartcSendChannel::QuartcSendChannel(QuartcMultiplexer* multiplexer,
- uint64_t id,
- QuicBufferAllocator* allocator,
- Delegate* delegate)
- : multiplexer_(multiplexer),
- id_(id),
- encoded_length_(QuicDataWriter::GetVarInt62Len(id_)),
- allocator_(allocator),
- delegate_(delegate) {}
-
-QuartcStream* QuartcSendChannel::CreateOutgoingBidirectionalStream() {
- if (!session_) {
- QUIC_LOG(DFATAL) << "Session is not ready to write yet; channel_id=" << id_;
- return nullptr;
- }
- QuicMemSlice id_slice = EncodeChannelId();
-
- QuartcStream* stream = session_->CreateOutgoingBidirectionalStream();
- QuicConsumedData consumed =
- stream->WriteMemSlices(QuicMemSliceSpan(&id_slice), /*fin=*/false);
- DCHECK_EQ(consumed.bytes_consumed, encoded_length_);
- return stream;
-}
-
-bool QuartcSendChannel::SendOrQueueMessage(QuicMemSliceSpan message,
- int64_t datagram_id) {
- if (!session_) {
- QUIC_LOG(DFATAL) << "Session is not ready to write yet; channel_id=" << id_
- << "datagram size=" << message.total_length();
- return false;
- }
- QuicMemSliceStorage storage(nullptr, 0, nullptr, 0); // Empty storage.
- storage.Append(EncodeChannelId());
-
- message.ConsumeAll(
- [&storage](QuicMemSlice slice) { storage.Append(std::move(slice)); });
-
- // Allocate a unique datagram id so that notifications can be routed back to
- // the right send channel.
- int64_t unique_datagram_id = multiplexer_->AllocateDatagramId(this);
- multiplexer_to_user_datagram_ids_[unique_datagram_id] = datagram_id;
-
- return session_->SendOrQueueMessage(storage.ToSpan(), unique_datagram_id);
-}
-
-void QuartcSendChannel::OnMessageSent(int64_t datagram_id) {
- // Map back to the caller-chosen |datagram_id|.
- datagram_id = multiplexer_to_user_datagram_ids_[datagram_id];
- delegate_->OnMessageSent(datagram_id);
-}
-
-void QuartcSendChannel::OnMessageAcked(int64_t datagram_id,
- QuicTime receive_timestamp) {
- // Map back to the caller-chosen |datagram_id|.
- auto it = multiplexer_to_user_datagram_ids_.find(datagram_id);
- if (it == multiplexer_to_user_datagram_ids_.end()) {
- QUIC_LOG(DFATAL) << "Datagram acked/lost multiple times; datagram_id="
- << datagram_id;
- return;
- }
- delegate_->OnMessageAcked(it->second, receive_timestamp);
- multiplexer_to_user_datagram_ids_.erase(it);
-}
-
-void QuartcSendChannel::OnMessageLost(int64_t datagram_id) {
- // Map back to the caller-chosen |datagram_id|.
- auto it = multiplexer_to_user_datagram_ids_.find(datagram_id);
- if (it == multiplexer_to_user_datagram_ids_.end()) {
- QUIC_LOG(DFATAL) << "Datagram acked/lost multiple times; datagram_id="
- << datagram_id;
- return;
- }
- delegate_->OnMessageLost(it->second);
- multiplexer_to_user_datagram_ids_.erase(it);
-}
-
-void QuartcSendChannel::OnSessionCreated(QuartcSession* session) {
- session_ = session;
-}
-
-QuicMemSlice QuartcSendChannel::EncodeChannelId() {
- QuicUniqueBufferPtr buffer = MakeUniqueBuffer(allocator_, encoded_length_);
- QuicDataWriter writer(encoded_length_, buffer.get());
- writer.WriteVarInt62(id_);
- return QuicMemSlice(std::move(buffer), encoded_length_);
-}
-
-QuartcMultiplexer::QuartcMultiplexer(
- QuicBufferAllocator* allocator,
- QuartcSessionEventDelegate* session_delegate,
- QuartcReceiveChannel* default_receive_channel)
- : allocator_(allocator),
- session_delegate_(session_delegate),
- default_receive_channel_(default_receive_channel) {
- CHECK_NE(session_delegate_, nullptr);
- CHECK_NE(default_receive_channel_, nullptr);
-}
-
-QuartcSendChannel* QuartcMultiplexer::CreateSendChannel(
- uint64_t channel_id,
- QuartcSendChannel::Delegate* delegate) {
- send_channels_.push_back(std::make_unique<QuartcSendChannel>(
- this, channel_id, allocator_, delegate));
- if (session_) {
- send_channels_.back()->OnSessionCreated(session_);
- }
- return send_channels_.back().get();
-}
-
-void QuartcMultiplexer::RegisterReceiveChannel(uint64_t channel_id,
- QuartcReceiveChannel* channel) {
- if (channel == nullptr) {
- receive_channels_.erase(channel_id);
- return;
- }
- auto& registered_channel = receive_channels_[channel_id];
- if (registered_channel) {
- QUIC_LOG(DFATAL) << "Attempted to overwrite existing channel_id="
- << channel_id;
- return;
- }
- registered_channel = channel;
-}
-
-int64_t QuartcMultiplexer::AllocateDatagramId(QuartcSendChannel* channel) {
- send_channels_by_datagram_id_[next_datagram_id_] = channel;
- return next_datagram_id_++;
-}
-
-void QuartcMultiplexer::OnSessionCreated(QuartcSession* session) {
- for (auto& channel : send_channels_) {
- channel->OnSessionCreated(session);
- }
- session_ = session;
- session_delegate_->OnSessionCreated(session);
-}
-
-void QuartcMultiplexer::OnCryptoHandshakeComplete() {
- session_delegate_->OnCryptoHandshakeComplete();
-}
-
-void QuartcMultiplexer::OnConnectionWritable() {
- session_delegate_->OnConnectionWritable();
-}
-
-void QuartcMultiplexer::OnIncomingStream(QuartcStream* stream) {
- stream->SetDelegate(this);
-}
-
-void QuartcMultiplexer::OnCongestionControlChange(
- QuicBandwidth bandwidth_estimate,
- QuicBandwidth pacing_rate,
- QuicTime::Delta latest_rtt) {
- session_delegate_->OnCongestionControlChange(bandwidth_estimate, pacing_rate,
- latest_rtt);
-}
-
-void QuartcMultiplexer::OnConnectionClosed(
- const QuicConnectionCloseFrame& frame,
- ConnectionCloseSource source) {
- session_delegate_->OnConnectionClosed(frame, source);
-}
-
-void QuartcMultiplexer::OnMessageReceived(quiche::QuicheStringPiece message) {
- QuicDataReader reader(message);
- QuicVariableLengthIntegerLength channel_id_length =
- reader.PeekVarInt62Length();
-
- uint64_t channel_id;
- if (!reader.ReadVarInt62(&channel_id)) {
- QUIC_LOG(DFATAL) << "Received message without properly encoded channel id";
- return;
- }
-
- QuartcReceiveChannel* channel = default_receive_channel_;
- auto it = receive_channels_.find(channel_id);
- if (it != receive_channels_.end()) {
- channel = it->second;
- }
-
- channel->OnMessageReceived(channel_id, message.substr(channel_id_length));
-}
-
-void QuartcMultiplexer::OnMessageSent(int64_t datagram_id) {
- auto it = send_channels_by_datagram_id_.find(datagram_id);
- if (it == send_channels_by_datagram_id_.end()) {
- return;
- }
- it->second->OnMessageSent(datagram_id);
-}
-
-void QuartcMultiplexer::OnMessageAcked(int64_t datagram_id,
- QuicTime receive_timestamp) {
- auto it = send_channels_by_datagram_id_.find(datagram_id);
- if (it == send_channels_by_datagram_id_.end()) {
- return;
- }
- it->second->OnMessageAcked(datagram_id, receive_timestamp);
- send_channels_by_datagram_id_.erase(it);
-}
-
-void QuartcMultiplexer::OnMessageLost(int64_t datagram_id) {
- auto it = send_channels_by_datagram_id_.find(datagram_id);
- if (it == send_channels_by_datagram_id_.end()) {
- return;
- }
- it->second->OnMessageLost(datagram_id);
- send_channels_by_datagram_id_.erase(it);
-}
-
-size_t QuartcMultiplexer::OnReceived(QuartcStream* stream,
- iovec* iov,
- size_t iov_length,
- bool /*fin*/) {
- if (iov == nullptr || iov_length <= 0) {
- return 0;
- }
-
- QuicDataReader reader(static_cast<char*>(iov[0].iov_base), iov[0].iov_len);
- QuicVariableLengthIntegerLength channel_id_length =
- reader.PeekVarInt62Length();
-
- uint64_t channel_id;
- if (reader.BytesRemaining() >= channel_id_length) {
- // Fast path, have enough data to read immediately.
- if (!reader.ReadVarInt62(&channel_id)) {
- return 0;
- }
- } else {
- // Slow path, need to coalesce multiple iovecs.
- std::string data;
- for (size_t i = 0; i < iov_length; ++i) {
- data += std::string(static_cast<char*>(iov[i].iov_base), iov[i].iov_len);
- }
- QuicDataReader combined_reader(data);
- if (!combined_reader.ReadVarInt62(&channel_id)) {
- return 0;
- }
- }
-
- QuartcReceiveChannel* channel = default_receive_channel_;
- auto it = receive_channels_.find(channel_id);
- if (it != receive_channels_.end()) {
- channel = it->second;
- }
- channel->OnIncomingStream(channel_id, stream);
- return channel_id_length;
-}
-
-void QuartcMultiplexer::OnClose(QuartcStream* /*stream*/) {}
-
-void QuartcMultiplexer::OnBufferChanged(QuartcStream* /*stream*/) {}
-
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h
deleted file mode 100644
index 1e6c2e5dbdf..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright (c) 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_QUARTC_QUARTC_MULTIPLEXER_H_
-#define QUICHE_QUIC_QUARTC_QUARTC_MULTIPLEXER_H_
-
-#include <cstdint>
-
-#include "net/third_party/quiche/src/quic/core/quic_time.h"
-#include "net/third_party/quiche/src/quic/core/quic_types.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_session.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_stream.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
-
-namespace quic {
-
-class QuartcMultiplexer;
-
-// A single, multiplexed send channel within a Quartc session. A send channel
-// wraps send-side operations with an outgoing multiplex id.
-class QuartcSendChannel {
- public:
- class Delegate {
- public:
- virtual ~Delegate() = default;
-
- // Called when a message with |datagram_id| is sent by this channel.
- virtual void OnMessageSent(int64_t datagram_id) = 0;
-
- // Called when a message sent on this channel with |datagram_id| is acked.
- // |receive_timestamp| indicates when the peer received this message,
- // according to the peer's clock.
- virtual void OnMessageAcked(int64_t datagram_id,
- QuicTime receive_timestamp) = 0;
-
- // Called when a message sent on this channel with |datagram_id| is lost.
- virtual void OnMessageLost(int64_t datagram_id) = 0;
- };
-
- QuartcSendChannel(QuartcMultiplexer* multiplexer,
- uint64_t id,
- QuicBufferAllocator* allocator,
- Delegate* delegate);
- virtual ~QuartcSendChannel() = default;
-
- // Creates a new, outgoing stream on this channel.
- //
- // Automatically writes the channel id to the start of the stream. The caller
- // SHOULD create a |ScopedPacketFlusher| before calling this function to
- // prevent the channel id from being sent by itself.
- QuartcStream* CreateOutgoingBidirectionalStream();
-
- // Writes |message| to the session. Prepends the channel's send id before any
- // following message data.
- bool SendOrQueueMessage(QuicMemSliceSpan message, int64_t datagram_id);
-
- // Gets the current largest message payload for this channel. Returns the
- // largest payload size supported by the session minus overhead required to
- // encode this channel's send id.
- QuicPacketLength GetCurrentLargestMessagePayload() const;
-
- // The following are called by the multiplexer to deliver message
- // notifications. The |datagram_id| passed to these is unique per-message,
- // and must be translated back to the sender's chosen datagram_id.
- void OnMessageSent(int64_t datagram_id);
- void OnMessageAcked(int64_t datagram_id, QuicTime receive_timestamp);
- void OnMessageLost(int64_t datagram_id);
- void OnSessionCreated(QuartcSession* session);
-
- private:
- // Creates a mem slice containing a varint-62 encoded channel id.
- QuicMemSlice EncodeChannelId();
-
- QuartcMultiplexer* const multiplexer_;
- const uint64_t id_;
- const QuicVariableLengthIntegerLength encoded_length_;
- QuicBufferAllocator* const allocator_;
- Delegate* const delegate_;
-
- QuartcSession* session_;
-
- // Map of multiplexer-chosen to user/caller-specified datagram ids. The user
- // may specify any number as a datagram's id. This number does not have to be
- // unique across channels (nor even within a single channel). In order
- // to demux sent, acked, and lost messages, the multiplexer assigns a globally
- // unique id to each message. This map is used to restore the original caller
- // datagram id before issuing callbacks.
- QuicHashMap<int64_t, int64_t> multiplexer_to_user_datagram_ids_;
-};
-
-// A single, multiplexed receive channel within a Quartc session. A receive
-// channel is a delegate which accepts incoming streams and datagrams on one (or
-// more) channel ids.
-class QuartcReceiveChannel {
- public:
- virtual ~QuartcReceiveChannel() = default;
-
- // Called when a new incoming stream arrives on this channel.
- virtual void OnIncomingStream(uint64_t channel_id, QuartcStream* stream) = 0;
-
- // Called when a message is recieved by this channel.
- virtual void OnMessageReceived(uint64_t channel_id,
- quiche::QuicheStringPiece message) = 0;
-};
-
-// Delegate for session-wide events.
-class QuartcSessionEventDelegate {
- public:
- virtual ~QuartcSessionEventDelegate() = default;
-
- virtual void OnSessionCreated(QuartcSession* session) = 0;
- virtual void OnCryptoHandshakeComplete() = 0;
- virtual void OnConnectionWritable() = 0;
- virtual void OnCongestionControlChange(QuicBandwidth bandwidth_estimate,
- QuicBandwidth pacing_rate,
- QuicTime::Delta latest_rtt) = 0;
- virtual void OnConnectionClosed(const QuicConnectionCloseFrame& frame,
- ConnectionCloseSource source) = 0;
-};
-
-// A multiplexer capable of sending and receiving data on multiple channels.
-class QuartcMultiplexer : public QuartcEndpoint::Delegate,
- public QuartcStream::Delegate {
- public:
- // Creates a new multiplexer. |session_delegate| handles all session-wide
- // events, while |default_receive_channel| handles incoming data on unknown
- // or unregistered channel ids. Neither |session_delegate| nor
- // |default_receive_channel| may be nullptr, and both must outlive the
- // multiplexer.
- QuartcMultiplexer(QuicBufferAllocator* allocator,
- QuartcSessionEventDelegate* session_delegate,
- QuartcReceiveChannel* default_receive_channel);
-
- // Creates a new send channel. The channel is owned by the multiplexer, and
- // references to it must not outlive the multiplexer.
- QuartcSendChannel* CreateSendChannel(uint64_t channel_id,
- QuartcSendChannel::Delegate* delegate);
-
- // Registers a receiver for incoming data on |channel_id|.
- void RegisterReceiveChannel(uint64_t channel_id,
- QuartcReceiveChannel* channel);
-
- // Allocates a datagram id to |channel|.
- int64_t AllocateDatagramId(QuartcSendChannel* channel);
-
- // QuartcEndpoint::Delegate overrides.
- void OnSessionCreated(QuartcSession* session) override;
-
- // QuartcSession::Delegate overrides.
- void OnCryptoHandshakeComplete() override;
- void OnConnectionWritable() override;
- void OnIncomingStream(QuartcStream* stream) override;
- void OnCongestionControlChange(QuicBandwidth bandwidth_estimate,
- QuicBandwidth pacing_rate,
- QuicTime::Delta latest_rtt) override;
- void OnConnectionClosed(const QuicConnectionCloseFrame& frame,
- ConnectionCloseSource source) override;
- void OnMessageReceived(quiche::QuicheStringPiece message) override;
- void OnMessageSent(int64_t datagram_id) override;
- void OnMessageAcked(int64_t datagram_id, QuicTime receive_timestamp) override;
- void OnMessageLost(int64_t datagram_id) override;
-
- // QuartcStream::Delegate overrides.
- size_t OnReceived(QuartcStream* stream,
- iovec* iov,
- size_t iov_length,
- bool fin) override;
- void OnClose(QuartcStream* stream) override;
- void OnBufferChanged(QuartcStream* stream) override;
-
- private:
- QuicBufferAllocator* const allocator_;
- QuartcSessionEventDelegate* const session_delegate_;
-
- QuartcSession* session_ = nullptr;
- std::vector<std::unique_ptr<QuartcSendChannel>> send_channels_;
- QuicHashMap<uint64_t, QuartcReceiveChannel*> receive_channels_;
- QuartcReceiveChannel* default_receive_channel_ = nullptr;
-
- int64_t next_datagram_id_ = 1;
- QuicHashMap<int64_t, QuartcSendChannel*> send_channels_by_datagram_id_;
-};
-
-} // namespace quic
-
-#endif // QUICHE_QUIC_QUARTC_QUARTC_MULTIPLEXER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer_test.cc
deleted file mode 100644
index 024b67d8a94..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer_test.cc
+++ /dev/null
@@ -1,496 +0,0 @@
-// Copyright (c) 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h"
-
-#include <memory>
-#include <utility>
-
-#include "net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h"
-#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h"
-#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h"
-#include "net/third_party/quiche/src/quic/core/quic_time.h"
-#include "net/third_party/quiche/src/quic/core/quic_types.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_test_mem_slice_vector.h"
-#include "net/third_party/quiche/src/quic/quartc/counting_packet_filter.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_fakes.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_session.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_stream.h"
-#include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
-#include "net/third_party/quiche/src/quic/test_tools/simulator/link.h"
-#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
-
-namespace quic {
-namespace {
-
-using ::testing::ElementsAreArray;
-using ::testing::Gt;
-using ::testing::IsEmpty;
-using ::testing::Pair;
-
-constexpr QuicTime::Delta kPropagationDelay =
- QuicTime::Delta::FromMilliseconds(10);
-
-class FakeSessionEventDelegate : public QuartcSessionEventDelegate {
- public:
- void OnSessionCreated(QuartcSession* session) override {
- session->StartCryptoHandshake();
- session_ = session;
- }
-
- void OnConnectionWritable() override { ++writable_count_; }
-
- void OnCryptoHandshakeComplete() override { ++handshake_count_; }
-
- void OnConnectionClosed(const QuicConnectionCloseFrame& frame,
- ConnectionCloseSource source) override {
- error_ = frame.quic_error_code;
- close_source_ = source;
- }
-
- void OnCongestionControlChange(QuicBandwidth bandwidth_estimate,
- QuicBandwidth pacing_rate,
- QuicTime::Delta latest_rtt) override {
- latest_bandwidth_estimate_ = bandwidth_estimate;
- latest_pacing_rate_ = pacing_rate;
- latest_rtt_ = latest_rtt;
- }
-
- QuartcSession* session() { return session_; }
- int writable_count() const { return writable_count_; }
- int handshake_count() const { return handshake_count_; }
- QuicErrorCode error() const { return error_; }
- ConnectionCloseSource close_source() const { return close_source_; }
- QuicBandwidth latest_bandwidth_estimate() const {
- return latest_bandwidth_estimate_;
- }
- QuicBandwidth latest_pacing_rate() const { return latest_pacing_rate_; }
- QuicTime::Delta latest_rtt() const { return latest_rtt_; }
-
- private:
- QuartcSession* session_ = nullptr;
- int writable_count_ = 0;
- int handshake_count_ = 0;
- QuicErrorCode error_ = QUIC_NO_ERROR;
- ConnectionCloseSource close_source_;
- QuicBandwidth latest_bandwidth_estimate_ = QuicBandwidth::Zero();
- QuicBandwidth latest_pacing_rate_ = QuicBandwidth::Zero();
- QuicTime::Delta latest_rtt_ = QuicTime::Delta::Zero();
-};
-
-class FakeSendDelegate : public QuartcSendChannel::Delegate {
- public:
- void OnMessageSent(int64_t datagram_id) override {
- datagrams_sent_.push_back(datagram_id);
- }
-
- void OnMessageAcked(int64_t datagram_id,
- QuicTime receive_timestamp) override {
- datagrams_acked_.push_back({datagram_id, receive_timestamp});
- }
-
- void OnMessageLost(int64_t datagram_id) override {
- datagrams_lost_.push_back(datagram_id);
- }
-
- const std::vector<int64_t>& datagrams_sent() const { return datagrams_sent_; }
- const std::vector<std::pair<int64_t, QuicTime>>& datagrams_acked() const {
- return datagrams_acked_;
- }
- const std::vector<int64_t>& datagrams_lost() const { return datagrams_lost_; }
-
- private:
- std::vector<int64_t> datagrams_sent_;
- std::vector<std::pair<int64_t, QuicTime>> datagrams_acked_;
- std::vector<int64_t> datagrams_lost_;
-};
-
-class FakeReceiveDelegate : public QuartcReceiveChannel,
- public QuartcStream::Delegate {
- public:
- const std::vector<std::pair<uint64_t, std::string>> messages_received()
- const {
- return messages_received_;
- }
-
- void OnIncomingStream(uint64_t channel_id, QuartcStream* stream) override {
- stream->SetDelegate(this);
- stream_to_channel_id_[stream] = channel_id;
- }
-
- void OnMessageReceived(uint64_t channel_id,
- quiche::QuicheStringPiece message) override {
- messages_received_.emplace_back(channel_id, message);
- }
-
- // Stream delegate overrides.
- size_t OnReceived(QuartcStream* stream,
- iovec* iov,
- size_t iov_length,
- bool fin) override {
- if (!fin) {
- return 0;
- }
-
- size_t bytes = 0;
- std::string message;
- for (size_t i = 0; i < iov_length; ++i) {
- message +=
- std::string(static_cast<char*>(iov[i].iov_base), iov[i].iov_len);
- bytes += iov[i].iov_len;
- }
- QUIC_LOG(INFO) << "Received " << bytes << " byte message on channel "
- << stream_to_channel_id_[stream];
- messages_received_.emplace_back(stream_to_channel_id_[stream], message);
- return bytes;
- }
-
- void OnClose(QuartcStream* stream) override {
- stream_to_channel_id_.erase(stream);
- }
-
- void OnBufferChanged(QuartcStream* /*stream*/) override {}
-
- private:
- std::vector<std::pair<uint64_t, std::string>> messages_received_;
- QuicUnorderedMap<QuartcStream*, uint64_t> stream_to_channel_id_;
-};
-
-class QuartcMultiplexerTest : public QuicTest {
- public:
- QuartcMultiplexerTest()
- : simulator_(),
- client_transport_(&simulator_,
- "client_transport",
- "server_transport",
- 10 * kDefaultMaxPacketSize),
- server_transport_(&simulator_,
- "server_transport",
- "client_transport",
- 10 * kDefaultMaxPacketSize),
- client_filter_(&simulator_, "client_filter", &client_transport_),
- client_server_link_(&client_filter_,
- &server_transport_,
- QuicBandwidth::FromKBitsPerSecond(10 * 1000),
- kPropagationDelay),
- client_multiplexer_(simulator_.GetStreamSendBufferAllocator(),
- &client_session_delegate_,
- &client_default_receiver_),
- server_multiplexer_(simulator_.GetStreamSendBufferAllocator(),
- &server_session_delegate_,
- &server_default_receiver_),
- client_endpoint_(std::make_unique<QuartcClientEndpoint>(
- simulator_.GetAlarmFactory(),
- simulator_.GetClock(),
- simulator_.GetRandomGenerator(),
- &client_multiplexer_,
- quic::QuartcSessionConfig(),
- /*serialized_server_config=*/"")),
- server_endpoint_(std::make_unique<QuartcServerEndpoint>(
- simulator_.GetAlarmFactory(),
- simulator_.GetClock(),
- simulator_.GetRandomGenerator(),
- &server_multiplexer_,
- quic::QuartcSessionConfig())) {
- // TODO(b/150224094): Re-enable TLS handshake.
- // TODO(b/150236522): Parametrize by QUIC version.
- quic::test::DisableQuicVersionsWithTls();
- }
-
- void Connect() {
- client_endpoint_->Connect(&client_transport_);
- server_endpoint_->Connect(&server_transport_);
- ASSERT_TRUE(simulator_.RunUntil([this]() {
- return client_session_delegate_.writable_count() > 0 &&
- server_session_delegate_.writable_count() > 0;
- }));
- }
-
- void Disconnect() {
- client_session_delegate_.session()->CloseConnection("test");
- server_session_delegate_.session()->CloseConnection("test");
- }
-
- protected:
- QuartcMultiplexer* client_multiplexer() { return &client_multiplexer_; }
-
- QuartcMultiplexer* server_multiplexer() { return &server_multiplexer_; }
-
- simulator::Simulator simulator_;
-
- simulator::SimulatedQuartcPacketTransport client_transport_;
- simulator::SimulatedQuartcPacketTransport server_transport_;
- simulator::CountingPacketFilter client_filter_;
- simulator::SymmetricLink client_server_link_;
-
- FakeSessionEventDelegate client_session_delegate_;
- FakeSessionEventDelegate server_session_delegate_;
-
- FakeReceiveDelegate client_default_receiver_;
- FakeReceiveDelegate server_default_receiver_;
-
- QuartcMultiplexer client_multiplexer_;
- QuartcMultiplexer server_multiplexer_;
-
- std::unique_ptr<QuartcClientEndpoint> client_endpoint_;
- std::unique_ptr<QuartcServerEndpoint> server_endpoint_;
-};
-
-TEST_F(QuartcMultiplexerTest, MultiplexMessages) {
- Connect();
-
- FakeSendDelegate send_delegate_1;
- QuartcSendChannel* send_channel_1 =
- client_multiplexer()->CreateSendChannel(1, &send_delegate_1);
- FakeSendDelegate send_delegate_2;
- QuartcSendChannel* send_channel_2 =
- client_multiplexer()->CreateSendChannel(2, &send_delegate_2);
-
- FakeReceiveDelegate receive_delegate_1;
- server_multiplexer()->RegisterReceiveChannel(1, &receive_delegate_1);
-
- int num_messages = 10;
- std::vector<std::pair<uint64_t, std::string>> messages_1;
- messages_1.reserve(num_messages);
- std::vector<std::pair<uint64_t, std::string>> messages_2;
- messages_2.reserve(num_messages);
- std::vector<int64_t> messages_sent_1;
- std::vector<int64_t> messages_sent_2;
- std::vector<testing::Matcher<std::pair<int64_t, QuicTime>>> ack_matchers_1;
- std::vector<testing::Matcher<std::pair<int64_t, QuicTime>>> ack_matchers_2;
- for (int i = 0; i < num_messages; ++i) {
- messages_1.emplace_back(1, quiche::QuicheStrCat("message for 1: ", i));
- test::QuicTestMemSliceVector slice_1(
- {std::make_pair(const_cast<char*>(messages_1.back().second.data()),
- messages_1.back().second.size())});
- send_channel_1->SendOrQueueMessage(slice_1.span(), i);
- messages_sent_1.push_back(i);
- ack_matchers_1.push_back(Pair(i, Gt(QuicTime::Zero())));
-
- messages_2.emplace_back(2, quiche::QuicheStrCat("message for 2: ", i));
- test::QuicTestMemSliceVector slice_2(
- {std::make_pair(const_cast<char*>(messages_2.back().second.data()),
- messages_2.back().second.size())});
- // Use i + 5 as the datagram id for channel 2, so that some of the ids
- // overlap and some are disjoint.
- send_channel_2->SendOrQueueMessage(slice_2.span(), i + 5);
- messages_sent_2.push_back(i + 5);
- ack_matchers_2.push_back(Pair(i + 5, Gt(QuicTime::Zero())));
- }
-
- EXPECT_TRUE(simulator_.RunUntil([&send_delegate_1, &send_delegate_2]() {
- return send_delegate_1.datagrams_acked().size() == 10 &&
- send_delegate_2.datagrams_acked().size() == 10;
- }));
-
- EXPECT_EQ(send_delegate_1.datagrams_sent(), messages_sent_1);
- EXPECT_EQ(send_delegate_2.datagrams_sent(), messages_sent_2);
-
- EXPECT_EQ(receive_delegate_1.messages_received(), messages_1);
- EXPECT_EQ(server_default_receiver_.messages_received(), messages_2);
-
- EXPECT_THAT(send_delegate_1.datagrams_acked(),
- ElementsAreArray(ack_matchers_1));
- EXPECT_THAT(send_delegate_2.datagrams_acked(),
- ElementsAreArray(ack_matchers_2));
-}
-
-TEST_F(QuartcMultiplexerTest, MultiplexStreams) {
- FakeSendDelegate send_delegate_1;
- QuartcSendChannel* send_channel_1 =
- client_multiplexer()->CreateSendChannel(1, &send_delegate_1);
- FakeSendDelegate send_delegate_2;
- QuartcSendChannel* send_channel_2 =
- client_multiplexer()->CreateSendChannel(2, &send_delegate_2);
-
- FakeQuartcStreamDelegate fake_send_stream_delegate;
-
- FakeReceiveDelegate receive_delegate_1;
- server_multiplexer()->RegisterReceiveChannel(1, &receive_delegate_1);
-
- Connect();
-
- int num_messages = 10;
- std::vector<std::pair<uint64_t, std::string>> messages_1;
- messages_1.reserve(num_messages);
- std::vector<std::pair<uint64_t, std::string>> messages_2;
- messages_2.reserve(num_messages);
- for (int i = 0; i < num_messages; ++i) {
- messages_1.emplace_back(1, quiche::QuicheStrCat("message for 1: ", i));
- test::QuicTestMemSliceVector slice_1(
- {std::make_pair(const_cast<char*>(messages_1.back().second.data()),
- messages_1.back().second.size())});
- QuartcStream* stream_1 =
- send_channel_1->CreateOutgoingBidirectionalStream();
- stream_1->SetDelegate(&fake_send_stream_delegate);
- stream_1->WriteMemSlices(slice_1.span(), /*fin=*/true);
-
- messages_2.emplace_back(2, quiche::QuicheStrCat("message for 2: ", i));
- test::QuicTestMemSliceVector slice_2(
- {std::make_pair(const_cast<char*>(messages_2.back().second.data()),
- messages_2.back().second.size())});
- QuartcStream* stream_2 =
- send_channel_2->CreateOutgoingBidirectionalStream();
- stream_2->SetDelegate(&fake_send_stream_delegate);
- stream_2->WriteMemSlices(slice_2.span(), /*fin=*/true);
- }
-
- EXPECT_TRUE(simulator_.RunUntilOrTimeout(
- [this, &receive_delegate_1]() {
- return receive_delegate_1.messages_received().size() == 10 &&
- server_default_receiver_.messages_received().size() == 10;
- },
- QuicTime::Delta::FromSeconds(5)));
-
- EXPECT_EQ(receive_delegate_1.messages_received(), messages_1);
- EXPECT_EQ(server_default_receiver_.messages_received(), messages_2);
-}
-
-// Tests that datagram-lost callbacks are invoked on the right send channel
-// delegate, and that they work with overlapping datagram ids.
-TEST_F(QuartcMultiplexerTest, MultiplexLostDatagrams) {
- Connect();
- ASSERT_TRUE(simulator_.RunUntil([this]() {
- return client_session_delegate_.handshake_count() > 0 &&
- server_session_delegate_.handshake_count() > 0;
- }));
-
- // Just drop everything we try to send.
- client_filter_.set_packets_to_drop(30);
-
- FakeSendDelegate send_delegate_1;
- QuartcSendChannel* send_channel_1 =
- client_multiplexer()->CreateSendChannel(1, &send_delegate_1);
- FakeSendDelegate send_delegate_2;
- QuartcSendChannel* send_channel_2 =
- client_multiplexer()->CreateSendChannel(2, &send_delegate_2);
-
- FakeQuartcStreamDelegate fake_send_stream_delegate;
-
- FakeReceiveDelegate receive_delegate_1;
- server_multiplexer()->RegisterReceiveChannel(1, &receive_delegate_1);
-
- int num_messages = 10;
- std::vector<std::pair<uint64_t, std::string>> messages_1;
- messages_1.reserve(num_messages);
- std::vector<std::pair<uint64_t, std::string>> messages_2;
- messages_2.reserve(num_messages);
- std::vector<int64_t> messages_sent_1;
- std::vector<int64_t> messages_sent_2;
- for (int i = 0; i < num_messages; ++i) {
- messages_1.emplace_back(1, quiche::QuicheStrCat("message for 1: ", i));
- test::QuicTestMemSliceVector slice_1(
- {std::make_pair(const_cast<char*>(messages_1.back().second.data()),
- messages_1.back().second.size())});
- send_channel_1->SendOrQueueMessage(slice_1.span(), i);
- messages_sent_1.push_back(i);
-
- messages_2.emplace_back(2, quiche::QuicheStrCat("message for 2: ", i));
- test::QuicTestMemSliceVector slice_2(
- {std::make_pair(const_cast<char*>(messages_2.back().second.data()),
- messages_2.back().second.size())});
- // Use i + 5 as the datagram id for channel 2, so that some of the ids
- // overlap and some are disjoint.
- send_channel_2->SendOrQueueMessage(slice_2.span(), i + 5);
- messages_sent_2.push_back(i + 5);
- }
-
- // Now send something retransmittable to prompt loss detection.
- // If we never send anything retransmittable, we will never get acks, and
- // never detect losses.
- messages_1.emplace_back(
- 1, quiche::QuicheStrCat("message for 1: ", num_messages));
- test::QuicTestMemSliceVector slice(
- {std::make_pair(const_cast<char*>(messages_1.back().second.data()),
- messages_1.back().second.size())});
- QuartcStream* stream_1 = send_channel_1->CreateOutgoingBidirectionalStream();
- stream_1->SetDelegate(&fake_send_stream_delegate);
- stream_1->WriteMemSlices(slice.span(), /*fin=*/true);
-
- EXPECT_TRUE(simulator_.RunUntilOrTimeout(
- [&send_delegate_1, &send_delegate_2]() {
- return send_delegate_1.datagrams_lost().size() == 10 &&
- send_delegate_2.datagrams_lost().size() == 10;
- },
- QuicTime::Delta::FromSeconds(60)));
-
- EXPECT_EQ(send_delegate_1.datagrams_lost(), messages_sent_1);
- EXPECT_EQ(send_delegate_2.datagrams_lost(), messages_sent_2);
-
- EXPECT_THAT(send_delegate_1.datagrams_acked(), IsEmpty());
- EXPECT_THAT(send_delegate_2.datagrams_acked(), IsEmpty());
-
- EXPECT_THAT(receive_delegate_1.messages_received(), IsEmpty());
- EXPECT_THAT(server_default_receiver_.messages_received(), IsEmpty());
-}
-
-TEST_F(QuartcMultiplexerTest, UnregisterReceiveChannel) {
- Connect();
-
- FakeSendDelegate send_delegate;
- QuartcSendChannel* send_channel =
- client_multiplexer()->CreateSendChannel(1, &send_delegate);
- FakeQuartcStreamDelegate fake_send_stream_delegate;
-
- FakeReceiveDelegate receive_delegate;
- server_multiplexer()->RegisterReceiveChannel(1, &receive_delegate);
- server_multiplexer()->RegisterReceiveChannel(1, nullptr);
-
- int num_messages = 10;
- std::vector<std::pair<uint64_t, std::string>> messages;
- messages.reserve(num_messages);
- std::vector<int64_t> messages_sent;
- std::vector<testing::Matcher<std::pair<int64_t, QuicTime>>> ack_matchers;
- for (int i = 0; i < num_messages; ++i) {
- messages.emplace_back(1, quiche::QuicheStrCat("message for 1: ", i));
- test::QuicTestMemSliceVector slice(
- {std::make_pair(const_cast<char*>(messages.back().second.data()),
- messages.back().second.size())});
- send_channel->SendOrQueueMessage(slice.span(), i);
- messages_sent.push_back(i);
- ack_matchers.push_back(Pair(i, Gt(QuicTime::Zero())));
- }
-
- EXPECT_TRUE(simulator_.RunUntil([&send_delegate]() {
- return send_delegate.datagrams_acked().size() == 10;
- }));
-
- EXPECT_EQ(send_delegate.datagrams_sent(), messages_sent);
- EXPECT_EQ(server_default_receiver_.messages_received(), messages);
- EXPECT_THAT(send_delegate.datagrams_acked(), ElementsAreArray(ack_matchers));
-}
-
-TEST_F(QuartcMultiplexerTest, CloseEvent) {
- Connect();
- Disconnect();
-
- EXPECT_THAT(client_session_delegate_.error(),
- test::IsError(QUIC_CONNECTION_CANCELLED));
- EXPECT_THAT(server_session_delegate_.error(),
- test::IsError(QUIC_CONNECTION_CANCELLED));
-}
-
-TEST_F(QuartcMultiplexerTest, CongestionEvent) {
- Connect();
- ASSERT_TRUE(simulator_.RunUntil([this]() {
- return client_session_delegate_.handshake_count() > 0 &&
- server_session_delegate_.handshake_count() > 0;
- }));
-
- EXPECT_GT(client_session_delegate_.latest_bandwidth_estimate(),
- QuicBandwidth::Zero());
- EXPECT_GT(client_session_delegate_.latest_pacing_rate(),
- QuicBandwidth::Zero());
- EXPECT_GT(client_session_delegate_.latest_rtt(), QuicTime::Delta::Zero());
-}
-
-} // namespace
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_packet_writer.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_packet_writer.cc
deleted file mode 100644
index f67cc774ea8..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_packet_writer.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h"
-
-#include <utility>
-
-namespace quic {
-
-std::unique_ptr<PerPacketOptions> QuartcPerPacketOptions::Clone() const {
- return std::make_unique<QuartcPerPacketOptions>(*this);
-}
-
-QuartcPacketWriter::QuartcPacketWriter(QuartcPacketTransport* packet_transport,
- QuicByteCount max_packet_size)
- : packet_transport_(packet_transport), max_packet_size_(max_packet_size) {}
-
-WriteResult QuartcPacketWriter::WritePacket(
- const char* buffer,
- size_t buf_len,
- const QuicIpAddress& /*self_address*/,
- const QuicSocketAddress& /*peer_address*/,
- PerPacketOptions* options) {
- DCHECK(packet_transport_);
-
- QuartcPacketTransport::PacketInfo info;
- QuartcPerPacketOptions* quartc_options =
- static_cast<QuartcPerPacketOptions*>(options);
- if (quartc_options && quartc_options->connection) {
- info.packet_number =
- quartc_options->connection->packet_creator().packet_number();
- }
- int bytes_written = packet_transport_->Write(buffer, buf_len, info);
- if (bytes_written <= 0) {
- writable_ = false;
- return WriteResult(WRITE_STATUS_BLOCKED, EWOULDBLOCK);
- }
- return WriteResult(WRITE_STATUS_OK, bytes_written);
-}
-
-bool QuartcPacketWriter::IsWriteBlocked() const {
- return !writable_;
-}
-
-QuicByteCount QuartcPacketWriter::GetMaxPacketSize(
- const QuicSocketAddress& /*peer_address*/) const {
- return max_packet_size_;
-}
-
-void QuartcPacketWriter::SetWritable() {
- writable_ = true;
-}
-
-bool QuartcPacketWriter::SupportsReleaseTime() const {
- return false;
-}
-
-bool QuartcPacketWriter::IsBatchMode() const {
- return false;
-}
-
-char* QuartcPacketWriter::GetNextWriteLocation(
- const QuicIpAddress& /*self_address*/,
- const QuicSocketAddress& /*peer_address*/) {
- return nullptr;
-}
-
-WriteResult QuartcPacketWriter::Flush() {
- return WriteResult(WRITE_STATUS_OK, 0);
-}
-
-void QuartcPacketWriter::SetPacketTransportDelegate(
- QuartcPacketTransport::Delegate* delegate) {
- packet_transport_->SetDelegate(delegate);
-}
-
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h
deleted file mode 100644
index f3eb885fd53..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_QUARTC_QUARTC_PACKET_WRITER_H_
-#define QUICHE_QUIC_QUARTC_QUARTC_PACKET_WRITER_H_
-
-#include "net/third_party/quiche/src/quic/core/quic_connection.h"
-#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h"
-#include "net/third_party/quiche/src/quic/core/quic_types.h"
-
-namespace quic {
-
-// Send and receive packets, like a virtual UDP socket. For example, this
-// could be implemented by WebRTC's IceTransport.
-class QuartcPacketTransport {
- public:
- // Additional metadata provided for each packet written.
- struct PacketInfo {
- QuicPacketNumber packet_number;
- };
-
- // Delegate for packet transport callbacks. Note that the delegate is not
- // thread-safe. Packet transport implementations must ensure that callbacks
- // are synchronized with all other work done by QUIC.
- class Delegate {
- public:
- virtual ~Delegate() = default;
-
- // Called whenever the transport can write.
- virtual void OnTransportCanWrite() = 0;
-
- // Called when the transport receives a packet.
- virtual void OnTransportReceived(const char* data, size_t data_len) = 0;
- };
-
- virtual ~QuartcPacketTransport() {}
-
- // Called by the QuartcPacketWriter when writing packets to the network.
- // Return the number of written bytes. Return 0 if the write is blocked.
- virtual int Write(const char* buffer,
- size_t buf_len,
- const PacketInfo& info) = 0;
-
- // Sets the delegate which must be called when the transport can write or
- // a packet is received. QUIC sets |delegate| to a nonnull pointer when it
- // is ready to process incoming packets and sets |delegate| to nullptr before
- // QUIC is deleted. Implementations may assume |delegate| remains valid until
- // it is set to nullptr.
- virtual void SetDelegate(Delegate* delegate) = 0;
-};
-
-struct QuartcPerPacketOptions : public PerPacketOptions {
- std::unique_ptr<PerPacketOptions> Clone() const override;
-
- // The connection which is sending this packet.
- QuicConnection* connection = nullptr;
-};
-
-// Implements a QuicPacketWriter using a QuartcPacketTransport, which allows a
-// QuicConnection to use (for example), a WebRTC IceTransport.
-class QuartcPacketWriter : public QuicPacketWriter {
- public:
- QuartcPacketWriter(QuartcPacketTransport* packet_transport,
- QuicByteCount max_packet_size);
- ~QuartcPacketWriter() override {}
-
- // The QuicConnection calls WritePacket and the QuicPacketWriter writes them
- // to the QuartcSession::PacketTransport.
- WriteResult WritePacket(const char* buffer,
- size_t buf_len,
- const QuicIpAddress& self_address,
- const QuicSocketAddress& peer_address,
- PerPacketOptions* options) override;
-
- // Whether the underneath |transport_| is blocked. If this returns true,
- // outgoing QUIC packets are queued by QuicConnection until SetWritable() is
- // called.
- bool IsWriteBlocked() const override;
-
- // Maximum size of the QUIC packet which can be written. Users such as WebRTC
- // can set the value through the QuartcFactoryConfig without updating the QUIC
- // code.
- QuicByteCount GetMaxPacketSize(
- const QuicSocketAddress& peer_address) const override;
-
- // Sets the packet writer to a writable (non-blocked) state.
- void SetWritable() override;
-
- bool SupportsReleaseTime() const override;
-
- bool IsBatchMode() const override;
-
- char* GetNextWriteLocation(const QuicIpAddress& self_address,
- const QuicSocketAddress& peer_address) override;
-
- WriteResult Flush() override;
-
- void SetPacketTransportDelegate(QuartcPacketTransport::Delegate* delegate);
-
- private:
- // QuartcPacketWriter will not own the transport.
- QuartcPacketTransport* packet_transport_;
- // The maximum size of the packet can be written by this writer.
- QuicByteCount max_packet_size_;
-
- // Whether packets can be written.
- bool writable_ = false;
-};
-
-} // namespace quic
-
-#endif // QUICHE_QUIC_QUARTC_QUARTC_PACKET_WRITER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc
deleted file mode 100644
index 0a7fca933bf..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc
+++ /dev/null
@@ -1,470 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/quartc/quartc_session.h"
-
-#include <utility>
-
-#include "net/third_party/quiche/src/quic/core/quic_utils.h"
-#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h"
-#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
-
-namespace quic {
-namespace {
-
-// Arbitrary server port number for net::QuicCryptoClientConfig.
-const int kQuicServerPort = 0;
-
-} // namespace
-
-QuartcSession::QuartcSession(std::unique_ptr<QuicConnection> connection,
- Visitor* visitor,
- const QuicConfig& config,
- const ParsedQuicVersionVector& supported_versions,
- const QuicClock* clock)
- : QuicSession(connection.get(),
- visitor,
- config,
- supported_versions,
- /*num_expected_unidirectional_static_streams = */ 0),
- connection_(std::move(connection)),
- clock_(clock),
- per_packet_options_(std::make_unique<QuartcPerPacketOptions>()) {
- per_packet_options_->connection = connection_.get();
- connection_->set_per_packet_options(per_packet_options_.get());
-}
-
-QuartcSession::~QuartcSession() {}
-
-QuartcStream* QuartcSession::CreateOutgoingBidirectionalStream() {
- // Use default priority for incoming QUIC streams.
- // TODO(zhihuang): Determine if this value is correct.
- return ActivateDataStream(CreateDataStream(
- GetNextOutgoingBidirectionalStreamId(), QuicStream::kDefaultPriority));
-}
-
-bool QuartcSession::SendOrQueueMessage(QuicMemSliceSpan message,
- int64_t datagram_id) {
- if (!CanSendMessage()) {
- QUIC_LOG(ERROR) << "Quic session does not support SendMessage";
- return false;
- }
-
- if (message.total_length() > GetCurrentLargestMessagePayload()) {
- QUIC_LOG(ERROR) << "Message is too big, message_size="
- << message.total_length()
- << ", GetCurrentLargestMessagePayload="
- << GetCurrentLargestMessagePayload();
- return false;
- }
-
- // There may be other messages in send queue, so we have to add message
- // to the queue and call queue processing helper.
- QueuedMessage queued_message;
- queued_message.datagram_id = datagram_id;
- message.ConsumeAll([&queued_message](QuicMemSlice slice) {
- queued_message.message.Append(std::move(slice));
- });
- send_message_queue_.push_back(std::move(queued_message));
-
- ProcessSendMessageQueue();
-
- return true;
-}
-
-void QuartcSession::ProcessSendMessageQueue() {
- QuicConnection::ScopedPacketFlusher flusher(connection());
- while (!send_message_queue_.empty()) {
- QueuedMessage& it = send_message_queue_.front();
- QuicMemSliceSpan span = it.message.ToSpan();
- const size_t message_size = span.total_length();
- MessageResult result = SendMessage(span);
-
- // Handle errors.
- switch (result.status) {
- case MESSAGE_STATUS_SUCCESS: {
- QUIC_VLOG(1) << "Quartc message sent, message_id=" << result.message_id
- << ", message_size=" << message_size;
-
- auto element = message_to_datagram_id_.find(result.message_id);
-
- DCHECK(element == message_to_datagram_id_.end())
- << "Mapped message_id already exists, message_id="
- << result.message_id << ", datagram_id=" << element->second;
-
- message_to_datagram_id_[result.message_id] = it.datagram_id;
-
- // Notify that datagram was sent.
- session_delegate_->OnMessageSent(it.datagram_id);
- } break;
-
- // If connection is congestion controlled or not writable yet, stop
- // send loop and we'll retry again when we get OnCanWrite notification.
- case MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED:
- case MESSAGE_STATUS_BLOCKED:
- QUIC_VLOG(1) << "Quartc message not sent because connection is blocked"
- << ", message will be retried later, status="
- << result.status << ", message_size=" << message_size;
-
- return;
-
- // Other errors are unexpected. We do not propagate error to Quartc,
- // because writes can be delayed.
- case MESSAGE_STATUS_UNSUPPORTED:
- case MESSAGE_STATUS_TOO_LARGE:
- case MESSAGE_STATUS_INTERNAL_ERROR:
- QUIC_DLOG(DFATAL)
- << "Failed to send quartc message due to unexpected error"
- << ", message will not be retried, status=" << result.status
- << ", message_size=" << message_size;
- break;
- }
-
- send_message_queue_.pop_front();
- }
-}
-
-void QuartcSession::OnCanWrite() {
- // TODO(b/119640244): Since we currently use messages for audio and streams
- // for video, it makes sense to process queued messages first, then call quic
- // core OnCanWrite, which will resend queued streams. Long term we may need
- // better solution especially if quic connection is used for both data and
- // media.
-
- // Process quartc messages that were previously blocked.
- ProcessSendMessageQueue();
-
- QuicSession::OnCanWrite();
-}
-
-bool QuartcSession::SendProbingData() {
- if (QuicSession::SendProbingData()) {
- return true;
- }
-
- // Set transmission type to PROBING_RETRANSMISSION such that the packets will
- // be padded to full.
- SetTransmissionType(PROBING_RETRANSMISSION);
- // TODO(mellem): this sent PING will be retransmitted if it is lost which is
- // not ideal. Consider to send stream data as probing data instead.
- SendPing();
- return true;
-}
-
-void QuartcSession::SetDefaultEncryptionLevel(EncryptionLevel level) {
- QuicSession::SetDefaultEncryptionLevel(level);
- switch (level) {
- case ENCRYPTION_INITIAL:
- break;
- case ENCRYPTION_ZERO_RTT:
- if (connection()->perspective() == Perspective::IS_CLIENT) {
- DCHECK(IsEncryptionEstablished());
- DCHECK(session_delegate_);
- session_delegate_->OnConnectionWritable();
- }
- break;
- case ENCRYPTION_HANDSHAKE:
- break;
- case ENCRYPTION_FORWARD_SECURE:
- // On the server, handshake confirmed is the first time when you can start
- // writing packets.
- DCHECK(IsEncryptionEstablished());
- DCHECK(OneRttKeysAvailable());
-
- DCHECK(session_delegate_);
- session_delegate_->OnConnectionWritable();
- session_delegate_->OnCryptoHandshakeComplete();
- break;
- default:
- QUIC_BUG << "Unknown encryption level: "
- << EncryptionLevelToString(level);
- }
-}
-
-void QuartcSession::OnOneRttKeysAvailable() {
- QuicSession::OnOneRttKeysAvailable();
- // On the server, handshake confirmed is the first time when you can start
- // writing packets.
- DCHECK(IsEncryptionEstablished());
- DCHECK(OneRttKeysAvailable());
-
- DCHECK(session_delegate_);
- session_delegate_->OnConnectionWritable();
- session_delegate_->OnCryptoHandshakeComplete();
-}
-
-void QuartcSession::CancelStream(QuicStreamId stream_id) {
- ResetQuartcStream(stream_id, QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED);
-}
-
-void QuartcSession::ResetQuartcStream(QuicStreamId stream_id,
- QuicRstStreamErrorCode error) {
- if (!IsOpenStream(stream_id)) {
- return;
- }
- QuicStream* stream = QuicSession::GetOrCreateStream(stream_id);
- if (stream) {
- stream->Reset(error);
- }
-}
-
-void QuartcSession::OnCongestionWindowChange(QuicTime /*now*/) {
- DCHECK(session_delegate_);
- const RttStats* rtt_stats = connection_->sent_packet_manager().GetRttStats();
-
- QuicBandwidth bandwidth_estimate =
- connection_->sent_packet_manager().BandwidthEstimate();
-
- QuicByteCount in_flight =
- connection_->sent_packet_manager().GetBytesInFlight();
- QuicBandwidth pacing_rate =
- connection_->sent_packet_manager().GetSendAlgorithm()->PacingRate(
- in_flight);
-
- session_delegate_->OnCongestionControlChange(bandwidth_estimate, pacing_rate,
- rtt_stats->latest_rtt());
-}
-
-bool QuartcSession::ShouldKeepConnectionAlive() const {
- // TODO(mellem): Quartc may want different keepalive logic than HTTP.
- return GetNumActiveStreams() > 0;
-}
-
-void QuartcSession::OnConnectionClosed(const QuicConnectionCloseFrame& frame,
- ConnectionCloseSource source) {
- QuicSession::OnConnectionClosed(frame, source);
- DCHECK(session_delegate_);
- session_delegate_->OnConnectionClosed(frame, source);
-}
-
-void QuartcSession::CloseConnection(const std::string& details) {
- connection_->CloseConnection(
- QuicErrorCode::QUIC_CONNECTION_CANCELLED, details,
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
-}
-
-void QuartcSession::SetDelegate(Delegate* session_delegate) {
- if (session_delegate_) {
- QUIC_LOG(WARNING) << "The delegate for the session has already been set.";
- }
- session_delegate_ = session_delegate;
- DCHECK(session_delegate_);
-}
-
-void QuartcSession::OnTransportCanWrite() {
- connection()->writer()->SetWritable();
- if (HasDataToWrite()) {
- connection()->OnCanWrite();
- }
-}
-
-void QuartcSession::OnTransportReceived(const char* data, size_t data_len) {
- QuicReceivedPacket packet(data, data_len, clock_->Now());
- ProcessUdpPacket(connection()->self_address(), connection()->peer_address(),
- packet);
-}
-
-void QuartcSession::OnMessageReceived(quiche::QuicheStringPiece message) {
- session_delegate_->OnMessageReceived(message);
-}
-
-void QuartcSession::OnMessageAcked(QuicMessageId message_id,
- QuicTime receive_timestamp) {
- auto element = message_to_datagram_id_.find(message_id);
-
- if (element == message_to_datagram_id_.end()) {
- return;
- }
-
- session_delegate_->OnMessageAcked(/*datagram_id=*/element->second,
- receive_timestamp);
-
- // Free up space -- we should never see message_id again.
- message_to_datagram_id_.erase(element);
-}
-
-void QuartcSession::OnMessageLost(QuicMessageId message_id) {
- auto it = message_to_datagram_id_.find(message_id);
- if (it == message_to_datagram_id_.end()) {
- return;
- }
-
- session_delegate_->OnMessageLost(/*datagram_id=*/it->second);
-
- // Free up space.
- message_to_datagram_id_.erase(it);
-}
-
-QuicStream* QuartcSession::CreateIncomingStream(QuicStreamId id) {
- return ActivateDataStream(CreateDataStream(id, QuicStream::kDefaultPriority));
-}
-
-QuicStream* QuartcSession::CreateIncomingStream(PendingStream* /*pending*/) {
- QUIC_NOTREACHED();
- return nullptr;
-}
-
-std::unique_ptr<QuartcStream> QuartcSession::CreateDataStream(
- QuicStreamId id,
- spdy::SpdyPriority priority) {
- if (GetCryptoStream() == nullptr ||
- !GetCryptoStream()->encryption_established()) {
- // Encryption not active so no stream created
- return nullptr;
- }
- return InitializeDataStream(std::make_unique<QuartcStream>(id, this),
- priority);
-}
-
-std::unique_ptr<QuartcStream> QuartcSession::InitializeDataStream(
- std::unique_ptr<QuartcStream> stream,
- spdy::SpdyPriority priority) {
- // Register the stream to the QuicWriteBlockedList. |priority| is clamped
- // between 0 and 7, with 0 being the highest priority and 7 the lowest
- // priority.
- write_blocked_streams()->UpdateStreamPriority(
- stream->id(), spdy::SpdyStreamPrecedence(priority));
-
- if (IsIncomingStream(stream->id())) {
- DCHECK(session_delegate_);
- // Incoming streams need to be registered with the session_delegate_.
- session_delegate_->OnIncomingStream(stream.get());
- }
- return stream;
-}
-
-QuartcStream* QuartcSession::ActivateDataStream(
- std::unique_ptr<QuartcStream> stream) {
- // Transfer ownership of the data stream to the session via ActivateStream().
- QuartcStream* raw = stream.release();
- if (raw) {
- // Make QuicSession take ownership of the stream.
- ActivateStream(std::unique_ptr<QuicStream>(raw));
- }
- return raw;
-}
-
-QuartcClientSession::QuartcClientSession(
- std::unique_ptr<QuicConnection> connection,
- const QuicConfig& config,
- const ParsedQuicVersionVector& supported_versions,
- const QuicClock* clock,
- std::unique_ptr<QuartcPacketWriter> packet_writer,
- std::unique_ptr<QuicCryptoClientConfig> client_crypto_config,
- quiche::QuicheStringPiece server_crypto_config)
- : QuartcSession(std::move(connection),
- /*visitor=*/nullptr,
- config,
- supported_versions,
- clock),
- packet_writer_(std::move(packet_writer)),
- client_crypto_config_(std::move(client_crypto_config)),
- server_config_(server_crypto_config) {
- DCHECK_EQ(QuartcSession::connection()->perspective(), Perspective::IS_CLIENT);
-}
-
-QuartcClientSession::~QuartcClientSession() {
- // The client session is the packet transport delegate, so it must be unset
- // before the session is deleted.
- packet_writer_->SetPacketTransportDelegate(nullptr);
-}
-
-void QuartcClientSession::Initialize() {
- DCHECK(crypto_stream_) << "Do not call QuartcSession::Initialize(), call "
- "StartCryptoHandshake() instead.";
- QuartcSession::Initialize();
-
- // QUIC is ready to process incoming packets after Initialize().
- // Set the packet transport delegate to begin receiving packets.
- packet_writer_->SetPacketTransportDelegate(this);
-}
-
-const QuicCryptoStream* QuartcClientSession::GetCryptoStream() const {
- return crypto_stream_.get();
-}
-
-QuicCryptoStream* QuartcClientSession::GetMutableCryptoStream() {
- return crypto_stream_.get();
-}
-
-void QuartcClientSession::StartCryptoHandshake() {
- QuicServerId server_id(/*host=*/"", kQuicServerPort,
- /*privacy_mode_enabled=*/false);
-
- if (!server_config_.empty()) {
- QuicCryptoServerConfig::ConfigOptions options;
-
- std::string error;
- QuicWallTime now = clock()->WallNow();
- QuicCryptoClientConfig::CachedState::ServerConfigState result =
- client_crypto_config_->LookupOrCreate(server_id)->SetServerConfig(
- server_config_, now,
- /*expiry_time=*/now.Add(QuicTime::Delta::Infinite()), &error);
-
- if (result == QuicCryptoClientConfig::CachedState::SERVER_CONFIG_VALID) {
- DCHECK_EQ(error, "");
- client_crypto_config_->LookupOrCreate(server_id)->SetProof(
- std::vector<std::string>{kDummyCertName}, /*cert_sct=*/"",
- /*chlo_hash=*/"", /*signature=*/"anything");
- } else {
- QUIC_LOG(DFATAL) << "Unable to set server config, error=" << error;
- }
- }
-
- crypto_stream_ = std::make_unique<QuicCryptoClientStream>(
- server_id, this,
- client_crypto_config_->proof_verifier()->CreateDefaultContext(),
- client_crypto_config_.get(), this, /*has_application_state = */ true);
- Initialize();
- crypto_stream_->CryptoConnect();
-}
-
-void QuartcClientSession::OnProofValid(
- const QuicCryptoClientConfig::CachedState& /*cached*/) {
- // TODO(zhihuang): Handle the proof verification.
-}
-
-void QuartcClientSession::OnProofVerifyDetailsAvailable(
- const ProofVerifyDetails& /*verify_details*/) {
- // TODO(zhihuang): Handle the proof verification.
-}
-
-QuartcServerSession::QuartcServerSession(
- std::unique_ptr<QuicConnection> connection,
- Visitor* visitor,
- const QuicConfig& config,
- const ParsedQuicVersionVector& supported_versions,
- const QuicClock* clock,
- const QuicCryptoServerConfig* server_crypto_config,
- QuicCompressedCertsCache* const compressed_certs_cache,
- QuicCryptoServerStreamBase::Helper* const stream_helper)
- : QuartcSession(std::move(connection),
- visitor,
- config,
- supported_versions,
- clock),
- server_crypto_config_(server_crypto_config),
- compressed_certs_cache_(compressed_certs_cache),
- stream_helper_(stream_helper) {
- DCHECK_EQ(QuartcSession::connection()->perspective(), Perspective::IS_SERVER);
-}
-
-const QuicCryptoStream* QuartcServerSession::GetCryptoStream() const {
- return crypto_stream_.get();
-}
-
-QuicCryptoStream* QuartcServerSession::GetMutableCryptoStream() {
- return crypto_stream_.get();
-}
-
-void QuartcServerSession::StartCryptoHandshake() {
- crypto_stream_ = CreateCryptoServerStream(
- server_crypto_config_, compressed_certs_cache_, this, stream_helper_);
- Initialize();
-}
-
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.h
deleted file mode 100644
index 66ddfc3617f..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.h
+++ /dev/null
@@ -1,339 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_QUARTC_QUARTC_SESSION_H_
-#define QUICHE_QUIC_QUARTC_QUARTC_SESSION_H_
-
-#include <memory>
-#include <string>
-
-#include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h"
-#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h"
-#include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h"
-#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
-#include "net/third_party/quiche/src/quic/core/quic_session.h"
-#include "net/third_party/quiche/src/quic/core/quic_types.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_stream.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
-
-namespace quic {
-
-// QuartcSession owns and manages a QUIC connection.
-class QuartcSession : public QuicSession,
- public QuartcPacketTransport::Delegate {
- public:
- QuartcSession(std::unique_ptr<QuicConnection> connection,
- Visitor* visitor,
- const QuicConfig& config,
- const ParsedQuicVersionVector& supported_versions,
- const QuicClock* clock);
- QuartcSession(const QuartcSession&) = delete;
- QuartcSession& operator=(const QuartcSession&) = delete;
- ~QuartcSession() override;
-
- // QuicSession overrides.
- QuartcStream* CreateOutgoingBidirectionalStream();
-
- // Sends short unreliable message using quic message frame (message must fit
- // in one quic packet). If connection is blocked by congestion control,
- // message will be queued and resent later after receiving an OnCanWrite
- // notification.
- //
- // Message size must be <= GetLargestMessagePayload().
- //
- // Supported in quic version 45 or later.
- //
- // Returns false and logs error if message is too long or session does not
- // support SendMessage API. Other unexpected errors during send will not be
- // returned, because messages can be sent later if connection is congestion
- // controlled.
- //
- // |datagram_id| is used to notify when message was sent in
- // Delegate::OnMessageSent.
- //
- // TODO(sukhanov): We can not use QUIC message ID for notifications, because
- // QUIC does not take ownership of messages and if connection is congestion
- // controlled, message is not sent and does not get message id until it is
- // sent successfully. It also creates problem of flow control between
- // messages and streams if they are used together. We discussed it with QUIC
- // team and there are multiple solutions, but for now we have to use our
- // own datagram identification.
- bool SendOrQueueMessage(QuicMemSliceSpan message, int64_t datagram_id);
-
- // Returns largest message payload acceptable in SendQuartcMessage.
- QuicPacketLength GetCurrentLargestMessagePayload() const {
- return connection()->GetCurrentLargestMessagePayload();
- }
-
- // Return true if transport support message frame.
- bool CanSendMessage() const {
- return VersionSupportsMessageFrames(transport_version());
- }
-
- void SetDefaultEncryptionLevel(EncryptionLevel level) override;
- void OnOneRttKeysAvailable() override;
-
- // QuicConnectionVisitorInterface overrides.
- void OnCongestionWindowChange(QuicTime now) override;
- bool ShouldKeepConnectionAlive() const override;
-
- void OnCanWrite() override;
- bool SendProbingData() override;
-
- void OnConnectionClosed(const QuicConnectionCloseFrame& frame,
- ConnectionCloseSource source) override;
-
- // QuartcSession methods.
- virtual void StartCryptoHandshake() = 0;
-
- // Closes the connection with the given human-readable error details.
- // The connection closes with the QUIC_CONNECTION_CANCELLED error code to
- // indicate the application closed it.
- //
- // Informs the peer that the connection has been closed. This prevents the
- // peer from waiting until the connection times out.
- //
- // Cleans up the underlying QuicConnection's state. Closing the connection
- // makes it safe to delete the QuartcSession.
- void CloseConnection(const std::string& details);
-
- // If the given stream is still open, sends a reset frame to cancel it.
- // Note: This method cancels a stream by QuicStreamId rather than by pointer
- // (or by a method on QuartcStream) because QuartcSession (and not
- // the caller) owns the streams. Streams may finish and be deleted before the
- // caller tries to cancel them, rendering the caller's pointers invalid.
- void CancelStream(QuicStreamId stream_id);
-
- // Callbacks called by the QuartcSession to notify the user of the
- // QuartcSession of certain events.
- class Delegate {
- public:
- virtual ~Delegate() {}
-
- // Called when the crypto handshake is complete. Crypto handshake on the
- // client is only completed _after_ SHLO is received, but we can actually
- // start sending media data right after CHLO is sent.
- virtual void OnCryptoHandshakeComplete() = 0;
-
- // Connection can be writable even before crypto handshake is complete.
- // In particular, on the client, we can start sending data after sending
- // full CHLO, without waiting for SHLO. This reduces a send delay by 1-rtt.
- //
- // This may be called multiple times.
- virtual void OnConnectionWritable() = 0;
-
- // Called when a new stream is received from the remote endpoint.
- virtual void OnIncomingStream(QuartcStream* stream) = 0;
-
- // Called when network parameters change in response to an ack frame.
- virtual void OnCongestionControlChange(QuicBandwidth bandwidth_estimate,
- QuicBandwidth pacing_rate,
- QuicTime::Delta latest_rtt) = 0;
-
- // Called when the connection is closed. This means all of the streams will
- // be closed and no new streams can be created.
- virtual void OnConnectionClosed(const QuicConnectionCloseFrame& frame,
- ConnectionCloseSource source) = 0;
-
- // Called when message (sent as SendMessage) is received.
- virtual void OnMessageReceived(quiche::QuicheStringPiece message) = 0;
-
- // Called when message is sent to QUIC.
- //
- // Takes into account delay due to congestion control, but does not take
- // into account any additional socket delays.
- //
- // Passed |datagram_id| is the same used in SendOrQueueMessage.
- //
- // TODO(sukhanov): We can take into account socket delay, but it's not clear
- // if it's worth doing if we eventually plan to move congestion control to
- // QUIC in QRTP model. If we need to do it, mellem@ thinks it's fairly
- // strtaightforward: QUIC does not know about socket delay, but ICE does. We
- // can tell ICE the QUIC packet number for each packet sent, and it will
- // echo it back to us when the packet actually goes out. We just need to
- // plumb that signal up to RTP's congestion control.
- virtual void OnMessageSent(int64_t datagram_id) = 0;
-
- // Called when message with |datagram_id| gets acked. |receive_timestamp|
- // indicates when the peer received this message, according to its own
- // clock.
- virtual void OnMessageAcked(int64_t datagram_id,
- QuicTime receive_timestamp) = 0;
-
- // Called when message with |datagram_id| is lost.
- virtual void OnMessageLost(int64_t datagram_id) = 0;
-
- // TODO(zhihuang): Add proof verification.
- };
-
- // The |delegate| is not owned by QuartcSession.
- void SetDelegate(Delegate* session_delegate);
-
- // Called when CanWrite() changes from false to true.
- void OnTransportCanWrite() override;
-
- // Called when a packet has been received and should be handled by the
- // QuicConnection.
- void OnTransportReceived(const char* data, size_t data_len) override;
-
- void OnMessageReceived(quiche::QuicheStringPiece message) override;
-
- // Called when message with |message_id| gets acked.
- void OnMessageAcked(QuicMessageId message_id,
- QuicTime receive_timestamp) override;
-
- void OnMessageLost(QuicMessageId message_id) override;
-
- // Returns number of queued (not sent) messages submitted by
- // SendOrQueueMessage. Messages are queued if connection is congestion
- // controlled.
- size_t send_message_queue_size() const { return send_message_queue_.size(); }
-
- protected:
- // QuicSession override.
- QuicStream* CreateIncomingStream(QuicStreamId id) override;
- QuicStream* CreateIncomingStream(PendingStream* pending) override;
-
- std::unique_ptr<QuartcStream> CreateDataStream(QuicStreamId id,
- spdy::SpdyPriority priority);
- // Activates a QuartcStream. The session takes ownership of the stream, but
- // returns an unowned pointer to the stream for convenience.
- QuartcStream* ActivateDataStream(std::unique_ptr<QuartcStream> stream);
-
- void ResetQuartcStream(QuicStreamId stream_id, QuicRstStreamErrorCode error);
-
- const QuicClock* clock() { return clock_; }
-
- private:
- std::unique_ptr<QuartcStream> InitializeDataStream(
- std::unique_ptr<QuartcStream> stream,
- spdy::SpdyPriority priority);
-
- // Holds message until it's sent.
- struct QueuedMessage {
- QueuedMessage() : message(nullptr, 0, nullptr, 0), datagram_id(0) {}
-
- QuicMemSliceStorage message;
- int64_t datagram_id;
- };
-
- void ProcessSendMessageQueue();
-
- // Take ownership of the QuicConnection. Note: if |connection_| changes,
- // the new value of |connection_| must be given to |packet_writer_| before any
- // packets are written. Otherwise, |packet_writer_| will crash.
- std::unique_ptr<QuicConnection> connection_;
-
- // For recording packet receipt time
- const QuicClock* clock_;
-
- // Not owned by QuartcSession.
- Delegate* session_delegate_ = nullptr;
-
- // Options passed to the packet writer for each packet.
- std::unique_ptr<QuartcPerPacketOptions> per_packet_options_;
-
- // Queue of pending messages sent by SendQuartcMessage that were not sent
- // yet or blocked by congestion control. Messages are queued in the order
- // of sent by SendOrQueueMessage().
- QuicCircularDeque<QueuedMessage> send_message_queue_;
-
- // Maps message ids to datagram ids, so we could translate message ACKs
- // received from QUIC to datagram ACKs that are propagated up the stack.
- QuicHashMap<QuicMessageId, int64_t> message_to_datagram_id_;
-};
-
-class QuartcClientSession : public QuartcSession,
- public QuicCryptoClientStream::ProofHandler {
- public:
- QuartcClientSession(
- std::unique_ptr<QuicConnection> connection,
- const QuicConfig& config,
- const ParsedQuicVersionVector& supported_versions,
- const QuicClock* clock,
- std::unique_ptr<QuartcPacketWriter> packet_writer,
- std::unique_ptr<QuicCryptoClientConfig> client_crypto_config,
- quiche::QuicheStringPiece server_crypto_config);
- QuartcClientSession(const QuartcClientSession&) = delete;
- QuartcClientSession& operator=(const QuartcClientSession&) = delete;
-
- ~QuartcClientSession() override;
-
- // Initialize should not be called on a QuartcSession. Instead, call
- // StartCryptoHandshake().
- // TODO(mellem): Move creation of the crypto stream into Initialize() and
- // remove StartCryptoHandshake() to bring QuartcSession in line with other
- // implementations of QuicSession, which can be started by calling
- // Initialize().
- void Initialize() override;
-
- // Accessors for the client crypto stream.
- QuicCryptoStream* GetMutableCryptoStream() override;
- const QuicCryptoStream* GetCryptoStream() const override;
-
- // Initializes the session and sends a handshake.
- void StartCryptoHandshake() override;
-
- // ProofHandler overrides.
- void OnProofValid(const QuicCryptoClientConfig::CachedState& cached) override;
-
- // Called by the client crypto handshake when proof verification details
- // become available, either because proof verification is complete, or when
- // cached details are used.
- void OnProofVerifyDetailsAvailable(
- const ProofVerifyDetails& verify_details) override;
-
- private:
- // Packet writer used by |connection_|.
- std::unique_ptr<QuartcPacketWriter> packet_writer_;
-
- // Config for QUIC crypto stream.
- std::unique_ptr<QuicCryptoClientConfig> client_crypto_config_;
-
- // Client perspective crypto stream.
- std::unique_ptr<QuicCryptoClientStream> crypto_stream_;
-
- const std::string server_config_;
-};
-
-class QuartcServerSession : public QuartcSession {
- public:
- QuartcServerSession(std::unique_ptr<QuicConnection> connection,
- Visitor* visitor,
- const QuicConfig& config,
- const ParsedQuicVersionVector& supported_versions,
- const QuicClock* clock,
- const QuicCryptoServerConfig* server_crypto_config,
- QuicCompressedCertsCache* const compressed_certs_cache,
- QuicCryptoServerStreamBase::Helper* const stream_helper);
- QuartcServerSession(const QuartcServerSession&) = delete;
- QuartcServerSession& operator=(const QuartcServerSession&) = delete;
-
- // Accessors for the server crypto stream.
- QuicCryptoStream* GetMutableCryptoStream() override;
- const QuicCryptoStream* GetCryptoStream() const override;
-
- // Initializes the session and prepares to receive a handshake.
- void StartCryptoHandshake() override;
-
- private:
- // Config for QUIC crypto stream.
- const QuicCryptoServerConfig* server_crypto_config_;
-
- // Used by QUIC crypto server stream to track most recently compressed certs.
- QuicCompressedCertsCache* const compressed_certs_cache_;
-
- // This helper is needed to create QuicCryptoServerStream.
- QuicCryptoServerStreamBase::Helper* const stream_helper_;
-
- // Server perspective crypto stream.
- std::unique_ptr<QuicCryptoServerStreamBase> crypto_stream_;
-};
-
-} // namespace quic
-
-#endif // QUICHE_QUIC_QUARTC_QUARTC_SESSION_H_
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session_test.cc
deleted file mode 100644
index 93172e7c55d..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session_test.cc
+++ /dev/null
@@ -1,680 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/quartc/quartc_session.h"
-
-#include <utility>
-
-#include "net/third_party/quiche/src/quic/core/quic_clock.h"
-#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
-#include "net/third_party/quiche/src/quic/core/quic_types.h"
-#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h"
-#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_string_utils.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_test_mem_slice_vector.h"
-#include "net/third_party/quiche/src/quic/quartc/counting_packet_filter.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_fakes.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h"
-#include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h"
-#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
-#include "net/third_party/quiche/src/quic/test_tools/simulator/packet_filter.h"
-#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
-
-namespace quic {
-
-namespace {
-
-using ::testing::ElementsAre;
-using ::testing::ElementsAreArray;
-using ::testing::Gt;
-using ::testing::Pair;
-
-constexpr QuicTime::Delta kPropagationDelay =
- QuicTime::Delta::FromMilliseconds(10);
-// Propagation delay and a bit, but no more than full RTT.
-constexpr QuicTime::Delta kPropagationDelayAndABit =
- QuicTime::Delta::FromMilliseconds(12);
-
-static QuicByteCount kDefaultMaxPacketSize = 1200;
-
-test::QuicTestMemSliceVector CreateMemSliceVector(
- quiche::QuicheStringPiece data) {
- return test::QuicTestMemSliceVector(
- {std::pair<char*, size_t>(const_cast<char*>(data.data()), data.size())});
-}
-
-class QuartcSessionTest : public QuicTest {
- public:
- ~QuartcSessionTest() override {}
-
- void Init(bool create_client_endpoint = true) {
- // TODO(b/150224094): Re-enable TLS handshake.
- // TODO(b/150236522): Parametrize by QUIC version.
- quic::test::DisableQuicVersionsWithTls();
-
- client_transport_ =
- std::make_unique<simulator::SimulatedQuartcPacketTransport>(
- &simulator_, "client_transport", "server_transport",
- 10 * kDefaultMaxPacketSize);
- server_transport_ =
- std::make_unique<simulator::SimulatedQuartcPacketTransport>(
- &simulator_, "server_transport", "client_transport",
- 10 * kDefaultMaxPacketSize);
-
- client_filter_ = std::make_unique<simulator::CountingPacketFilter>(
- &simulator_, "client_filter", client_transport_.get());
-
- client_server_link_ = std::make_unique<simulator::SymmetricLink>(
- client_filter_.get(), server_transport_.get(),
- QuicBandwidth::FromKBitsPerSecond(10 * 1000), kPropagationDelay);
-
- client_stream_delegate_ = std::make_unique<FakeQuartcStreamDelegate>();
- client_session_delegate_ = std::make_unique<FakeQuartcEndpointDelegate>(
- client_stream_delegate_.get(), simulator_.GetClock());
-
- server_stream_delegate_ = std::make_unique<FakeQuartcStreamDelegate>();
- server_session_delegate_ = std::make_unique<FakeQuartcEndpointDelegate>(
- server_stream_delegate_.get(), simulator_.GetClock());
-
- // No 0-rtt setup, because server config is empty.
- // CannotCreateDataStreamBeforeHandshake depends on 1-rtt setup.
- if (create_client_endpoint) {
- client_endpoint_ = std::make_unique<QuartcClientEndpoint>(
- simulator_.GetAlarmFactory(), simulator_.GetClock(),
- simulator_.GetRandomGenerator(), client_session_delegate_.get(),
- quic::QuartcSessionConfig(),
- /*serialized_server_config=*/"");
- }
- server_endpoint_ = std::make_unique<QuartcServerEndpoint>(
- simulator_.GetAlarmFactory(), simulator_.GetClock(),
- simulator_.GetRandomGenerator(), server_session_delegate_.get(),
- quic::QuartcSessionConfig());
- }
-
- // Note that input session config will apply to both server and client.
- // Perspective and packet_transport will be overwritten.
- void CreateClientAndServerSessions(
- const QuartcSessionConfig& /*session_config*/,
- bool init = true) {
- if (init) {
- Init();
- }
-
- server_endpoint_->Connect(server_transport_.get());
- client_endpoint_->Connect(client_transport_.get());
-
- CHECK(simulator_.RunUntil([this] {
- return client_session_delegate_->session() != nullptr &&
- server_session_delegate_->session() != nullptr;
- }));
-
- client_peer_ = client_session_delegate_->session();
- server_peer_ = server_session_delegate_->session();
- }
-
- // Runs all tasks scheduled in the next 200 ms.
- void RunTasks() { simulator_.RunFor(QuicTime::Delta::FromMilliseconds(200)); }
-
- void AwaitHandshake() {
- simulator_.RunUntil([this] {
- return client_peer_->OneRttKeysAvailable() &&
- server_peer_->OneRttKeysAvailable();
- });
- }
-
- // Test handshake establishment and sending/receiving of data for two
- // directions.
- void TestSendReceiveStreams() {
- ASSERT_TRUE(server_peer_->OneRttKeysAvailable());
- ASSERT_TRUE(client_peer_->OneRttKeysAvailable());
- ASSERT_TRUE(server_peer_->IsEncryptionEstablished());
- ASSERT_TRUE(client_peer_->IsEncryptionEstablished());
-
- // Now we can establish encrypted outgoing stream.
- QuartcStream* outgoing_stream =
- server_peer_->CreateOutgoingBidirectionalStream();
- QuicStreamId stream_id = outgoing_stream->id();
- ASSERT_NE(nullptr, outgoing_stream);
- EXPECT_TRUE(server_peer_->ShouldKeepConnectionAlive());
-
- outgoing_stream->SetDelegate(server_stream_delegate_.get());
-
- // Send a test message from peer 1 to peer 2.
- test::QuicTestMemSliceVector data = CreateMemSliceVector("Hello");
- outgoing_stream->WriteMemSlices(data.span(), /*fin=*/false);
- RunTasks();
-
- // Wait for peer 2 to receive messages.
- ASSERT_TRUE(client_stream_delegate_->has_data());
-
- QuartcStream* incoming = client_session_delegate_->last_incoming_stream();
- ASSERT_TRUE(incoming);
- EXPECT_EQ(incoming->id(), stream_id);
- EXPECT_TRUE(client_peer_->ShouldKeepConnectionAlive());
-
- EXPECT_EQ(client_stream_delegate_->data()[stream_id], "Hello");
- // Send a test message from peer 2 to peer 1.
- test::QuicTestMemSliceVector response = CreateMemSliceVector("Response");
- incoming->WriteMemSlices(response.span(), /*fin=*/false);
- RunTasks();
- // Wait for peer 1 to receive messages.
- ASSERT_TRUE(server_stream_delegate_->has_data());
-
- EXPECT_EQ(server_stream_delegate_->data()[stream_id], "Response");
- }
-
- // Test sending/receiving of messages for two directions.
- void TestSendReceiveMessage() {
- ASSERT_TRUE(server_peer_->CanSendMessage());
- ASSERT_TRUE(client_peer_->CanSendMessage());
-
- // Disable probing retransmissions such that the first message from either
- // side can be sent without being queued.
- client_peer_->connection()->set_fill_up_link_during_probing(false);
- server_peer_->connection()->set_fill_up_link_during_probing(false);
-
- int64_t server_datagram_id = 111;
- int64_t client_datagram_id = 222;
-
- // Send message from peer 1 to peer 2.
- test::QuicTestMemSliceVector message =
- CreateMemSliceVector("Message from server");
- ASSERT_TRUE(
- server_peer_->SendOrQueueMessage(message.span(), server_datagram_id));
-
- // First message in each direction should not be queued.
- EXPECT_EQ(server_peer_->send_message_queue_size(), 0u);
-
- // Wait for peer 2 to receive message.
- RunTasks();
-
- EXPECT_THAT(client_session_delegate_->incoming_messages(),
- testing::ElementsAre("Message from server"));
-
- EXPECT_THAT(server_session_delegate_->sent_datagram_ids(),
- testing::ElementsAre(server_datagram_id));
-
- EXPECT_THAT(
- server_session_delegate_->acked_datagram_id_to_receive_timestamp(),
- ElementsAre(Pair(server_datagram_id, Gt(QuicTime::Zero()))));
-
- // Send message from peer 2 to peer 1.
- message = CreateMemSliceVector("Message from client");
- ASSERT_TRUE(
- client_peer_->SendOrQueueMessage(message.span(), client_datagram_id));
-
- // First message in each direction should not be queued.
- EXPECT_EQ(client_peer_->send_message_queue_size(), 0u);
-
- // Wait for peer 1 to receive message.
- RunTasks();
-
- EXPECT_THAT(server_session_delegate_->incoming_messages(),
- testing::ElementsAre("Message from client"));
-
- EXPECT_THAT(client_session_delegate_->sent_datagram_ids(),
- testing::ElementsAre(client_datagram_id));
-
- EXPECT_THAT(
- client_session_delegate_->acked_datagram_id_to_receive_timestamp(),
- ElementsAre(Pair(client_datagram_id, Gt(QuicTime::Zero()))));
- }
-
- // Test for sending multiple messages that also result in queueing.
- // This is one-way test, which is run in given direction.
- void TestSendReceiveQueuedMessages(bool direction_from_server) {
- // Send until queue_size number of messages are queued.
- constexpr size_t queue_size = 10;
-
- ASSERT_TRUE(server_peer_->CanSendMessage());
- ASSERT_TRUE(client_peer_->CanSendMessage());
-
- QuartcSession* const peer_sending =
- direction_from_server ? server_peer_ : client_peer_;
-
- FakeQuartcEndpointDelegate* const delegate_receiving =
- direction_from_server ? client_session_delegate_.get()
- : server_session_delegate_.get();
-
- FakeQuartcEndpointDelegate* const delegate_sending =
- direction_from_server ? server_session_delegate_.get()
- : client_session_delegate_.get();
-
- // There should be no messages in the queue before we start sending.
- EXPECT_EQ(peer_sending->send_message_queue_size(), 0u);
-
- // Send messages from peer 1 to peer 2 until required number of messages
- // are queued in unsent message queue.
- std::vector<std::string> sent_messages;
- std::vector<int64_t> sent_datagram_ids;
- int64_t current_datagram_id = 0;
- while (peer_sending->send_message_queue_size() < queue_size) {
- sent_messages.push_back(quiche::QuicheStrCat("Sending message, index=",
- sent_messages.size()));
- ASSERT_TRUE(peer_sending->SendOrQueueMessage(
- CreateMemSliceVector(sent_messages.back()).span(),
- current_datagram_id));
-
- sent_datagram_ids.push_back(current_datagram_id);
- ++current_datagram_id;
- }
-
- // Wait for peer 2 to receive all messages.
- RunTasks();
-
- std::vector<testing::Matcher<std::pair<int64_t, QuicTime>>> ack_matchers;
- for (int64_t id : sent_datagram_ids) {
- ack_matchers.push_back(Pair(id, Gt(QuicTime::Zero())));
- }
- EXPECT_EQ(delegate_receiving->incoming_messages(), sent_messages);
- EXPECT_EQ(delegate_sending->sent_datagram_ids(), sent_datagram_ids);
- EXPECT_THAT(delegate_sending->acked_datagram_id_to_receive_timestamp(),
- ElementsAreArray(ack_matchers));
- }
-
- // Test sending long messages:
- // - message of maximum allowed length should succeed
- // - message of > maximum allowed length should fail.
- void TestSendLongMessage() {
- ASSERT_TRUE(server_peer_->CanSendMessage());
- ASSERT_TRUE(client_peer_->CanSendMessage());
-
- // Send message of maximum allowed length.
- std::string message_max_long =
- std::string(server_peer_->GetCurrentLargestMessagePayload(), 'A');
- test::QuicTestMemSliceVector message =
- CreateMemSliceVector(message_max_long);
- ASSERT_TRUE(
- server_peer_->SendOrQueueMessage(message.span(), /*datagram_id=*/0));
-
- // Send long message which should fail.
- std::string message_too_long =
- std::string(server_peer_->GetCurrentLargestMessagePayload() + 1, 'B');
- message = CreateMemSliceVector(message_too_long);
- ASSERT_FALSE(
- server_peer_->SendOrQueueMessage(message.span(), /*datagram_id=*/0));
-
- // Wait for peer 2 to receive message.
- RunTasks();
-
- // Client should only receive one message of allowed length.
- EXPECT_THAT(client_session_delegate_->incoming_messages(),
- testing::ElementsAre(message_max_long));
- }
-
- // Test that client and server are not connected after handshake failure.
- void TestDisconnectAfterFailedHandshake() {
- EXPECT_TRUE(!client_session_delegate_->connected());
- EXPECT_TRUE(!server_session_delegate_->connected());
-
- EXPECT_FALSE(client_peer_->IsEncryptionEstablished());
- EXPECT_FALSE(client_peer_->OneRttKeysAvailable());
-
- EXPECT_FALSE(server_peer_->IsEncryptionEstablished());
- EXPECT_FALSE(server_peer_->OneRttKeysAvailable());
- }
-
- protected:
- simulator::Simulator simulator_;
-
- std::unique_ptr<simulator::SimulatedQuartcPacketTransport> client_transport_;
- std::unique_ptr<simulator::SimulatedQuartcPacketTransport> server_transport_;
- std::unique_ptr<simulator::CountingPacketFilter> client_filter_;
- std::unique_ptr<simulator::SymmetricLink> client_server_link_;
-
- std::unique_ptr<FakeQuartcStreamDelegate> client_stream_delegate_;
- std::unique_ptr<FakeQuartcEndpointDelegate> client_session_delegate_;
- std::unique_ptr<FakeQuartcStreamDelegate> server_stream_delegate_;
- std::unique_ptr<FakeQuartcEndpointDelegate> server_session_delegate_;
-
- std::unique_ptr<QuartcClientEndpoint> client_endpoint_;
- std::unique_ptr<QuartcServerEndpoint> server_endpoint_;
-
- QuartcSession* client_peer_ = nullptr;
- QuartcSession* server_peer_ = nullptr;
-};
-
-TEST_F(QuartcSessionTest, SendReceiveStreams) {
- CreateClientAndServerSessions(QuartcSessionConfig());
- AwaitHandshake();
- TestSendReceiveStreams();
-}
-
-TEST_F(QuartcSessionTest, SendReceiveMessages) {
- CreateClientAndServerSessions(QuartcSessionConfig());
- AwaitHandshake();
- TestSendReceiveMessage();
-}
-
-TEST_F(QuartcSessionTest, SendReceiveQueuedMessages) {
- CreateClientAndServerSessions(QuartcSessionConfig());
- AwaitHandshake();
- TestSendReceiveQueuedMessages(/*direction_from_server=*/true);
- TestSendReceiveQueuedMessages(/*direction_from_server=*/false);
-}
-
-TEST_F(QuartcSessionTest, SendMultiMemSliceMessage) {
- CreateClientAndServerSessions(QuartcSessionConfig());
- AwaitHandshake();
- ASSERT_TRUE(server_peer_->CanSendMessage());
-
- std::vector<std::pair<char*, size_t>> buffers;
- char first_piece[] = "Hello, ";
- char second_piece[] = "world!";
- buffers.emplace_back(first_piece, 7);
- buffers.emplace_back(second_piece, 6);
- test::QuicTestMemSliceVector message(buffers);
- ASSERT_TRUE(
- server_peer_->SendOrQueueMessage(message.span(), /*datagram_id=*/1));
-
- // Wait for the client to receive the message.
- RunTasks();
-
- // The message is not fragmented along MemSlice boundaries.
- EXPECT_THAT(client_session_delegate_->incoming_messages(),
- testing::ElementsAre("Hello, world!"));
-}
-
-TEST_F(QuartcSessionTest, SendMessageFails) {
- CreateClientAndServerSessions(QuartcSessionConfig());
- AwaitHandshake();
- TestSendLongMessage();
-}
-
-TEST_F(QuartcSessionTest, TestCryptoHandshakeCanWriteTriggers) {
- CreateClientAndServerSessions(QuartcSessionConfig());
-
- AwaitHandshake();
-
- RunTasks();
-
- ASSERT_TRUE(client_session_delegate_->writable_time().IsInitialized());
- ASSERT_TRUE(
- client_session_delegate_->crypto_handshake_time().IsInitialized());
- // On client, we are writable 1-rtt before crypto handshake is complete.
- ASSERT_LT(client_session_delegate_->writable_time(),
- client_session_delegate_->crypto_handshake_time());
-
- ASSERT_TRUE(server_session_delegate_->writable_time().IsInitialized());
- ASSERT_TRUE(
- server_session_delegate_->crypto_handshake_time().IsInitialized());
- // On server, the writable time and crypto handshake are the same. (when SHLO
- // is sent).
- ASSERT_EQ(server_session_delegate_->writable_time(),
- server_session_delegate_->crypto_handshake_time());
-}
-
-TEST_F(QuartcSessionTest, PreSharedKeyHandshake) {
- QuartcSessionConfig config;
- config.pre_shared_key = "foo";
- CreateClientAndServerSessions(config);
- AwaitHandshake();
- TestSendReceiveStreams();
- TestSendReceiveMessage();
-}
-
-// Test that data streams are not created before handshake.
-TEST_F(QuartcSessionTest, CannotCreateDataStreamBeforeHandshake) {
- CreateClientAndServerSessions(QuartcSessionConfig());
- EXPECT_EQ(nullptr, server_peer_->CreateOutgoingBidirectionalStream());
- EXPECT_EQ(nullptr, client_peer_->CreateOutgoingBidirectionalStream());
-}
-
-TEST_F(QuartcSessionTest, CancelQuartcStream) {
- CreateClientAndServerSessions(QuartcSessionConfig());
- AwaitHandshake();
- ASSERT_TRUE(client_peer_->OneRttKeysAvailable());
- ASSERT_TRUE(server_peer_->OneRttKeysAvailable());
-
- QuartcStream* stream = client_peer_->CreateOutgoingBidirectionalStream();
- ASSERT_NE(nullptr, stream);
-
- uint32_t id = stream->id();
- EXPECT_FALSE(client_peer_->IsClosedStream(id));
- stream->SetDelegate(client_stream_delegate_.get());
- client_peer_->CancelStream(id);
- EXPECT_EQ(stream->stream_error(),
- QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED);
- EXPECT_TRUE(client_peer_->IsClosedStream(id));
-}
-
-// TODO(b/112561077): This is the wrong layer for this test. We should write a
-// test specifically for QuartcPacketWriter with a stubbed-out
-// QuartcPacketTransport and remove
-// SimulatedQuartcPacketTransport::last_packet_number().
-TEST_F(QuartcSessionTest, WriterGivesPacketNumberToTransport) {
- CreateClientAndServerSessions(QuartcSessionConfig());
- AwaitHandshake();
- ASSERT_TRUE(client_peer_->OneRttKeysAvailable());
- ASSERT_TRUE(server_peer_->OneRttKeysAvailable());
-
- QuartcStream* stream = client_peer_->CreateOutgoingBidirectionalStream();
- stream->SetDelegate(client_stream_delegate_.get());
-
- test::QuicTestMemSliceVector stream_data = CreateMemSliceVector("Hello");
- stream->WriteMemSlices(stream_data.span(), /*fin=*/false);
- RunTasks();
-
- // The transport should see the latest packet number sent by QUIC.
- EXPECT_EQ(
- client_transport_->last_packet_number(),
- client_peer_->connection()->sent_packet_manager().GetLargestSentPacket());
-}
-
-TEST_F(QuartcSessionTest, CloseConnection) {
- CreateClientAndServerSessions(QuartcSessionConfig());
- AwaitHandshake();
- ASSERT_TRUE(client_peer_->OneRttKeysAvailable());
- ASSERT_TRUE(server_peer_->OneRttKeysAvailable());
-
- client_peer_->CloseConnection("Connection closed by client");
- EXPECT_FALSE(client_session_delegate_->connected());
- RunTasks();
- EXPECT_FALSE(server_session_delegate_->connected());
-}
-
-TEST_F(QuartcSessionTest, StreamRetransmissionEnabled) {
- CreateClientAndServerSessions(QuartcSessionConfig());
- AwaitHandshake();
- ASSERT_TRUE(client_peer_->OneRttKeysAvailable());
- ASSERT_TRUE(server_peer_->OneRttKeysAvailable());
-
- QuartcStream* stream = client_peer_->CreateOutgoingBidirectionalStream();
- QuicStreamId stream_id = stream->id();
- stream->SetDelegate(client_stream_delegate_.get());
- stream->set_cancel_on_loss(false);
-
- client_filter_->set_packets_to_drop(1);
-
- test::QuicTestMemSliceVector stream_data = CreateMemSliceVector("Hello");
- stream->WriteMemSlices(stream_data.span(), /*fin=*/false);
- RunTasks();
-
- // Stream data should make it despite packet loss.
- ASSERT_TRUE(server_stream_delegate_->has_data());
- EXPECT_EQ(server_stream_delegate_->data()[stream_id], "Hello");
-}
-
-TEST_F(QuartcSessionTest, StreamRetransmissionDisabled) {
- // Disable tail loss probe, otherwise test maybe flaky because dropped
- // message will be retransmitted to detect tail loss.
- QuartcSessionConfig session_config;
- session_config.enable_tail_loss_probe = false;
- CreateClientAndServerSessions(session_config);
-
- // Disable probing retransmissions, otherwise test maybe flaky because dropped
- // message will be retransmitted to to probe for more bandwidth.
- client_peer_->connection()->set_fill_up_link_during_probing(false);
-
- AwaitHandshake();
- ASSERT_TRUE(client_peer_->OneRttKeysAvailable());
- ASSERT_TRUE(server_peer_->OneRttKeysAvailable());
-
- // The client sends an ACK for the crypto handshake next. This must be
- // flushed before we set the filter to drop the next packet, in order to
- // ensure that the filter drops a data-bearing packet instead of just an ack.
- RunTasks();
-
- QuartcStream* stream = client_peer_->CreateOutgoingBidirectionalStream();
- QuicStreamId stream_id = stream->id();
- stream->SetDelegate(client_stream_delegate_.get());
- stream->set_cancel_on_loss(true);
-
- client_filter_->set_packets_to_drop(1);
-
- test::QuicTestMemSliceVector stream_data = CreateMemSliceVector("Hello");
- stream->WriteMemSlices(stream_data.span(), /*fin=*/false);
- simulator_.RunFor(QuicTime::Delta::FromMilliseconds(1));
-
- // Send another packet to trigger loss detection.
- QuartcStream* stream_1 = client_peer_->CreateOutgoingBidirectionalStream();
- stream_1->SetDelegate(client_stream_delegate_.get());
-
- test::QuicTestMemSliceVector stream_data_1 =
- CreateMemSliceVector("Second message");
- stream_1->WriteMemSlices(stream_data_1.span(), /*fin=*/false);
- RunTasks();
-
- // QUIC should try to retransmit the first stream by loss detection. Instead,
- // it will cancel itself.
- EXPECT_THAT(server_stream_delegate_->data()[stream_id], testing::IsEmpty());
-
- EXPECT_TRUE(client_peer_->IsClosedStream(stream_id));
- EXPECT_TRUE(server_peer_->IsClosedStream(stream_id));
- EXPECT_THAT(client_stream_delegate_->stream_error(stream_id),
- test::IsStreamError(QUIC_STREAM_CANCELLED));
- EXPECT_THAT(server_stream_delegate_->stream_error(stream_id),
- test::IsStreamError(QUIC_STREAM_CANCELLED));
-}
-
-TEST_F(QuartcSessionTest, LostDatagramNotifications) {
- // Disable tail loss probe, otherwise test maybe flaky because dropped
- // message will be retransmitted to detect tail loss.
- QuartcSessionConfig session_config;
- session_config.enable_tail_loss_probe = false;
- CreateClientAndServerSessions(session_config);
-
- // Disable probing retransmissions, otherwise test maybe flaky because dropped
- // message will be retransmitted to to probe for more bandwidth.
- client_peer_->connection()->set_fill_up_link_during_probing(false);
- server_peer_->connection()->set_fill_up_link_during_probing(false);
-
- AwaitHandshake();
- ASSERT_TRUE(client_peer_->OneRttKeysAvailable());
- ASSERT_TRUE(server_peer_->OneRttKeysAvailable());
-
- // The client sends an ACK for the crypto handshake next. This must be
- // flushed before we set the filter to drop the next packet, in order to
- // ensure that the filter drops a data-bearing packet instead of just an ack.
- RunTasks();
-
- // Drop the next packet.
- client_filter_->set_packets_to_drop(1);
-
- test::QuicTestMemSliceVector message =
- CreateMemSliceVector("This message will be lost");
- ASSERT_TRUE(client_peer_->SendOrQueueMessage(message.span(), 1));
-
- RunTasks();
-
- // Send another packet to elicit an ack and trigger loss detection.
- message = CreateMemSliceVector("This message will arrive");
- ASSERT_TRUE(client_peer_->SendOrQueueMessage(message.span(), 2));
-
- RunTasks();
-
- EXPECT_THAT(server_session_delegate_->incoming_messages(),
- ElementsAre("This message will arrive"));
- EXPECT_THAT(client_session_delegate_->sent_datagram_ids(), ElementsAre(1, 2));
- EXPECT_THAT(
- client_session_delegate_->acked_datagram_id_to_receive_timestamp(),
- ElementsAre(Pair(2, Gt(QuicTime::Zero()))));
- EXPECT_THAT(client_session_delegate_->lost_datagram_ids(), ElementsAre(1));
-}
-
-TEST_F(QuartcSessionTest, ServerRegistersAsWriteBlocked) {
- // Initialize client and server session, but with the server write-blocked.
- Init();
- server_transport_->SetWritable(false);
- CreateClientAndServerSessions(QuartcSessionConfig(), /*init=*/false);
-
- // Let the client send a few copies of the CHLO. The server can't respond, as
- // it's still write-blocked.
- RunTasks();
-
- // Making the server's transport writable should trigger a callback that
- // reaches the server session, allowing it to write packets.
- server_transport_->SetWritable(true);
-
- // Now the server should respond with the SHLO, encryption should be
- // established, and data should flow normally.
- // Note that if the server is *not* correctly registered as write-blocked,
- // it will crash here (see b/124527328 for details).
- AwaitHandshake();
- TestSendReceiveStreams();
-}
-
-TEST_F(QuartcSessionTest, PreSharedKeyHandshakeIs0RTT) {
- QuartcSessionConfig session_config;
- session_config.pre_shared_key = "foo";
-
- // Client endpoint is created below. Destructing client endpoint
- // causes issues with the simulator.
- Init(/*create_client_endpoint=*/false);
-
- server_endpoint_->Connect(server_transport_.get());
-
- client_endpoint_ = std::make_unique<QuartcClientEndpoint>(
- simulator_.GetAlarmFactory(), simulator_.GetClock(),
- simulator_.GetRandomGenerator(), client_session_delegate_.get(),
- QuartcSessionConfig(),
- // This is the key line here. It passes through the server config
- // from the server to the client.
- server_endpoint_->server_crypto_config());
-
- client_endpoint_->Connect(client_transport_.get());
-
- // Running for 1ms. This is shorter than the RTT, so the
- // client session should be created, but server won't be created yet.
- simulator_.RunFor(QuicTime::Delta::FromMilliseconds(1));
-
- client_peer_ = client_session_delegate_->session();
- server_peer_ = server_session_delegate_->session();
-
- ASSERT_NE(client_peer_, nullptr);
- ASSERT_EQ(server_peer_, nullptr);
-
- // Write data to the client before running tasks. This should be sent by the
- // client and received by the server if the handshake is 0RTT.
- // If this test fails, add 'RunTasks()' above, and see what error is sent
- // by the server in the rejection message.
- QuartcStream* stream = client_peer_->CreateOutgoingBidirectionalStream();
- ASSERT_NE(stream, nullptr);
- QuicStreamId stream_id = stream->id();
- stream->SetDelegate(client_stream_delegate_.get());
-
- char message[] = "Hello in 0RTTs!";
- test::QuicTestMemSliceVector data({std::make_pair(message, strlen(message))});
- stream->WriteMemSlices(data.span(), /*fin=*/false);
-
- // This will now run the rest of the connection. But the
- // Server peer will receive the CHLO and message after 1 delay.
- simulator_.RunFor(kPropagationDelayAndABit);
-
- // If we can decrypt the data, it means that 0 rtt was successful.
- // This is because we waited only a propagation delay. So if the decryption
- // failed, we would send sREJ instead of SHLO, but it wouldn't be delivered to
- // the client yet.
- ASSERT_TRUE(server_stream_delegate_->has_data());
- EXPECT_EQ(server_stream_delegate_->data()[stream_id], message);
-}
-
-} // namespace
-
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc
deleted file mode 100644
index 01494c5ddf5..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc
+++ /dev/null
@@ -1,170 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/quartc/quartc_stream.h"
-
-#include <memory>
-#include <utility>
-
-#include "net/third_party/quiche/src/quic/core/quic_ack_listener_interface.h"
-#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
-#include "net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h"
-#include "net/third_party/quiche/src/quic/core/quic_stream_sequencer.h"
-#include "net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h"
-#include "net/third_party/quiche/src/quic/core/quic_types.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
-
-namespace quic {
-
-QuartcStream::QuartcStream(QuicStreamId id, QuicSession* session)
- : QuicStream(id, session, /*is_static=*/false, BIDIRECTIONAL) {
- sequencer()->set_level_triggered(true);
-}
-
-QuartcStream::~QuartcStream() {}
-
-void QuartcStream::OnDataAvailable() {
- size_t bytes_consumed = 0;
- do {
- bool fin = sequencer()->ReadableBytes() + sequencer()->NumBytesConsumed() ==
- sequencer()->close_offset();
-
- // Upper bound on number of readable regions. Each complete block's worth
- // of data crosses at most one region boundary. The remainder may cross one
- // more boundary. Number of regions is one more than the number of region
- // boundaries crossed.
- size_t iov_length = sequencer()->ReadableBytes() /
- QuicStreamSequencerBuffer::kBlockSizeBytes +
- 2;
- std::unique_ptr<iovec[]> iovecs = std::make_unique<iovec[]>(iov_length);
- iov_length = sequencer()->GetReadableRegions(iovecs.get(), iov_length);
-
- bytes_consumed = delegate_->OnReceived(this, iovecs.get(), iov_length, fin);
- sequencer()->MarkConsumed(bytes_consumed);
- if (sequencer()->IsClosed()) {
- OnFinRead();
- break;
- }
- } while (bytes_consumed > 0);
-}
-
-void QuartcStream::OnClose() {
- QuicStream::OnClose();
- DCHECK(delegate_);
- delegate_->OnClose(this);
-}
-
-void QuartcStream::OnStreamDataConsumed(QuicByteCount bytes_consumed) {
- QuicStream::OnStreamDataConsumed(bytes_consumed);
-
- if (delegate_) {
- delegate_->OnBufferChanged(this);
- }
-}
-
-void QuartcStream::OnDataBuffered(
- QuicStreamOffset /*offset*/,
- QuicByteCount /*data_length*/,
- const QuicReferenceCountedPointer<
- QuicAckListenerInterface>& /*ack_listener*/) {
- if (delegate_) {
- delegate_->OnBufferChanged(this);
- }
-}
-
-bool QuartcStream::OnStreamFrameAcked(QuicStreamOffset offset,
- QuicByteCount data_length,
- bool fin_acked,
- QuicTime::Delta ack_delay_time,
- QuicTime receive_timestamp,
- QuicByteCount* newly_acked_length) {
- // Previous losses of acked data are no longer relevant to the retransmission
- // count. Once data is acked, it will never be retransmitted.
- lost_frame_counter_.RemoveInterval(
- QuicInterval<QuicStreamOffset>(offset, offset + data_length));
-
- return QuicStream::OnStreamFrameAcked(offset, data_length, fin_acked,
- ack_delay_time, receive_timestamp,
- newly_acked_length);
-}
-
-void QuartcStream::OnStreamFrameRetransmitted(QuicStreamOffset offset,
- QuicByteCount data_length,
- bool fin_retransmitted) {
- QuicStream::OnStreamFrameRetransmitted(offset, data_length,
- fin_retransmitted);
-
- DCHECK(delegate_);
- delegate_->OnBufferChanged(this);
-}
-
-void QuartcStream::OnStreamFrameLost(QuicStreamOffset offset,
- QuicByteCount data_length,
- bool fin_lost) {
- QuicStream::OnStreamFrameLost(offset, data_length, fin_lost);
-
- lost_frame_counter_.AddInterval(
- QuicInterval<QuicStreamOffset>(offset, offset + data_length));
-
- DCHECK(delegate_);
- delegate_->OnBufferChanged(this);
-}
-
-void QuartcStream::OnCanWrite() {
- if (lost_frame_counter_.MaxCount() >
- static_cast<size_t>(max_retransmission_count_) &&
- HasPendingRetransmission()) {
- Reset(QUIC_STREAM_CANCELLED);
- return;
- }
- QuicStream::OnCanWrite();
-}
-
-bool QuartcStream::cancel_on_loss() {
- return max_retransmission_count_ == 0;
-}
-
-void QuartcStream::set_cancel_on_loss(bool cancel_on_loss) {
- if (cancel_on_loss) {
- max_retransmission_count_ = 0;
- } else {
- max_retransmission_count_ = std::numeric_limits<int>::max();
- }
-}
-
-int QuartcStream::max_retransmission_count() const {
- return max_retransmission_count_;
-}
-
-void QuartcStream::set_max_retransmission_count(int max_retransmission_count) {
- max_retransmission_count_ = max_retransmission_count;
-}
-
-QuicByteCount QuartcStream::BytesPendingRetransmission() {
- if (lost_frame_counter_.MaxCount() >
- static_cast<size_t>(max_retransmission_count_)) {
- return 0; // Lost bytes will never be retransmitted.
- }
- QuicByteCount bytes = 0;
- for (const auto& interval : send_buffer().pending_retransmissions()) {
- bytes += interval.Length();
- }
- return bytes;
-}
-
-QuicStreamOffset QuartcStream::ReadOffset() {
- return sequencer()->NumBytesConsumed();
-}
-
-void QuartcStream::FinishWriting() {
- WriteOrBufferData(quiche::QuicheStringPiece(nullptr, 0), true, nullptr);
-}
-
-void QuartcStream::SetDelegate(Delegate* delegate) {
- delegate_ = delegate;
- DCHECK(delegate_);
-}
-
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.h
deleted file mode 100644
index 7f3c28d005c..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.h
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_QUARTC_QUARTC_STREAM_H_
-#define QUICHE_QUIC_QUARTC_QUARTC_STREAM_H_
-
-#include <stddef.h>
-#include <limits>
-
-#include "net/third_party/quiche/src/quic/core/quic_ack_listener_interface.h"
-#include "net/third_party/quiche/src/quic/core/quic_session.h"
-#include "net/third_party/quiche/src/quic/core/quic_stream.h"
-#include "net/third_party/quiche/src/quic/core/quic_types.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h"
-#include "net/quic/platform/impl/quic_export_impl.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_interval_counter.h"
-
-namespace quic {
-
-// Sends and receives data with a particular QUIC stream ID, reliably and
-// in-order. To send/receive data out of order, use separate streams. To
-// send/receive unreliably, close a stream after reliability is no longer
-// needed.
-class QuartcStream : public QuicStream {
- public:
- QuartcStream(QuicStreamId id, QuicSession* session);
-
- ~QuartcStream() override;
-
- // QuicStream overrides.
- void OnDataAvailable() override;
-
- void OnClose() override;
-
- void OnStreamDataConsumed(QuicByteCount bytes_consumed) override;
-
- void OnDataBuffered(
- QuicStreamOffset offset,
- QuicByteCount data_length,
- const QuicReferenceCountedPointer<QuicAckListenerInterface>& ack_listener)
- override;
-
- bool OnStreamFrameAcked(QuicStreamOffset offset,
- QuicByteCount data_length,
- bool fin_acked,
- QuicTime::Delta ack_delay_time,
- QuicTime receive_timestamp,
- QuicByteCount* newly_acked_length) override;
-
- void OnStreamFrameRetransmitted(QuicStreamOffset offset,
- QuicByteCount data_length,
- bool fin_retransmitted) override;
-
- void OnStreamFrameLost(QuicStreamOffset offset,
- QuicByteCount data_length,
- bool fin_lost) override;
-
- void OnCanWrite() override;
-
- // QuartcStream interface methods.
-
- // Whether the stream should be cancelled instead of retransmitted on loss.
- // If set to true, the stream will reset itself instead of retransmitting lost
- // stream frames. Defaults to false. Setting it to true is equivalent to
- // setting |max_retransmission_count| to zero.
- bool cancel_on_loss();
- void set_cancel_on_loss(bool cancel_on_loss);
-
- // Maximum number of times this stream's data may be retransmitted. Each byte
- // of stream data may be retransmitted this many times. If any byte (or range
- // of bytes) is lost and would be retransmitted more than this number of
- // times, the stream resets itself instead of retransmitting the data again.
- // Setting this value to zero disables retransmissions.
- //
- // Note that this limit applies only to stream data, not to the FIN bit. If
- // only the FIN bit needs to be retransmitted, there is no benefit to
- // cancelling the stream and sending a reset frame instead.
- int max_retransmission_count() const;
- void set_max_retransmission_count(int max_retransmission_count);
-
- QuicByteCount BytesPendingRetransmission();
-
- // Returns the current read offset for this stream. During a call to
- // Delegate::OnReceived, this value is the offset of the first byte read.
- QuicStreamOffset ReadOffset();
-
- // Marks this stream as finished writing. Asynchronously sends a FIN and
- // closes the write-side. It is not necessary to call FinishWriting() if the
- // last call to Write() sends a FIN.
- void FinishWriting();
-
- // Implemented by the user of the QuartcStream to receive incoming
- // data and be notified of state changes.
- class Delegate {
- public:
- virtual ~Delegate() {}
-
- // Called when the stream receives data. |iov| is a pointer to the first of
- // |iov_length| readable regions. |iov| points to readable data within
- // |stream|'s sequencer buffer. QUIC may modify or delete this data after
- // the application consumes it. |fin| indicates the end of stream data.
- // Returns the number of bytes consumed. May return 0 if the delegate is
- // unable to consume any bytes at this time.
- virtual size_t OnReceived(QuartcStream* stream,
- iovec* iov,
- size_t iov_length,
- bool fin) = 0;
-
- // Called when the stream is closed, either locally or by the remote
- // endpoint. Streams close when (a) fin bits are both sent and received,
- // (b) Close() is called, or (c) the stream is reset.
- // TODO(zhihuang) Creates a map from the integer error_code to WebRTC native
- // error code.
- virtual void OnClose(QuartcStream* stream) = 0;
-
- // Called when the contents of the stream's buffer changes.
- virtual void OnBufferChanged(QuartcStream* stream) = 0;
- };
-
- // The |delegate| is not owned by QuartcStream.
- void SetDelegate(Delegate* delegate);
-
- private:
- Delegate* delegate_ = nullptr;
-
- // Maximum number of times this stream's data may be retransmitted.
- int max_retransmission_count_ = std::numeric_limits<int>::max();
-
- // Counter which tracks the number of times each frame has been lost
- // (accounting for the possibility of overlapping frames).
- //
- // If the maximum count of any lost frame exceeds |max_retransmission_count_|,
- // the stream will cancel itself on the next attempt to retransmit data (the
- // next call to |OnCanWrite|).
- QuartcIntervalCounter<QuicStreamOffset> lost_frame_counter_;
-};
-
-} // namespace quic
-
-#endif // QUICHE_QUIC_QUARTC_QUARTC_STREAM_H_
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc
deleted file mode 100644
index b387e7f9723..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc
+++ /dev/null
@@ -1,656 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/quartc/quartc_stream.h"
-
-#include <memory>
-#include <string>
-#include <type_traits>
-#include <utility>
-
-#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
-#include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h"
-#include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h"
-#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h"
-#include "net/third_party/quiche/src/quic/core/quic_clock.h"
-#include "net/third_party/quiche/src/quic/core/quic_config.h"
-#include "net/third_party/quiche/src/quic/core/quic_connection.h"
-#include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h"
-#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
-#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
-#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h"
-#include "net/third_party/quiche/src/quic/core/quic_session.h"
-#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
-#include "net/third_party/quiche/src/quic/core/quic_time.h"
-#include "net/third_party/quiche/src/quic/core/quic_types.h"
-#include "net/third_party/quiche/src/quic/core/quic_utils.h"
-#include "net/third_party/quiche/src/quic/core/quic_versions.h"
-#include "net/third_party/quiche/src/quic/core/quic_write_blocked_list.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_test_mem_slice_vector.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_factory.h"
-#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
-
-using ::quic::test::IsQuicStreamNoError;
-using ::quic::test::IsStreamError;
-
-namespace quic {
-
-namespace {
-
-static const QuicStreamId kStreamId = 5;
-
-// MockQuicSession that does not create streams and writes data from
-// QuicStream to a string.
-class MockQuicSession : public QuicSession {
- public:
- MockQuicSession(QuicConnection* connection,
- const QuicConfig& config,
- std::string* write_buffer)
- : QuicSession(connection,
- nullptr /*visitor*/,
- config,
- CurrentSupportedVersions(),
- /*num_expected_unidirectional_static_streams = */ 0),
- write_buffer_(write_buffer) {}
-
- ~MockQuicSession() override {}
-
- // Writes outgoing data from QuicStream to a string.
- QuicConsumedData WritevData(
- QuicStreamId id,
- size_t write_length,
- QuicStreamOffset offset,
- StreamSendingState state,
- TransmissionType /*type*/,
- quiche::QuicheOptional<EncryptionLevel> /*level*/) override {
- if (!writable_) {
- return QuicConsumedData(0, false);
- }
-
- // WritevData does not pass down a iovec, data is saved in stream before
- // data is consumed. Retrieve data from stream.
- char* buf = new char[write_length];
- QuicDataWriter writer(write_length, buf, quiche::NETWORK_BYTE_ORDER);
- QuicStream* stream = GetOrCreateStream(id);
- DCHECK(stream);
- if (write_length > 0) {
- stream->WriteStreamData(offset, write_length, &writer);
- }
- write_buffer_->append(buf, write_length);
- delete[] buf;
- return QuicConsumedData(write_length, state != StreamSendingState::NO_FIN);
- }
-
- QuartcStream* CreateIncomingStream(QuicStreamId /*id*/) override {
- return nullptr;
- }
-
- QuartcStream* CreateIncomingStream(PendingStream* /*pending*/) override {
- return nullptr;
- }
-
- const QuicCryptoStream* GetCryptoStream() const override { return nullptr; }
- QuicCryptoStream* GetMutableCryptoStream() override { return nullptr; }
- bool ShouldKeepConnectionAlive() const override {
- return GetNumActiveStreams() > 0;
- }
-
- // Called by QuicStream when they want to close stream.
- void SendRstStream(QuicStreamId /*id*/,
- QuicRstStreamErrorCode /*error*/,
- QuicStreamOffset /*bytes_written*/) override {}
-
- // Sets whether data is written to buffer, or else if this is write blocked.
- void set_writable(bool writable) { writable_ = writable; }
-
- // Tracks whether the stream is write blocked and its priority.
- void RegisterReliableStream(QuicStreamId stream_id,
- spdy::SpdyPriority priority) {
- write_blocked_streams()->RegisterStream(
- stream_id,
- /*is_static_stream=*/false, spdy::SpdyStreamPrecedence(priority));
- }
-
- // The session take ownership of the stream.
- void ActivateReliableStream(std::unique_ptr<QuicStream> stream) {
- ActivateStream(std::move(stream));
- }
-
- private:
- // Stores written data from ReliableQuicStreamAdapter.
- std::string* write_buffer_;
- // Whether data is written to write_buffer_.
- bool writable_ = true;
-};
-
-// Packet writer that does nothing. This is required for QuicConnection but
-// isn't used for writing data.
-class DummyPacketWriter : public QuicPacketWriter {
- public:
- DummyPacketWriter() {}
-
- // QuicPacketWriter overrides.
- WriteResult WritePacket(const char* /*buffer*/,
- size_t /*buf_len*/,
- const QuicIpAddress& /*self_address*/,
- const QuicSocketAddress& /*peer_address*/,
- PerPacketOptions* /*options*/) override {
- return WriteResult(WRITE_STATUS_ERROR, 0);
- }
-
- bool IsWriteBlocked() const override { return false; }
-
- void SetWritable() override {}
-
- QuicByteCount GetMaxPacketSize(
- const QuicSocketAddress& /*peer_address*/) const override {
- return 0;
- }
-
- bool SupportsReleaseTime() const override { return false; }
-
- bool IsBatchMode() const override { return false; }
-
- char* GetNextWriteLocation(
- const QuicIpAddress& /*self_address*/,
- const QuicSocketAddress& /*peer_address*/) override {
- return nullptr;
- }
-
- WriteResult Flush() override { return WriteResult(WRITE_STATUS_OK, 0); }
-};
-
-class MockQuartcStreamDelegate : public QuartcStream::Delegate {
- public:
- MockQuartcStreamDelegate(QuicStreamId id, std::string* read_buffer)
- : id_(id), read_buffer_(read_buffer) {}
-
- void OnBufferChanged(QuartcStream* stream) override {
- last_bytes_buffered_ = stream->BufferedDataBytes();
- last_bytes_pending_retransmission_ = stream->BytesPendingRetransmission();
- }
-
- size_t OnReceived(QuartcStream* stream,
- iovec* iov,
- size_t iov_length,
- bool /*fin*/) override {
- EXPECT_EQ(id_, stream->id());
- EXPECT_EQ(stream->ReadOffset(), read_buffer_->size());
- size_t bytes_consumed = 0;
- for (size_t i = 0; i < iov_length; ++i) {
- read_buffer_->append(static_cast<const char*>(iov[i].iov_base),
- iov[i].iov_len);
- bytes_consumed += iov[i].iov_len;
- }
- return bytes_consumed;
- }
-
- void OnClose(QuartcStream* /*stream*/) override { closed_ = true; }
-
- bool closed() { return closed_; }
-
- QuicByteCount last_bytes_buffered() { return last_bytes_buffered_; }
- QuicByteCount last_bytes_pending_retransmission() {
- return last_bytes_pending_retransmission_;
- }
-
- protected:
- QuicStreamId id_;
- // Data read by the QuicStream.
- std::string* read_buffer_;
- // Whether the QuicStream is closed.
- bool closed_ = false;
-
- // Last amount of data observed as buffered.
- QuicByteCount last_bytes_buffered_ = 0;
- QuicByteCount last_bytes_pending_retransmission_ = 0;
-};
-
-class QuartcStreamTest : public QuicTestWithParam<ParsedQuicVersion>,
- public QuicConnectionHelperInterface {
- public:
- QuartcStreamTest() : version_(GetParam()) {}
-
- ~QuartcStreamTest() override = default;
-
- void CreateReliableQuicStream() {
- // Arbitrary values for QuicConnection.
- Perspective perspective = Perspective::IS_SERVER;
- QuicIpAddress ip;
- ip.FromString("0.0.0.0");
- bool owns_writer = true;
-
- alarm_factory_ = std::make_unique<test::MockAlarmFactory>();
-
- connection_ = std::make_unique<QuicConnection>(
- QuicUtils::CreateZeroConnectionId(version_.transport_version),
- QuicSocketAddress(ip, 0), this /*QuicConnectionHelperInterface*/,
- alarm_factory_.get(), new DummyPacketWriter(), owns_writer, perspective,
- ParsedQuicVersionVector{version_});
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- session_ = std::make_unique<MockQuicSession>(connection_.get(),
- QuicConfig(), &write_buffer_);
- mock_stream_delegate_ =
- std::make_unique<MockQuartcStreamDelegate>(kStreamId, &read_buffer_);
- stream_ = new QuartcStream(kStreamId, session_.get());
- stream_->SetDelegate(mock_stream_delegate_.get());
- session_->ActivateReliableStream(std::unique_ptr<QuartcStream>(stream_));
- }
-
- const QuicClock* GetClock() const override { return &clock_; }
-
- QuicRandom* GetRandomGenerator() override {
- return QuicRandom::GetInstance();
- }
-
- QuicBufferAllocator* GetStreamSendBufferAllocator() override {
- return &buffer_allocator_;
- }
-
- protected:
- const ParsedQuicVersion version_;
- // The QuicSession will take the ownership.
- QuartcStream* stream_;
- std::unique_ptr<MockQuartcStreamDelegate> mock_stream_delegate_;
- std::unique_ptr<MockQuicSession> session_;
- // Data written by the ReliableQuicStreamAdapterTest.
- std::string write_buffer_;
- // Data read by the ReliableQuicStreamAdapterTest.
- std::string read_buffer_;
- std::unique_ptr<QuicAlarmFactory> alarm_factory_;
- std::unique_ptr<QuicConnection> connection_;
- // Used to implement the QuicConnectionHelperInterface.
- SimpleBufferAllocator buffer_allocator_;
- MockClock clock_;
-};
-
-// TODO(b/150224094): Enable versions with TLS handshake.
-INSTANTIATE_TEST_SUITE_P(
- Tests,
- QuartcStreamTest,
- ::testing::ValuesIn(CurrentSupportedVersionsWithQuicCrypto()),
- ::testing::PrintToStringParamName());
-
-// Write an entire string.
-TEST_P(QuartcStreamTest, WriteDataWhole) {
- CreateReliableQuicStream();
- char message[] = "Foo bar";
- test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
- stream_->WriteMemSlices(data.span(), /*fin=*/false);
- EXPECT_EQ("Foo bar", write_buffer_);
-}
-
-// Write part of a string.
-TEST_P(QuartcStreamTest, WriteDataPartial) {
- CreateReliableQuicStream();
- char message[] = "Foo bar";
- test::QuicTestMemSliceVector data({std::make_pair(message, 5)});
- stream_->WriteMemSlices(data.span(), /*fin=*/false);
- EXPECT_EQ("Foo b", write_buffer_);
-}
-
-// Test that a QuartcStream buffers writes correctly.
-TEST_P(QuartcStreamTest, StreamBuffersData) {
- CreateReliableQuicStream();
-
- char message[] = "Foo bar";
- test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
-
- // The stream is not yet writable, so data will be buffered.
- session_->set_writable(false);
- stream_->WriteMemSlices(data.span(), /*fin=*/false);
-
- // Check that data is buffered.
- EXPECT_TRUE(stream_->HasBufferedData());
- EXPECT_EQ(7u, stream_->BufferedDataBytes());
-
- // Check that the stream told its delegate about the buffer change.
- EXPECT_EQ(7u, mock_stream_delegate_->last_bytes_buffered());
-
- // Check that none of the data was written yet.
- // Note that |write_buffer_| actually holds data written by the QuicSession
- // (not data buffered by the stream).
- EXPECT_EQ(0ul, write_buffer_.size());
-
- char message1[] = "xyzzy";
- test::QuicTestMemSliceVector data1({std::make_pair(message1, 5)});
-
- // More writes go into the buffer.
- stream_->WriteMemSlices(data1.span(), /*fin=*/false);
-
- EXPECT_TRUE(stream_->HasBufferedData());
- EXPECT_EQ(12u, stream_->BufferedDataBytes());
- EXPECT_EQ(12u, mock_stream_delegate_->last_bytes_buffered());
- EXPECT_EQ(0ul, write_buffer_.size());
-
- // The stream becomes writable, so it sends the buffered data.
- session_->set_writable(true);
- stream_->OnCanWrite();
-
- EXPECT_FALSE(stream_->HasBufferedData());
- EXPECT_EQ(0u, stream_->BufferedDataBytes());
- EXPECT_EQ(0u, mock_stream_delegate_->last_bytes_buffered());
- EXPECT_EQ("Foo barxyzzy", write_buffer_);
-}
-
-// Finish writing to a stream.
-// It delivers the fin bit and closes the write-side as soon as possible.
-TEST_P(QuartcStreamTest, FinishWriting) {
- CreateReliableQuicStream();
-
- session_->set_writable(false);
- stream_->FinishWriting();
- EXPECT_FALSE(stream_->fin_sent());
-
- // Fin is sent as soon as the stream becomes writable.
- session_->set_writable(true);
- stream_->OnCanWrite();
- EXPECT_TRUE(stream_->fin_sent());
- EXPECT_TRUE(stream_->write_side_closed());
-}
-
-// Read an entire string.
-TEST_P(QuartcStreamTest, ReadDataWhole) {
- CreateReliableQuicStream();
- QuicStreamFrame frame(kStreamId, false, 0, "Hello, World!");
- stream_->OnStreamFrame(frame);
-
- EXPECT_EQ("Hello, World!", read_buffer_);
-}
-
-// Read part of a string.
-TEST_P(QuartcStreamTest, ReadDataPartial) {
- CreateReliableQuicStream();
- QuicStreamFrame frame(kStreamId, false, 0, "Hello, World!");
- frame.data_length = 5;
- stream_->OnStreamFrame(frame);
-
- EXPECT_EQ("Hello", read_buffer_);
-}
-
-// Streams do not call OnReceived() after StopReading().
-// Note: this is tested here because Quartc relies on this behavior.
-TEST_P(QuartcStreamTest, StopReading) {
- CreateReliableQuicStream();
- stream_->StopReading();
-
- QuicStreamFrame frame(kStreamId, false, 0, "Hello, World!");
- stream_->OnStreamFrame(frame);
-
- EXPECT_EQ(0ul, read_buffer_.size());
-
- QuicStreamFrame frame2(kStreamId, true, 0, "Hello, World!");
- stream_->OnStreamFrame(frame2);
-
- EXPECT_EQ(0ul, read_buffer_.size());
- EXPECT_TRUE(stream_->fin_received());
-}
-
-// Test that closing the stream results in a callback.
-TEST_P(QuartcStreamTest, CloseStream) {
- CreateReliableQuicStream();
- EXPECT_FALSE(mock_stream_delegate_->closed());
- if (GetQuicReloadableFlag(quic_break_session_stream_close_loop)) {
- stream_->CloseWriteSide();
- stream_->CloseReadSide();
- } else {
- stream_->OnClose();
- }
- EXPECT_TRUE(mock_stream_delegate_->closed());
-}
-
-// Both sending and receiving fin automatically closes a stream.
-TEST_P(QuartcStreamTest, CloseOnFins) {
- CreateReliableQuicStream();
- QuicStreamFrame frame(kStreamId, true, 0, 0);
- stream_->OnStreamFrame(frame);
-
- test::QuicTestMemSliceVector data({});
- stream_->WriteMemSlices(data.span(), /*fin=*/true);
-
- // Check that the OnClose() callback occurred.
- EXPECT_TRUE(mock_stream_delegate_->closed());
-}
-
-TEST_P(QuartcStreamTest, TestCancelOnLossDisabled) {
- CreateReliableQuicStream();
-
- // This should be the default state.
- EXPECT_FALSE(stream_->cancel_on_loss());
-
- char message[] = "Foo bar";
- test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
- stream_->WriteMemSlices(data.span(), /*fin=*/false);
-
- EXPECT_EQ("Foo bar", write_buffer_);
-
- stream_->OnStreamFrameLost(0, 7, false);
- stream_->OnCanWrite();
-
- EXPECT_EQ("Foo barFoo bar", write_buffer_);
- EXPECT_THAT(stream_->stream_error(), IsQuicStreamNoError());
-}
-
-TEST_P(QuartcStreamTest, TestCancelOnLossEnabled) {
- CreateReliableQuicStream();
- stream_->set_cancel_on_loss(true);
-
- char message[] = "Foo bar";
- test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
- stream_->WriteMemSlices(data.span(), /*fin=*/false);
-
- EXPECT_EQ("Foo bar", write_buffer_);
-
- stream_->OnStreamFrameLost(0, 7, false);
- stream_->OnCanWrite();
-
- EXPECT_EQ("Foo bar", write_buffer_);
- EXPECT_THAT(stream_->stream_error(), IsStreamError(QUIC_STREAM_CANCELLED));
-}
-
-TEST_P(QuartcStreamTest, MaxRetransmissionsAbsent) {
- CreateReliableQuicStream();
-
- // This should be the default state.
- EXPECT_EQ(stream_->max_retransmission_count(),
- std::numeric_limits<int>::max());
-
- char message[] = "Foo bar";
- test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
- stream_->WriteMemSlices(data.span(), /*fin=*/false);
-
- EXPECT_EQ("Foo bar", write_buffer_);
-
- stream_->OnStreamFrameLost(0, 7, false);
- stream_->OnCanWrite();
-
- EXPECT_EQ("Foo barFoo bar", write_buffer_);
- EXPECT_THAT(stream_->stream_error(), IsQuicStreamNoError());
-}
-
-TEST_P(QuartcStreamTest, MaxRetransmissionsSet) {
- CreateReliableQuicStream();
- stream_->set_max_retransmission_count(2);
-
- char message[] = "Foo bar";
- test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
- stream_->WriteMemSlices(data.span(), /*fin=*/false);
-
- EXPECT_EQ("Foo bar", write_buffer_);
-
- stream_->OnStreamFrameLost(0, 7, false);
- stream_->OnCanWrite();
-
- EXPECT_EQ("Foo barFoo bar", write_buffer_);
-
- stream_->OnStreamFrameLost(0, 7, false);
- stream_->OnCanWrite();
-
- EXPECT_EQ("Foo barFoo barFoo bar", write_buffer_);
-
- stream_->OnStreamFrameLost(0, 7, false);
- stream_->OnCanWrite();
-
- EXPECT_EQ("Foo barFoo barFoo bar", write_buffer_);
- EXPECT_THAT(stream_->stream_error(), IsStreamError(QUIC_STREAM_CANCELLED));
-}
-
-TEST_P(QuartcStreamTest, MaxRetransmissionsDisjointFrames) {
- CreateReliableQuicStream();
- stream_->set_max_retransmission_count(2);
-
- char message[] = "Foo bar";
- test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
- stream_->WriteMemSlices(data.span(), /*fin=*/false);
-
- EXPECT_EQ("Foo bar", write_buffer_);
-
- // Retransmit bytes [0, 3].
- stream_->OnStreamFrameLost(0, 4, false);
- stream_->OnCanWrite();
-
- EXPECT_EQ("Foo barFoo ", write_buffer_);
-
- // Retransmit bytes [4, 6]. Everything has been retransmitted once.
- stream_->OnStreamFrameLost(4, 3, false);
- stream_->OnCanWrite();
-
- EXPECT_EQ("Foo barFoo bar", write_buffer_);
-
- // Retransmit bytes [0, 6]. Everything can be retransmitted a second time.
- stream_->OnStreamFrameLost(0, 7, false);
- stream_->OnCanWrite();
-
- EXPECT_EQ("Foo barFoo barFoo bar", write_buffer_);
-}
-
-TEST_P(QuartcStreamTest, MaxRetransmissionsOverlappingFrames) {
- CreateReliableQuicStream();
- stream_->set_max_retransmission_count(2);
-
- char message[] = "Foo bar";
- test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
- stream_->WriteMemSlices(data.span(), /*fin=*/false);
-
- EXPECT_EQ("Foo bar", write_buffer_);
-
- // Retransmit bytes 0 to 3.
- stream_->OnStreamFrameLost(0, 4, false);
- stream_->OnCanWrite();
-
- EXPECT_EQ("Foo barFoo ", write_buffer_);
-
- // Retransmit bytes 3 to 6. Byte 3 has been retransmitted twice.
- stream_->OnStreamFrameLost(3, 4, false);
- stream_->OnCanWrite();
-
- EXPECT_EQ("Foo barFoo bar", write_buffer_);
-
- // Retransmit byte 3 a third time. This should cause cancellation.
- stream_->OnStreamFrameLost(3, 1, false);
- stream_->OnCanWrite();
-
- EXPECT_EQ("Foo barFoo bar", write_buffer_);
- EXPECT_THAT(stream_->stream_error(), IsStreamError(QUIC_STREAM_CANCELLED));
-}
-
-TEST_P(QuartcStreamTest, MaxRetransmissionsWithAckedFrame) {
- CreateReliableQuicStream();
- stream_->set_max_retransmission_count(1);
-
- char message[] = "Foo bar";
- test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
- stream_->WriteMemSlices(data.span(), /*fin=*/false);
-
- EXPECT_EQ("Foo bar", write_buffer_);
-
- // Retransmit bytes [0, 7).
- stream_->OnStreamFrameLost(0, 7, false);
- stream_->OnCanWrite();
-
- EXPECT_EQ("Foo barFoo bar", write_buffer_);
-
- // Ack bytes [0, 7). These bytes should be pruned from the data tracked by
- // the stream.
- QuicByteCount newly_acked_length = 0;
- stream_->OnStreamFrameAcked(0, 7, false, QuicTime::Delta::FromMilliseconds(1),
- QuicTime::Zero(), &newly_acked_length);
- EXPECT_EQ(7u, newly_acked_length);
- stream_->OnCanWrite();
-
- EXPECT_EQ("Foo barFoo bar", write_buffer_);
-
- // Retransmit bytes [0, 7) again.
- // QUIC will never mark frames as lost after they've been acked, but this lets
- // us test that QuartcStream stopped tracking these bytes after the acked.
- stream_->OnStreamFrameLost(0, 7, false);
- stream_->OnCanWrite();
-
- // QuartcStream should be cancelled, but it stopped tracking the lost bytes
- // after they were acked, so it's not.
- EXPECT_THAT(stream_->stream_error(), IsQuicStreamNoError());
-}
-
-TEST_P(QuartcStreamTest, TestBytesPendingRetransmission) {
- CreateReliableQuicStream();
- stream_->set_cancel_on_loss(false);
-
- char message[] = "Foo bar";
- test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
- stream_->WriteMemSlices(data.span(), /*fin=*/false);
-
- EXPECT_EQ("Foo bar", write_buffer_);
-
- stream_->OnStreamFrameLost(0, 4, false);
- EXPECT_EQ(stream_->BytesPendingRetransmission(), 4u);
- EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 4u);
-
- stream_->OnStreamFrameLost(4, 3, false);
- EXPECT_EQ(stream_->BytesPendingRetransmission(), 7u);
- EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 7u);
-
- stream_->OnCanWrite();
- EXPECT_EQ(stream_->BytesPendingRetransmission(), 0u);
- EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0u);
-
- EXPECT_EQ("Foo barFoo bar", write_buffer_);
- EXPECT_THAT(stream_->stream_error(), IsQuicStreamNoError());
-}
-
-TEST_P(QuartcStreamTest, TestBytesPendingRetransmissionWithCancelOnLoss) {
- CreateReliableQuicStream();
- stream_->set_cancel_on_loss(true);
-
- char message[] = "Foo bar";
- test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
- stream_->WriteMemSlices(data.span(), /*fin=*/false);
-
- EXPECT_EQ("Foo bar", write_buffer_);
-
- stream_->OnStreamFrameLost(0, 4, false);
- EXPECT_EQ(stream_->BytesPendingRetransmission(), 0u);
- EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0u);
-
- stream_->OnStreamFrameLost(4, 3, false);
- EXPECT_EQ(stream_->BytesPendingRetransmission(), 0u);
- EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0u);
-
- stream_->OnCanWrite();
- EXPECT_EQ(stream_->BytesPendingRetransmission(), 0u);
- EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0u);
-
- EXPECT_EQ("Foo bar", write_buffer_);
- EXPECT_THAT(stream_->stream_error(), IsStreamError(QUIC_STREAM_CANCELLED));
-}
-
-} // namespace
-
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport.cc b/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport.cc
deleted file mode 100644
index 263c21395e0..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h"
-
-#include <utility>
-
-#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
-
-namespace quic {
-namespace simulator {
-
-SimulatedQuartcPacketTransport::SimulatedQuartcPacketTransport(
- Simulator* simulator,
- const std::string& name,
- const std::string& peer_name,
- QuicByteCount queue_capacity)
- : Endpoint(simulator, name),
- peer_name_(peer_name),
- egress_queue_(simulator,
- quiche::QuicheStringPrintf("%s (TX Queue)", name.c_str()),
- queue_capacity) {
- egress_queue_.set_listener_interface(this);
-}
-
-int SimulatedQuartcPacketTransport::Write(const char* buffer,
- size_t buf_len,
- const PacketInfo& info) {
- if (!writable_) {
- return 0;
- }
- if (egress_queue_.bytes_queued() + buf_len > egress_queue_.capacity()) {
- return 0;
- }
-
- last_packet_number_ = info.packet_number;
-
- auto packet = std::make_unique<Packet>();
- packet->contents = std::string(buffer, buf_len);
- packet->size = buf_len;
- packet->tx_timestamp = clock_->Now();
- packet->source = name();
- packet->destination = peer_name_;
-
- egress_queue_.AcceptPacket(std::move(packet));
- return buf_len;
-}
-
-void SimulatedQuartcPacketTransport::SetDelegate(Delegate* delegate) {
- delegate_ = delegate;
- Schedule(clock_->Now());
-}
-
-UnconstrainedPortInterface* SimulatedQuartcPacketTransport::GetRxPort() {
- return this;
-}
-
-void SimulatedQuartcPacketTransport::SetTxPort(ConstrainedPortInterface* port) {
- egress_queue_.set_tx_port(port);
- Schedule(clock_->Now());
-}
-
-void SimulatedQuartcPacketTransport::AcceptPacket(
- std::unique_ptr<Packet> packet) {
- // Simulated switches broadcast packets to all ports if the cannot determine
- // the recipient, so we need to drop packets that aren't intended for us.
- if (packet->destination != name()) {
- return;
- }
-
- if (delegate_) {
- delegate_->OnTransportReceived(packet->contents.data(), packet->size);
- }
-}
-
-void SimulatedQuartcPacketTransport::OnPacketDequeued() {
- if (delegate_ && writable_) {
- delegate_->OnTransportCanWrite();
- }
-}
-
-void SimulatedQuartcPacketTransport::Act() {
- if (delegate_ && writable_) {
- delegate_->OnTransportCanWrite();
- }
-}
-
-void SimulatedQuartcPacketTransport::SetWritable(bool writable) {
- writable_ = writable;
- if (writable_) {
- // May need to call |Delegate::OnTransportCanWrite|.
- Schedule(clock_->Now());
- }
-}
-
-} // namespace simulator
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h b/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h
deleted file mode 100644
index 185668b528a..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_QUARTC_SIMULATED_PACKET_TRANSPORT_H_
-#define QUICHE_QUIC_QUARTC_SIMULATED_PACKET_TRANSPORT_H_
-
-#include <string>
-
-#include "net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h"
-#include "net/third_party/quiche/src/quic/test_tools/simulator/port.h"
-#include "net/third_party/quiche/src/quic/test_tools/simulator/queue.h"
-
-namespace quic {
-namespace simulator {
-
-// Simulated implementation of QuartcPacketTransport. This packet transport
-// implementation connects Quartc to a QUIC simulator's network fabric.
-// Assumes that its caller and delegate run on the same thread as the network
-// simulation and therefore require no additional synchronization.
-class SimulatedQuartcPacketTransport : public Endpoint,
- public QuartcPacketTransport,
- public UnconstrainedPortInterface,
- public Queue::ListenerInterface {
- public:
- SimulatedQuartcPacketTransport(Simulator* simulator,
- const std::string& name,
- const std::string& peer_name,
- QuicByteCount queue_capacity);
-
- // QuartcPacketTransport methods.
- int Write(const char* buffer,
- size_t buf_len,
- const PacketInfo& info) override;
- void SetDelegate(Delegate* delegate) override;
-
- // Simulation methods below. These are implementation details.
-
- // Endpoint methods. Called by the simulation to connect the transport.
- UnconstrainedPortInterface* GetRxPort() override;
- void SetTxPort(ConstrainedPortInterface* port) override;
-
- // UnconstrainedPortInterface method. Called by the simulation to deliver a
- // packet to this transport.
- void AcceptPacket(std::unique_ptr<Packet> packet) override;
-
- // Queue::ListenerInterface method. Called when the internal egress queue has
- // dispatched a packet and may have room for more.
- void OnPacketDequeued() override;
-
- // Actor method. The transport schedules this to run when the delegate is set
- // in order to trigger an initial call to |Delegate::OnTransportCanWrite()|.
- // (The Quartc packet writer starts in a blocked state and needs an initial
- // callback to unblock it.)
- void Act() override;
-
- // Changes whether the transport is writable. If |writable| is false, the
- // transport will reject calls to |Write| and will not call
- // |Delegate::OnTransportCanWrite|. If |writable| is true, the transport will
- // allow calls to |Write| and will call |Delegate::OnTransportCanWrite|
- // whenever it is able to write another packet.
- void SetWritable(bool writable);
-
- // Last packet number sent over this simulated transport.
- // TODO(b/112561077): Reorganize tests so that this method can be deleted.
- // This exists purely for use by quartc_session_test.cc, to test that the
- // packet writer passes packet numbers to the transport.
- QuicPacketNumber last_packet_number() { return last_packet_number_; }
-
- private:
- std::string peer_name_;
- Delegate* delegate_ = nullptr;
- Queue egress_queue_;
- QuicPacketNumber last_packet_number_;
-
- // Controls whether the transport is considered to be writable. Used to
- // simulate behavior that arises when the transport is blocked.
- bool writable_ = true;
-};
-
-} // namespace simulator
-} // namespace quic
-
-#endif // QUICHE_QUIC_QUARTC_SIMULATED_PACKET_TRANSPORT_H_
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport_test.cc
deleted file mode 100644
index 24a4f4fc49f..00000000000
--- a/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport_test.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h"
-
-#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h"
-#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h"
-#include "net/third_party/quiche/src/quic/test_tools/simulator/switch.h"
-
-namespace quic {
-namespace simulator {
-namespace {
-
-using ::testing::ElementsAre;
-
-const QuicBandwidth kDefaultBandwidth =
- QuicBandwidth::FromKBitsPerSecond(10 * 1000);
-const QuicTime::Delta kDefaultPropagationDelay =
- QuicTime::Delta::FromMilliseconds(20);
-const QuicByteCount kDefaultBdp = kDefaultBandwidth * kDefaultPropagationDelay;
-const QuicByteCount kDefaultPacketSize = 1200;
-const QuicPacketCount kDefaultQueueLength = 10;
-
-class FakeDelegate : public QuartcPacketTransport::Delegate {
- public:
- explicit FakeDelegate(QuartcPacketTransport* transport)
- : transport_(transport) {
- transport_->SetDelegate(this);
- }
-
- ~FakeDelegate() { transport_->SetDelegate(nullptr); }
-
- void OnTransportCanWrite() override {
- while (!packets_to_send_.empty()) {
- const std::string& packet = packets_to_send_.front();
- if (transport_->Write(packet.data(), packet.size(),
- QuartcPacketTransport::PacketInfo()) <
- static_cast<int>(packet.size())) {
- ++write_blocked_count_;
- return;
- }
- packets_to_send_.pop();
- }
- }
-
- void OnTransportReceived(const char* data, size_t data_len) override {
- packets_received_.emplace_back(data, data_len);
- }
-
- void AddPacketToSend(const std::string& packet) {
- packets_to_send_.push(packet);
- }
-
- size_t packets_to_send() { return packets_to_send_.size(); }
- const std::vector<std::string>& packets_received() {
- return packets_received_;
- }
- int write_blocked_count() { return write_blocked_count_; }
-
- private:
- QuartcPacketTransport* const transport_ = nullptr;
- std::queue<std::string> packets_to_send_;
- std::vector<std::string> packets_received_;
- int write_blocked_count_ = 0;
-};
-
-class SimulatedPacketTransportTest : public QuicTest {
- protected:
- SimulatedPacketTransportTest()
- : switch_(&simulator_, "Switch", /*port_count=*/8, 2 * kDefaultBdp),
- client_(&simulator_,
- "sender",
- "receiver",
- kDefaultQueueLength * kDefaultPacketSize),
- server_(&simulator_,
- "receiver",
- "sender",
- kDefaultQueueLength * kDefaultPacketSize),
- client_link_(&client_,
- switch_.port(1),
- kDefaultBandwidth,
- kDefaultPropagationDelay),
- server_link_(&server_,
- switch_.port(2),
- kDefaultBandwidth,
- kDefaultPropagationDelay),
- client_delegate_(&client_),
- server_delegate_(&server_) {}
-
- Simulator simulator_;
- Switch switch_;
-
- SimulatedQuartcPacketTransport client_;
- SimulatedQuartcPacketTransport server_;
-
- SymmetricLink client_link_;
- SymmetricLink server_link_;
-
- FakeDelegate client_delegate_;
- FakeDelegate server_delegate_;
-};
-
-TEST_F(SimulatedPacketTransportTest, OneWayTransmission) {
- std::string packet_1(kDefaultPacketSize, 'a');
- std::string packet_2(kDefaultPacketSize, 'b');
- client_delegate_.AddPacketToSend(packet_1);
- client_delegate_.AddPacketToSend(packet_2);
-
- simulator_.RunUntil(
- [this] { return client_delegate_.packets_to_send() == 0; });
- simulator_.RunFor(3 * kDefaultPropagationDelay);
-
- EXPECT_THAT(server_delegate_.packets_received(),
- ElementsAre(packet_1, packet_2));
- EXPECT_THAT(client_delegate_.packets_received(), ElementsAre());
-}
-
-TEST_F(SimulatedPacketTransportTest, TwoWayTransmission) {
- std::string packet_1(kDefaultPacketSize, 'a');
- std::string packet_2(kDefaultPacketSize, 'b');
- std::string packet_3(kDefaultPacketSize, 'c');
- std::string packet_4(kDefaultPacketSize, 'd');
-
- client_delegate_.AddPacketToSend(packet_1);
- client_delegate_.AddPacketToSend(packet_2);
- server_delegate_.AddPacketToSend(packet_3);
- server_delegate_.AddPacketToSend(packet_4);
-
- simulator_.RunUntil(
- [this] { return client_delegate_.packets_to_send() == 0; });
- simulator_.RunUntil(
- [this] { return server_delegate_.packets_to_send() == 0; });
- simulator_.RunFor(3 * kDefaultPropagationDelay);
-
- EXPECT_THAT(server_delegate_.packets_received(),
- ElementsAre(packet_1, packet_2));
- EXPECT_THAT(client_delegate_.packets_received(),
- ElementsAre(packet_3, packet_4));
-}
-
-TEST_F(SimulatedPacketTransportTest, TestWriteBlocked) {
- // Add 10 packets beyond what fits in the egress queue.
- std::vector<std::string> packets;
- for (unsigned int i = 0; i < kDefaultQueueLength + 10; ++i) {
- packets.push_back(std::string(kDefaultPacketSize, 'a' + i));
- client_delegate_.AddPacketToSend(packets.back());
- }
-
- simulator_.RunUntil(
- [this] { return client_delegate_.packets_to_send() == 0; });
- simulator_.RunFor(3 * kDefaultPropagationDelay);
-
- // Each of the 10 packets in excess of the sender's egress queue length will
- // block the first time |client_delegate_| tries to write them.
- EXPECT_EQ(client_delegate_.write_blocked_count(), 10);
- EXPECT_EQ(server_delegate_.packets_received(), packets);
-}
-
-} // namespace
-} // namespace simulator
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.cc
index 401ae7e4278..0fb988aed37 100644
--- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.cc
@@ -23,7 +23,8 @@ QuicTransportStream::QuicTransportStream(
/*is_static=*/false,
QuicUtils::GetStreamType(id,
session->connection()->perspective(),
- session->IsIncomingStream(id))),
+ session->IsIncomingStream(id),
+ session->version())),
session_interface_(session_interface) {}
size_t QuicTransportStream::Read(char* buffer, size_t buffer_size) {
diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc
new file mode 100644
index 00000000000..81466de1240
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc
@@ -0,0 +1,221 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.h"
+
+#include <cstdint>
+#include <memory>
+
+#include "third_party/boringssl/src/include/openssl/sha.h"
+#include "net/third_party/quiche/src/quic/core/crypto/certificate_view.h"
+#include "net/third_party/quiche/src/quic/core/quic_time.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
+
+namespace quic {
+namespace {
+
+constexpr size_t kFingerprintLength = SHA256_DIGEST_LENGTH * 3 - 1;
+
+constexpr std::array<char, 16> kHexDigits = {'0', '1', '2', '3', '4', '5',
+ '6', '7', '8', '9', 'a', 'b',
+ 'c', 'd', 'e', 'f'};
+
+// Assumes that the character is normalized to lowercase beforehand.
+bool IsNormalizedHexDigit(char c) {
+ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
+}
+
+void NormalizeFingerprint(CertificateFingerprint& fingerprint) {
+ fingerprint.fingerprint =
+ quiche::QuicheTextUtils::ToLower(fingerprint.fingerprint);
+}
+
+} // namespace
+
+constexpr char CertificateFingerprint::kSha256[];
+
+std::string ComputeSha256Fingerprint(quiche::QuicheStringPiece input) {
+ std::vector<uint8_t> raw_hash;
+ raw_hash.resize(SHA256_DIGEST_LENGTH);
+ SHA256(reinterpret_cast<const uint8_t*>(input.data()), input.size(),
+ raw_hash.data());
+
+ std::string output;
+ output.resize(kFingerprintLength);
+ for (size_t i = 0; i < output.size(); i++) {
+ uint8_t hash_byte = raw_hash[i / 3];
+ switch (i % 3) {
+ case 0:
+ output[i] = kHexDigits[hash_byte >> 4];
+ break;
+ case 1:
+ output[i] = kHexDigits[hash_byte & 0xf];
+ break;
+ case 2:
+ output[i] = ':';
+ break;
+ }
+ }
+ return output;
+}
+
+ProofVerifyDetails* WebTransportFingerprintProofVerifier::Details::Clone()
+ const {
+ return new Details(*this);
+}
+
+WebTransportFingerprintProofVerifier::WebTransportFingerprintProofVerifier(
+ const QuicClock* clock,
+ int max_validity_days)
+ : clock_(clock),
+ max_validity_days_(max_validity_days),
+ // Add an extra second to max validity to accomodate various edge cases.
+ max_validity_(
+ QuicTime::Delta::FromSeconds(max_validity_days * 86400 + 1)) {}
+
+bool WebTransportFingerprintProofVerifier::AddFingerprint(
+ CertificateFingerprint fingerprint) {
+ NormalizeFingerprint(fingerprint);
+ if (fingerprint.algorithm != CertificateFingerprint::kSha256) {
+ QUIC_DLOG(WARNING) << "Algorithms other than SHA-256 are not supported";
+ return false;
+ }
+ if (fingerprint.fingerprint.size() != kFingerprintLength) {
+ QUIC_DLOG(WARNING) << "Invalid fingerprint length";
+ return false;
+ }
+ for (size_t i = 0; i < fingerprint.fingerprint.size(); i++) {
+ char current = fingerprint.fingerprint[i];
+ if (i % 3 == 2) {
+ if (current != ':') {
+ QUIC_DLOG(WARNING)
+ << "Missing colon separator between the bytes of the hash";
+ return false;
+ }
+ } else {
+ if (!IsNormalizedHexDigit(current)) {
+ QUIC_DLOG(WARNING) << "Fingerprint must be in hexadecimal";
+ return false;
+ }
+ }
+ }
+
+ fingerprints_.push_back(fingerprint);
+ return true;
+}
+
+QuicAsyncStatus WebTransportFingerprintProofVerifier::VerifyProof(
+ const std::string& /*hostname*/,
+ const uint16_t /*port*/,
+ const std::string& /*server_config*/,
+ QuicTransportVersion /*transport_version*/,
+ quiche::QuicheStringPiece /*chlo_hash*/,
+ const std::vector<std::string>& /*certs*/,
+ const std::string& /*cert_sct*/,
+ const std::string& /*signature*/,
+ const ProofVerifyContext* /*context*/,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* details,
+ std::unique_ptr<ProofVerifierCallback> /*callback*/) {
+ *error_details =
+ "QUIC crypto certificate verification is not supported in "
+ "WebTransportFingerprintProofVerifier";
+ QUIC_BUG << *error_details;
+ *details = std::make_unique<Details>(Status::kInternalError);
+ return QUIC_FAILURE;
+}
+
+QuicAsyncStatus WebTransportFingerprintProofVerifier::VerifyCertChain(
+ const std::string& /*hostname*/,
+ const uint16_t /*port*/,
+ const std::vector<std::string>& certs,
+ const std::string& /*ocsp_response*/,
+ const std::string& /*cert_sct*/,
+ const ProofVerifyContext* /*context*/,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* details,
+ std::unique_ptr<ProofVerifierCallback> /*callback*/) {
+ if (certs.empty()) {
+ *details = std::make_unique<Details>(Status::kInternalError);
+ *error_details = "No certificates provided";
+ return QUIC_FAILURE;
+ }
+
+ if (!HasKnownFingerprint(certs[0])) {
+ *details = std::make_unique<Details>(Status::kUnknownFingerprint);
+ *error_details = "Certificate does not match any fingerprint";
+ return QUIC_FAILURE;
+ }
+
+ std::unique_ptr<CertificateView> view =
+ CertificateView::ParseSingleCertificate(certs[0]);
+ if (view == nullptr) {
+ *details = std::make_unique<Details>(Status::kCertificateParseFailure);
+ *error_details = "Failed to parse the certificate";
+ return QUIC_FAILURE;
+ }
+
+ if (!HasValidExpiry(*view)) {
+ *details = std::make_unique<Details>(Status::kExpiryTooLong);
+ *error_details = quiche::QuicheStrCat(
+ "Certificate expiry exceeds the configured limit of ",
+ max_validity_days_, " days");
+ return QUIC_FAILURE;
+ }
+
+ if (!IsWithinValidityPeriod(*view)) {
+ *details = std::make_unique<Details>(Status::kExpired);
+ *error_details =
+ "Certificate has expired or has validity listed in the future";
+ return QUIC_FAILURE;
+ }
+
+ *details = std::make_unique<Details>(Status::kValidCertificate);
+ return QUIC_SUCCESS;
+}
+
+std::unique_ptr<ProofVerifyContext>
+WebTransportFingerprintProofVerifier::CreateDefaultContext() {
+ return nullptr;
+}
+
+bool WebTransportFingerprintProofVerifier::HasKnownFingerprint(
+ quiche::QuicheStringPiece der_certificate) {
+ // https://wicg.github.io/web-transport/#verify-a-certificate-fingerprint
+ const std::string fingerprint = ComputeSha256Fingerprint(der_certificate);
+ for (const CertificateFingerprint& reference : fingerprints_) {
+ if (reference.algorithm != CertificateFingerprint::kSha256) {
+ QUIC_BUG << "Unexpected non-SHA-256 hash";
+ continue;
+ }
+ if (fingerprint == reference.fingerprint) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool WebTransportFingerprintProofVerifier::HasValidExpiry(
+ const CertificateView& certificate) {
+ if (!certificate.validity_start().IsBefore(certificate.validity_end())) {
+ return false;
+ }
+
+ const QuicTime::Delta duration_seconds =
+ certificate.validity_end() - certificate.validity_start();
+ return duration_seconds <= max_validity_;
+}
+
+bool WebTransportFingerprintProofVerifier::IsWithinValidityPeriod(
+ const CertificateView& certificate) {
+ QuicWallTime now = clock_->WallNow();
+ return now.IsAfter(certificate.validity_start()) &&
+ now.IsBefore(certificate.validity_end());
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.h b/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.h
new file mode 100644
index 00000000000..7e4358de60d
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.h
@@ -0,0 +1,119 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QUIC_TRANSPORT_FINGERPRINT_PROOF_VERIFIER_H_
+#define QUICHE_QUIC_QUIC_TRANSPORT_FINGERPRINT_PROOF_VERIFIER_H_
+
+#include <vector>
+
+#include "net/third_party/quiche/src/quic/core/crypto/certificate_view.h"
+#include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h"
+#include "net/third_party/quiche/src/quic/core/quic_clock.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
+
+namespace quic {
+
+// Represents a fingerprint of an X.509 certificate in a format based on
+// https://w3c.github.io/webrtc-pc/#dom-rtcdtlsfingerprint.
+struct QUIC_EXPORT_PRIVATE CertificateFingerprint {
+ static constexpr char kSha256[] = "sha-256";
+
+ // An algorithm described by one of the names in
+ // https://www.iana.org/assignments/hash-function-text-names/hash-function-text-names.xhtml
+ std::string algorithm;
+ // Hex-encoded, colon-separated fingerprint of the certificate. For example,
+ // "12:3d:5b:71:8c:54:df:85:7e:bd:e3:7c:66:da:f9:db:6a:94:8f:85:cb:6e:44:7f:09:3e:05:f2:dd:d4:f7:86"
+ std::string fingerprint;
+};
+
+// Computes a SHA-256 fingerprint of the specified input formatted in the same
+// format as CertificateFingerprint::fingerprint would contain.
+QUIC_EXPORT_PRIVATE std::string ComputeSha256Fingerprint(
+ quiche::QuicheStringPiece input);
+
+// WebTransportFingerprintProofVerifier verifies the server leaf certificate
+// against a supplied list of certificate fingerprints following the procedure
+// described in the WebTransport specification. The certificate is deemed
+// trusted if it matches a fingerprint in the list, has expiry dates that are
+// not too long and has not expired. Only the leaf is checked, the rest of the
+// chain is ignored. Reference specification:
+// https://wicg.github.io/web-transport/#dom-quictransportconfiguration-server_certificate_fingerprints
+class QUIC_EXPORT_PRIVATE WebTransportFingerprintProofVerifier
+ : public ProofVerifier {
+ public:
+ // Note: the entries in this list may be logged into a UMA histogram, and thus
+ // should not be renumbered.
+ enum class Status {
+ kValidCertificate = 0,
+ kUnknownFingerprint = 1,
+ kCertificateParseFailure = 2,
+ kExpiryTooLong = 3,
+ kExpired = 4,
+ kInternalError = 5,
+
+ kMaxValue = kInternalError,
+ };
+
+ class QUIC_EXPORT_PRIVATE Details : public ProofVerifyDetails {
+ public:
+ explicit Details(Status status) : status_(status) {}
+ Status status() const { return status_; }
+
+ ProofVerifyDetails* Clone() const override;
+
+ private:
+ const Status status_;
+ };
+
+ // |clock| is used to check if the certificate has expired. It is not owned
+ // and must outlive the object. |max_validity_days| is the maximum time for
+ // which the certificate is allowed to be valid.
+ WebTransportFingerprintProofVerifier(const QuicClock* clock,
+ int max_validity_days);
+
+ // Adds a certificate fingerprint to be trusted. The fingerprints are
+ // case-insensitive and are validated internally; the function returns true if
+ // the validation passes.
+ bool AddFingerprint(CertificateFingerprint fingerprint);
+
+ // ProofVerifier implementation.
+ QuicAsyncStatus VerifyProof(
+ const std::string& hostname,
+ const uint16_t port,
+ const std::string& server_config,
+ QuicTransportVersion transport_version,
+ quiche::QuicheStringPiece chlo_hash,
+ const std::vector<std::string>& certs,
+ const std::string& cert_sct,
+ const std::string& signature,
+ const ProofVerifyContext* context,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* details,
+ std::unique_ptr<ProofVerifierCallback> callback) override;
+ QuicAsyncStatus VerifyCertChain(
+ const std::string& hostname,
+ const uint16_t port,
+ const std::vector<std::string>& certs,
+ const std::string& ocsp_response,
+ const std::string& cert_sct,
+ const ProofVerifyContext* context,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* details,
+ std::unique_ptr<ProofVerifierCallback> callback) override;
+ std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override;
+
+ private:
+ bool HasKnownFingerprint(quiche::QuicheStringPiece der_certificate);
+ bool HasValidExpiry(const CertificateView& certificate);
+ bool IsWithinValidityPeriod(const CertificateView& certificate);
+
+ const QuicClock* clock_; // Unowned.
+ const int max_validity_days_;
+ const QuicTime::Delta max_validity_;
+ std::vector<CertificateFingerprint> fingerprints_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QUIC_TRANSPORT_FINGERPRINT_PROOF_VERIFIER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier_test.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier_test.cc
new file mode 100644
index 00000000000..f9f27e5db69
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier_test.cc
@@ -0,0 +1,183 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.h"
+
+#include <memory>
+
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
+#include "net/third_party/quiche/src/quic/test_tools/test_certificates.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
+
+namespace quic {
+namespace test {
+namespace {
+
+using ::testing::HasSubstr;
+
+// 2020-02-01 12:35:56 UTC
+constexpr QuicTime::Delta kValidTime = QuicTime::Delta::FromSeconds(1580560556);
+
+struct VerifyResult {
+ QuicAsyncStatus status;
+ WebTransportFingerprintProofVerifier::Status detailed_status;
+ std::string error;
+};
+
+class WebTransportFingerprintProofVerifierTest : public QuicTest {
+ public:
+ WebTransportFingerprintProofVerifierTest() {
+ clock_.AdvanceTime(kValidTime);
+ verifier_ = std::make_unique<WebTransportFingerprintProofVerifier>(
+ &clock_, /*max_validity_days=*/365);
+ AddTestCertificate();
+ }
+
+ protected:
+ VerifyResult Verify(quiche::QuicheStringPiece certificate) {
+ VerifyResult result;
+ std::unique_ptr<ProofVerifyDetails> details;
+ result.status = verifier_->VerifyCertChain(
+ /*hostname=*/"", /*port=*/0,
+ std::vector<std::string>{std::string(certificate)},
+ /*ocsp_response=*/"",
+ /*cert_sct=*/"",
+ /*context=*/nullptr, &result.error, &details,
+ /*callback=*/nullptr);
+ result.detailed_status =
+ static_cast<WebTransportFingerprintProofVerifier::Details*>(
+ details.get())
+ ->status();
+ return result;
+ }
+
+ void AddTestCertificate() {
+ EXPECT_TRUE(verifier_->AddFingerprint(
+ CertificateFingerprint{CertificateFingerprint::kSha256,
+ ComputeSha256Fingerprint(kTestCertificate)}));
+ }
+
+ MockClock clock_;
+ std::unique_ptr<WebTransportFingerprintProofVerifier> verifier_;
+};
+
+TEST_F(WebTransportFingerprintProofVerifierTest, Sha256Fingerprint) {
+ // Computed using `openssl x509 -fingerprint -sha256`.
+ EXPECT_EQ(ComputeSha256Fingerprint(kTestCertificate),
+ "f2:e5:46:5e:2b:f7:ec:d6:f6:30:66:a5:a3:75:11:73:4a:a0:eb:7c:47:01:"
+ "0e:86:d6:75:8e:d4:f4:fa:1b:0f");
+}
+
+TEST_F(WebTransportFingerprintProofVerifierTest, SimpleFingerprint) {
+ VerifyResult result = Verify(kTestCertificate);
+ EXPECT_EQ(result.status, QUIC_SUCCESS);
+ EXPECT_EQ(result.detailed_status,
+ WebTransportFingerprintProofVerifier::Status::kValidCertificate);
+
+ result = Verify(kWildcardCertificate);
+ EXPECT_EQ(result.status, QUIC_FAILURE);
+ EXPECT_EQ(result.detailed_status,
+ WebTransportFingerprintProofVerifier::Status::kUnknownFingerprint);
+
+ result = Verify("Some random text");
+ EXPECT_EQ(result.status, QUIC_FAILURE);
+}
+
+TEST_F(WebTransportFingerprintProofVerifierTest, Validity) {
+ // Validity periods of kTestCertificate, according to `openssl x509 -text`:
+ // Not Before: Jan 30 18:13:59 2020 GMT
+ // Not After : Feb 2 18:13:59 2020 GMT
+
+ // 2020-01-29 19:00:00 UTC
+ constexpr QuicTime::Delta kStartTime =
+ QuicTime::Delta::FromSeconds(1580324400);
+ clock_.Reset();
+ clock_.AdvanceTime(kStartTime);
+
+ VerifyResult result = Verify(kTestCertificate);
+ EXPECT_EQ(result.status, QUIC_FAILURE);
+ EXPECT_EQ(result.detailed_status,
+ WebTransportFingerprintProofVerifier::Status::kExpired);
+
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(86400));
+ result = Verify(kTestCertificate);
+ EXPECT_EQ(result.status, QUIC_SUCCESS);
+ EXPECT_EQ(result.detailed_status,
+ WebTransportFingerprintProofVerifier::Status::kValidCertificate);
+
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(4 * 86400));
+ result = Verify(kTestCertificate);
+ EXPECT_EQ(result.status, QUIC_FAILURE);
+ EXPECT_EQ(result.detailed_status,
+ WebTransportFingerprintProofVerifier::Status::kExpired);
+}
+
+TEST_F(WebTransportFingerprintProofVerifierTest, MaxValidity) {
+ verifier_ = std::make_unique<WebTransportFingerprintProofVerifier>(
+ &clock_, /*max_validity_days=*/2);
+ AddTestCertificate();
+ VerifyResult result = Verify(kTestCertificate);
+ EXPECT_EQ(result.status, QUIC_FAILURE);
+ EXPECT_EQ(result.detailed_status,
+ WebTransportFingerprintProofVerifier::Status::kExpiryTooLong);
+ EXPECT_THAT(result.error, HasSubstr("limit of 2 days"));
+
+ // kTestCertificate is valid for exactly four days.
+ verifier_ = std::make_unique<WebTransportFingerprintProofVerifier>(
+ &clock_, /*max_validity_days=*/4);
+ AddTestCertificate();
+ result = Verify(kTestCertificate);
+ EXPECT_EQ(result.status, QUIC_SUCCESS);
+ EXPECT_EQ(result.detailed_status,
+ WebTransportFingerprintProofVerifier::Status::kValidCertificate);
+}
+
+TEST_F(WebTransportFingerprintProofVerifierTest, InvalidCertificate) {
+ constexpr quiche::QuicheStringPiece kInvalidCertificate = "Hello, world!";
+ ASSERT_TRUE(verifier_->AddFingerprint(
+ {CertificateFingerprint::kSha256,
+ ComputeSha256Fingerprint(kInvalidCertificate)}));
+
+ VerifyResult result = Verify(kInvalidCertificate);
+ EXPECT_EQ(result.status, QUIC_FAILURE);
+ EXPECT_EQ(
+ result.detailed_status,
+ WebTransportFingerprintProofVerifier::Status::kCertificateParseFailure);
+}
+
+TEST_F(WebTransportFingerprintProofVerifierTest, AddCertificate) {
+ // Accept all-uppercase fingerprints.
+ verifier_ = std::make_unique<WebTransportFingerprintProofVerifier>(
+ &clock_, /*max_validity_days=*/365);
+ EXPECT_TRUE(verifier_->AddFingerprint(
+ {CertificateFingerprint::kSha256,
+ "F2:E5:46:5E:2B:F7:EC:D6:F6:30:66:A5:A3:75:11:73:4A:A0:EB:"
+ "7C:47:01:0E:86:D6:75:8E:D4:F4:FA:1B:0F"}));
+ EXPECT_EQ(Verify(kTestCertificate).detailed_status,
+ WebTransportFingerprintProofVerifier::Status::kValidCertificate);
+
+ // Reject unknown hash algorithms.
+ EXPECT_FALSE(verifier_->AddFingerprint(
+ {"sha-1",
+ "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"}));
+ // Reject invalid length.
+ EXPECT_FALSE(verifier_->AddFingerprint(
+ {CertificateFingerprint::kSha256, "00:00:00:00"}));
+ // Reject missing colons.
+ EXPECT_FALSE(verifier_->AddFingerprint(
+ {CertificateFingerprint::kSha256,
+ "00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00."
+ "00.00.00.00.00.00.00.00.00.00.00.00.00"}));
+ // Reject non-hex symbols.
+ EXPECT_FALSE(verifier_->AddFingerprint(
+ {CertificateFingerprint::kSha256,
+ "zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:"
+ "zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz"}));
+}
+
+} // namespace
+} // namespace test
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc b/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc
index 486444183c9..eacbca5287c 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc
@@ -242,7 +242,12 @@ int HandshakeWithFakeServer(QuicConfig* server_quic_config,
TestQuicSpdyServerSession server_session(
server_conn, *server_quic_config, client_conn->supported_versions(),
crypto_config, &compressed_certs_cache);
+ // Call SetServerApplicationStateForResumption so that the fake server
+ // supports 0-RTT in TLS.
server_session.Initialize();
+ server_session.GetMutableCryptoStream()
+ ->SetServerApplicationStateForResumption(
+ std::make_unique<ApplicationState>());
EXPECT_CALL(*server_session.helper(),
CanAcceptClientHello(testing::_, testing::_, testing::_,
testing::_, testing::_))
@@ -404,9 +409,6 @@ std::pair<size_t, size_t> AdvanceHandshake(PacketSavingConnection* client_conn,
QUIC_LOG(INFO) << "Processing "
<< server_conn->encrypted_packets_.size() - server_i
<< " packets server->client";
- if (server_conn->encrypted_packets_.size() - server_i == 2) {
- QUIC_LOG(INFO) << "here";
- }
MovePackets(server_conn, &server_i, client, client_conn,
Perspective::IS_CLIENT);
@@ -574,7 +576,7 @@ void CompareCrypters(const QuicEncrypter* encrypter,
std::string label) {
if (encrypter == nullptr || decrypter == nullptr) {
ADD_FAILURE() << "Expected non-null crypters; have " << encrypter << " and "
- << decrypter;
+ << decrypter << " for " << label;
return;
}
quiche::QuicheStringPiece encrypter_key = encrypter->GetKey();
@@ -605,7 +607,8 @@ void CompareClientAndServerKeys(QuicCryptoClientStream* client,
const QuicDecrypter* server_decrypter(
QuicFramerPeer::GetDecrypter(server_framer, level));
if (level == ENCRYPTION_FORWARD_SECURE ||
- !((level == ENCRYPTION_HANDSHAKE || client_encrypter == nullptr) &&
+ !((level == ENCRYPTION_HANDSHAKE || level == ENCRYPTION_ZERO_RTT ||
+ client_encrypter == nullptr) &&
server_decrypter == nullptr)) {
CompareCrypters(client_encrypter, server_decrypter,
"client " + EncryptionLevelString(level) + " write");
@@ -616,7 +619,8 @@ void CompareClientAndServerKeys(QuicCryptoClientStream* client,
QuicFramerPeer::GetDecrypter(client_framer, level));
if (level == ENCRYPTION_FORWARD_SECURE ||
!(server_encrypter == nullptr &&
- (level == ENCRYPTION_HANDSHAKE || client_decrypter == nullptr))) {
+ (level == ENCRYPTION_HANDSHAKE || level == ENCRYPTION_ZERO_RTT ||
+ client_decrypter == nullptr))) {
CompareCrypters(server_encrypter, client_decrypter,
"server " + EncryptionLevelString(level) + " write");
}
@@ -748,10 +752,11 @@ void MovePackets(PacketSavingConnection* source_conn,
QuicConnectionPeer::AddBytesReceived(
dest_conn, source_conn->encrypted_packets_[index]->length());
if (!framer.ProcessPacket(*source_conn->encrypted_packets_[index])) {
- // The framer will be unable to decrypt forward-secure packets sent after
- // the handshake is complete. Don't treat them as handshake packets.
+ // The framer will be unable to decrypt zero-rtt packets sent during
+ // handshake or forward-secure packets sent after the handshake is
+ // complete. Don't treat them as handshake packets.
QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
- break;
+ continue;
}
QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
dest_conn->OnDecryptedPacket(framer.last_decrypted_level());
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/first_flight.h b/chromium/net/third_party/quiche/src/quic/test_tools/first_flight.h
index b2a4ebd36be..ad5f792e0b9 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/first_flight.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/first_flight.h
@@ -49,10 +49,10 @@ class QUIC_NO_EXPORT DelegatedPacketWriter : public QuicPacketWriter {
}
bool SupportsReleaseTime() const override { return false; }
bool IsBatchMode() const override { return false; }
- char* GetNextWriteLocation(
+ QuicPacketBuffer GetNextWriteLocation(
const QuicIpAddress& /*self_address*/,
const QuicSocketAddress& /*peer_address*/) override {
- return nullptr;
+ return {nullptr, nullptr};
}
WriteResult Flush() override { return WriteResult(WRITE_STATUS_OK, 0); }
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/mock_clock.cc b/chromium/net/third_party/quiche/src/quic/test_tools/mock_clock.cc
index 1761dd9af32..21c080a3c4c 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/mock_clock.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/mock_clock.cc
@@ -14,6 +14,10 @@ void MockClock::AdvanceTime(QuicTime::Delta delta) {
now_ = now_ + delta;
}
+void MockClock::Reset() {
+ now_ = QuicTime::Zero();
+}
+
QuicTime MockClock::Now() const {
return now_;
}
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/mock_clock.h b/chromium/net/third_party/quiche/src/quic/test_tools/mock_clock.h
index 4bd51e9d6d6..2ce2e966a9c 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/mock_clock.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/mock_clock.h
@@ -24,6 +24,8 @@ class MockClock : public QuicClock {
// Advances the current time by |delta|, which may be negative.
void AdvanceTime(QuicTime::Delta delta);
+ // Resets time back to zero.
+ void Reset();
private:
QuicTime now_;
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.h b/chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.h
index 75b9a5dcb30..f066e9191e4 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.h
@@ -54,12 +54,12 @@ class PacketDroppingTestWriter : public QuicPacketWriterWrapper {
void SetWritable() override;
- char* GetNextWriteLocation(
+ QuicPacketBuffer GetNextWriteLocation(
const QuicIpAddress& /*self_address*/,
const QuicSocketAddress& /*peer_address*/) override {
// If the wrapped writer supports zero-copy, disable it, because it is not
// compatible with delayed writes in this class.
- return nullptr;
+ return {nullptr, nullptr};
}
// Writes out any packet which should have been sent by now
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.cc
index 3e752154f27..52325d16650 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.cc
@@ -94,8 +94,8 @@ void QuicConfigPeer::SetReceivedStatelessResetToken(QuicConfig* config,
// static
void QuicConfigPeer::SetReceivedMaxPacketSize(QuicConfig* config,
- uint32_t max_packet_size) {
- config->max_packet_size_.SetReceivedValue(max_packet_size);
+ uint32_t max_udp_payload_size) {
+ config->max_udp_payload_size_.SetReceivedValue(max_udp_payload_size);
}
// static
@@ -106,8 +106,23 @@ void QuicConfigPeer::SetNegotiated(QuicConfig* config, bool negotiated) {
// static
void QuicConfigPeer::SetReceivedOriginalConnectionId(
QuicConfig* config,
- const QuicConnectionId& original_connection_id) {
- config->received_original_connection_id_ = original_connection_id;
+ const QuicConnectionId& original_destination_connection_id) {
+ config->received_original_destination_connection_id_ =
+ original_destination_connection_id;
+}
+
+// static
+void QuicConfigPeer::SetReceivedInitialSourceConnectionId(
+ QuicConfig* config,
+ const QuicConnectionId& initial_source_connection_id) {
+ config->received_initial_source_connection_id_ = initial_source_connection_id;
+}
+
+// static
+void QuicConfigPeer::SetReceivedRetrySourceConnectionId(
+ QuicConfig* config,
+ const QuicConnectionId& retry_source_connection_id) {
+ config->received_retry_source_connection_id_ = retry_source_connection_id;
}
// static
@@ -117,5 +132,10 @@ void QuicConfigPeer::SetReceivedMaxDatagramFrameSize(
config->max_datagram_frame_size_.SetReceivedValue(max_datagram_frame_size);
}
+// static
+void QuicConfigPeer::DisableSupportHandshakeDone(QuicConfig* config) {
+ config->support_handshake_done_.SetSendValue(0);
+}
+
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.h
index c435f2282da..109bd6453b3 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.h
@@ -58,16 +58,25 @@ class QuicConfigPeer {
QuicUint128 token);
static void SetReceivedMaxPacketSize(QuicConfig* config,
- uint32_t max_packet_size);
+ uint32_t max_udp_payload_size);
static void SetNegotiated(QuicConfig* config, bool negotiated);
static void SetReceivedOriginalConnectionId(
QuicConfig* config,
- const QuicConnectionId& original_connection_id);
+ const QuicConnectionId& original_destination_connection_id);
+
+ static void SetReceivedInitialSourceConnectionId(
+ QuicConfig* config,
+ const QuicConnectionId& initial_source_connection_id);
+
+ static void SetReceivedRetrySourceConnectionId(
+ QuicConfig* config,
+ const QuicConnectionId& retry_source_connection_id);
static void SetReceivedMaxDatagramFrameSize(QuicConfig* config,
uint64_t max_datagram_frame_size);
+ static void DisableSupportHandshakeDone(QuicConfig* config);
};
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc
index d276f6327ea..54616b2e407 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc
@@ -377,5 +377,10 @@ void QuicConnectionPeer::SetServerConnectionId(
connection->InstallInitialCrypters(server_connection_id);
}
+// static
+size_t QuicConnectionPeer::NumUndecryptablePackets(QuicConnection* connection) {
+ return connection->undecryptable_packets_.size();
+}
+
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h
index 9882f62ee35..a5b94ef2c53 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h
@@ -147,6 +147,8 @@ class QuicConnectionPeer {
static void SetServerConnectionId(
QuicConnection* connection,
const QuicConnectionId& server_connection_id);
+
+ static size_t NumUndecryptablePackets(QuicConnection* connection);
};
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.cc
new file mode 100644
index 00000000000..3cce97eed80
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.cc
@@ -0,0 +1,22 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.h"
+
+using testing::_;
+using testing::Invoke;
+
+namespace quic {
+namespace test {
+
+MockQuicSyscallWrapper::MockQuicSyscallWrapper(QuicSyscallWrapper* delegate) {
+ ON_CALL(*this, Sendmsg(_, _, _))
+ .WillByDefault(Invoke(delegate, &QuicSyscallWrapper::Sendmsg));
+
+ ON_CALL(*this, Sendmmsg(_, _, _, _))
+ .WillByDefault(Invoke(delegate, &QuicSyscallWrapper::Sendmmsg));
+}
+
+} // namespace test
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.h
new file mode 100644
index 00000000000..8dac5ad00c9
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_PLATFORM_IMPL_QUIC_MOCK_SYSCALL_WRAPPER_H_
+#define QUICHE_QUIC_PLATFORM_IMPL_QUIC_MOCK_SYSCALL_WRAPPER_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_syscall_wrapper.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+
+namespace quic {
+namespace test {
+
+class MockQuicSyscallWrapper : public QuicSyscallWrapper {
+ public:
+ // Create a standard mock object.
+ MockQuicSyscallWrapper() = default;
+
+ // Create a 'mockable' object that delegates everything to |delegate| by
+ // default.
+ explicit MockQuicSyscallWrapper(QuicSyscallWrapper* delegate);
+
+ MOCK_METHOD(ssize_t,
+ Sendmsg,
+ (int sockfd, const msghdr*, int flags),
+ (override));
+
+ MOCK_METHOD(int,
+ Sendmmsg,
+ (int sockfd, mmsghdr*, unsigned int vlen, int flags),
+ (override));
+};
+
+} // namespace test
+} // namespace quic
+
+#endif // QUICHE_QUIC_PLATFORM_IMPL_QUIC_MOCK_SYSCALL_WRAPPER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc
index 44fed8809ec..151575a0db0 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc
@@ -111,7 +111,7 @@ SerializedPacket QuicPacketCreatorPeer::SerializeAllFrames(
bool success = creator->AddFrame(frame, NOT_RETRANSMISSION);
DCHECK(success);
}
- creator->SerializePacket(buffer, buffer_len);
+ creator->SerializePacket(QuicOwnedPacketBuffer(buffer, nullptr), buffer_len);
SerializedPacket packet = std::move(creator->packet_);
// The caller takes ownership of the QuicEncryptedPacket.
creator->packet_.encrypted_buffer = nullptr;
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc
index ab28828cc14..ea9dc062fd1 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc
@@ -242,12 +242,17 @@ size_t QuicSessionPeer::GetNumOpenDynamicStreams(QuicSession* session) {
}
}
// Exclude draining streams.
- result -= session->GetNumDrainingStreams();
+ result -= session->num_draining_streams_;
// Add locally closed streams.
result += session->locally_closed_streams_highest_offset_.size();
return result;
}
+// static
+size_t QuicSessionPeer::GetNumDrainingStreams(QuicSession* session) {
+ return session->num_draining_streams_;
+}
+
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h
index ffb6a46446d..061f16da3a7 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h
@@ -82,6 +82,7 @@ class QuicSessionPeer {
static void set_is_configured(QuicSession* session, bool value);
static void SetPerspective(QuicSession* session, Perspective perspective);
static size_t GetNumOpenDynamicStreams(QuicSession* session);
+ static size_t GetNumDrainingStreams(QuicSession* session);
};
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc
index 22e65b822ee..503f58539b2 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc
@@ -210,6 +210,22 @@ MockableQuicClient::MockableQuicClient(
const ParsedQuicVersionVector& supported_versions,
QuicEpollServer* epoll_server,
std::unique_ptr<ProofVerifier> proof_verifier)
+ : MockableQuicClient(server_address,
+ server_id,
+ config,
+ supported_versions,
+ epoll_server,
+ std::move(proof_verifier),
+ nullptr) {}
+
+MockableQuicClient::MockableQuicClient(
+ QuicSocketAddress server_address,
+ const QuicServerId& server_id,
+ const QuicConfig& config,
+ const ParsedQuicVersionVector& supported_versions,
+ QuicEpollServer* epoll_server,
+ std::unique_ptr<ProofVerifier> proof_verifier,
+ std::unique_ptr<SessionCache> session_cache)
: QuicClient(
server_address,
server_id,
@@ -218,8 +234,8 @@ MockableQuicClient::MockableQuicClient(
epoll_server,
std::make_unique<MockableQuicClientEpollNetworkHelper>(epoll_server,
this),
- QuicWrapUnique(
- new RecordingProofVerifier(std::move(proof_verifier)))),
+ QuicWrapUnique(new RecordingProofVerifier(std::move(proof_verifier))),
+ std::move(session_cache)),
override_server_connection_id_(EmptyQuicConnectionId()),
server_connection_id_overridden_(false),
override_client_connection_id_(EmptyQuicConnectionId()),
@@ -342,6 +358,24 @@ QuicTestClient::QuicTestClient(
Initialize();
}
+QuicTestClient::QuicTestClient(
+ QuicSocketAddress server_address,
+ const std::string& server_hostname,
+ const QuicConfig& config,
+ const ParsedQuicVersionVector& supported_versions,
+ std::unique_ptr<ProofVerifier> proof_verifier,
+ std::unique_ptr<SessionCache> session_cache)
+ : client_(new MockableQuicClient(
+ server_address,
+ QuicServerId(server_hostname, server_address.port(), false),
+ config,
+ supported_versions,
+ &epoll_server_,
+ std::move(proof_verifier),
+ std::move(session_cache))) {
+ Initialize();
+}
+
QuicTestClient::QuicTestClient() = default;
QuicTestClient::~QuicTestClient() {
@@ -390,13 +424,8 @@ ssize_t QuicTestClient::SendRequestAndRstTogether(const std::string& uri) {
QuicStreamId stream_id = GetNthClientInitiatedBidirectionalStreamId(
session->transport_version(), 0);
QuicStream* stream = session->GetOrCreateStream(stream_id);
- if (session->break_close_loop()) {
- session->ResetStream(stream_id, QUIC_STREAM_CANCELLED,
- stream->stream_bytes_written());
- } else {
- session->SendRstStream(stream_id, QUIC_STREAM_CANCELLED,
- stream->stream_bytes_written());
- }
+ session->ResetStream(stream_id, QUIC_STREAM_CANCELLED,
+ stream->stream_bytes_written());
return ret;
}
@@ -962,7 +991,7 @@ void QuicTestClient::WaitForDelayedAcks() {
const QuicClock* clock = client()->client_session()->connection()->clock();
QuicTime wait_until = clock->ApproximateNow() + kWaitDuration;
- while (clock->ApproximateNow() < wait_until) {
+ while (connected() && clock->ApproximateNow() < wait_until) {
// This waits for up to 50 ms.
client()->WaitForEvents();
}
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.h
index f74974f4231..41e30b13dbb 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.h
@@ -49,6 +49,14 @@ class MockableQuicClient : public QuicClient {
const ParsedQuicVersionVector& supported_versions,
QuicEpollServer* epoll_server,
std::unique_ptr<ProofVerifier> proof_verifier);
+
+ MockableQuicClient(QuicSocketAddress server_address,
+ const QuicServerId& server_id,
+ const QuicConfig& config,
+ const ParsedQuicVersionVector& supported_versions,
+ QuicEpollServer* epoll_server,
+ std::unique_ptr<ProofVerifier> proof_verifier,
+ std::unique_ptr<SessionCache> session_cache);
MockableQuicClient(const MockableQuicClient&) = delete;
MockableQuicClient& operator=(const MockableQuicClient&) = delete;
@@ -100,6 +108,12 @@ class QuicTestClient : public QuicSpdyStream::Visitor,
const QuicConfig& config,
const ParsedQuicVersionVector& supported_versions,
std::unique_ptr<ProofVerifier> proof_verifier);
+ QuicTestClient(QuicSocketAddress server_address,
+ const std::string& server_hostname,
+ const QuicConfig& config,
+ const ParsedQuicVersionVector& supported_versions,
+ std::unique_ptr<ProofVerifier> proof_verifier,
+ std::unique_ptr<SessionCache> session_cache);
~QuicTestClient() override;
@@ -188,9 +202,10 @@ class QuicTestClient : public QuicSpdyStream::Visitor,
void WaitForInitialResponse() { WaitForInitialResponseForMs(-1); }
// Returns once at least one complete response or a connection close has been
- // received from the server, or once the timeout expires. -1 means no timeout.
- // If responses are received for multiple (say 2) streams, next
- // WaitForResponseForMs will return immediately.
+ // received from the server, or once the timeout expires.
+ // Passing in a timeout value of -1 disables the timeout. If multiple
+ // responses are received while the client is waiting, subsequent calls to
+ // this function will return immediately.
void WaitForResponseForMs(int timeout_ms) {
WaitUntil(timeout_ms, [this]() { return !closed_stream_states_.empty(); });
if (response_complete()) {
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc
index 7d88ccdaae7..41fb995e5e3 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc
@@ -419,6 +419,11 @@ bool NoOpFramerVisitor::OnHandshakeDoneFrame(
return true;
}
+bool NoOpFramerVisitor::OnAckFrequencyFrame(
+ const QuicAckFrequencyFrame& /*frame*/) {
+ return true;
+}
+
bool NoOpFramerVisitor::IsValidStatelessResetToken(
QuicUint128 /*token*/) const {
return false;
@@ -566,6 +571,7 @@ void PacketSavingConnection::SendOrQueuePacket(SerializedPacket packet) {
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
// Transfer ownership of the packet to the SentPacketManager and the
// ack notifier to the AckNotifierManager.
+ OnPacketSent(packet.encryption_level, packet.transmission_type);
QuicConnectionPeer::GetSentPacketManager(this)->OnPacketSent(
&packet, clock_.ApproximateNow(), NOT_RETRANSMISSION,
HAS_RETRANSMITTABLE_DATA);
@@ -755,8 +761,8 @@ TestQuicSpdyClientSession::TestQuicSpdyClientSession(
&push_promise_index_,
config,
supported_versions) {
- // TODO(b/153726130): Consider adding OnApplicationState calls in tests and
- // set |has_application_state| to true.
+ // TODO(b/153726130): Consider adding SetServerApplicationStateForResumption
+ // calls in tests and set |has_application_state| to true.
crypto_stream_ = std::make_unique<QuicCryptoClientStream>(
server_id, this, crypto_test_utils::ProofVerifyContextForTesting(),
crypto_config, this, /*has_application_state = */ false);
@@ -799,7 +805,7 @@ MockPacketWriter::MockPacketWriter() {
.WillByDefault(testing::Return(kMaxOutgoingPacketSize));
ON_CALL(*this, IsBatchMode()).WillByDefault(testing::Return(false));
ON_CALL(*this, GetNextWriteLocation(_, _))
- .WillByDefault(testing::Return(nullptr));
+ .WillByDefault(testing::Return(QuicPacketBuffer()));
ON_CALL(*this, Flush())
.WillByDefault(testing::Return(WriteResult(WRITE_STATUS_OK, 0)));
ON_CALL(*this, SupportsReleaseTime()).WillByDefault(testing::Return(false));
@@ -841,9 +847,9 @@ ParsedQuicVersion QuicVersionMin() {
}
void DisableQuicVersionsWithTls() {
- SetQuicReloadableFlag(quic_enable_version_draft_27, false);
- SetQuicReloadableFlag(quic_enable_version_draft_25_v3, false);
- SetQuicReloadableFlag(quic_enable_version_t050_v2, false);
+ for (const ParsedQuicVersion& version : AllSupportedVersionsWithTls()) {
+ QuicDisableVersion(version);
+ }
}
QuicEncryptedPacket* ConstructEncryptedPacket(
@@ -1255,12 +1261,12 @@ QuicStreamId GetNthClientInitiatedUnidirectionalStreamId(
}
StreamType DetermineStreamType(QuicStreamId id,
- QuicTransportVersion version,
+ ParsedQuicVersion version,
Perspective perspective,
bool is_incoming,
StreamType default_type) {
- return VersionHasIetfQuicFrames(version)
- ? QuicUtils::GetStreamType(id, perspective, is_incoming)
+ return version.HasIetfQuicFrames()
+ ? QuicUtils::GetStreamType(id, perspective, is_incoming, version)
: default_type;
}
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h
index 7d1d9db4459..2af8aeb3224 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h
@@ -15,6 +15,7 @@
#include "net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h"
#include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h"
+#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h"
#include "net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index.h"
#include "net/third_party/quiche/src/quic/core/http/quic_server_session_base.h"
#include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h"
@@ -395,6 +396,10 @@ class MockFramerVisitor : public QuicFramerVisitorInterface {
OnHandshakeDoneFrame,
(const QuicHandshakeDoneFrame& frame),
(override));
+ MOCK_METHOD(bool,
+ OnAckFrequencyFrame,
+ (const QuicAckFrequencyFrame& frame),
+ (override));
MOCK_METHOD(void, OnPacketComplete, (), (override));
MOCK_METHOD(bool,
IsValidStatelessResetToken,
@@ -459,6 +464,7 @@ class NoOpFramerVisitor : public QuicFramerVisitorInterface {
bool OnBlockedFrame(const QuicBlockedFrame& frame) override;
bool OnMessageFrame(const QuicMessageFrame& frame) override;
bool OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& frame) override;
+ bool OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame) override;
void OnPacketComplete() override {}
bool IsValidStatelessResetToken(QuicUint128 token) const override;
void OnAuthenticatedIetfStatelessResetPacket(
@@ -498,14 +504,18 @@ class MockQuicConnectionVisitor : public QuicConnectionVisitorInterface {
MOCK_METHOD(void, OnWriteBlocked, (), (override));
MOCK_METHOD(void, OnCanWrite, (), (override));
MOCK_METHOD(bool, SendProbingData, (), (override));
+ MOCK_METHOD(bool,
+ ValidateStatelessReset,
+ (const quic::QuicSocketAddress&, const quic::QuicSocketAddress&),
+ (override));
MOCK_METHOD(void, OnCongestionWindowChange, (QuicTime now), (override));
MOCK_METHOD(void,
OnConnectionMigration,
(AddressChangeType type),
(override));
MOCK_METHOD(void, OnPathDegrading, (), (override));
+ MOCK_METHOD(void, OnForwardProgressMadeAfterPathDegrading, (), (override));
MOCK_METHOD(bool, WillingAndAbleToWrite, (), (const, override));
- MOCK_METHOD(bool, HasPendingHandshake, (), (const, override));
MOCK_METHOD(bool, ShouldKeepConnectionAlive, (), (const, override));
MOCK_METHOD(void,
OnSuccessfulVersionNegotiation,
@@ -521,7 +531,6 @@ class MockQuicConnectionVisitor : public QuicConnectionVisitorInterface {
MOCK_METHOD(void, SendPing, (), (override));
MOCK_METHOD(bool, AllowSelfAddressChange, (), (const, override));
MOCK_METHOD(HandshakeState, GetHandshakeState, (), (const, override));
- MOCK_METHOD(void, OnForwardProgressConfirmed, (), (override));
MOCK_METHOD(bool,
OnMaxStreamsFrame,
(const QuicMaxStreamsFrame& frame),
@@ -672,6 +681,8 @@ class MockQuicConnection : public QuicConnection {
QuicConnection::OnError(framer);
}
+ void ReallyOnCanWrite() { QuicConnection::OnCanWrite(); }
+
void ReallyCloseConnection(
QuicErrorCode error,
const std::string& details,
@@ -738,6 +749,8 @@ class PacketSavingConnection : public MockQuicConnection {
void SendOrQueuePacket(SerializedPacket packet) override;
+ MOCK_METHOD(void, OnPacketSent, (EncryptionLevel, TransmissionType));
+
std::vector<std::unique_ptr<QuicEncryptedPacket>> encrypted_packets_;
MockClock clock_;
};
@@ -797,7 +810,6 @@ class MockQuicSession : public QuicSession {
MOCK_METHOD(void, OnAlpnSelected, (quiche::QuicheStringPiece), (override));
using QuicSession::ActivateStream;
- using QuicSession::GetNumDrainingStreams;
// Returns a QuicConsumedData that indicates all of |write_length| (and |fin|
// if set) has been consumed.
@@ -834,6 +846,8 @@ class MockQuicCryptoStream : public QuicCryptoStream {
void OnHandshakePacketSent() override {}
void OnHandshakeDoneReceived() override {}
HandshakeState GetHandshakeState() const override { return HANDSHAKE_START; }
+ void SetServerApplicationStateForResumption(
+ std::unique_ptr<ApplicationState> /*application_state*/) override {}
private:
QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;
@@ -1182,7 +1196,7 @@ class MockPacketWriter : public QuicPacketWriter {
(const, override));
MOCK_METHOD(bool, SupportsReleaseTime, (), (const, override));
MOCK_METHOD(bool, IsBatchMode, (), (const, override));
- MOCK_METHOD(char*,
+ MOCK_METHOD(QuicPacketBuffer,
GetNextWriteLocation,
(const QuicIpAddress& self_address,
const QuicSocketAddress& peer_address),
@@ -1285,6 +1299,7 @@ class MockLossAlgorithm : public LossDetectionInterface {
MOCK_METHOD(void, OnConfigNegotiated, (), (override));
MOCK_METHOD(void, OnMinRttAvailable, (), (override));
+ MOCK_METHOD(void, OnUserAgentIdKnown, (), (override));
MOCK_METHOD(void, OnConnectionClosed, (), (override));
};
@@ -1415,6 +1430,16 @@ class MockQuicConnectionDebugVisitor : public QuicConnectionDebugVisitor {
OnVersionNegotiationPacket,
(const QuicVersionNegotiationPacket&),
(override));
+
+ MOCK_METHOD(void,
+ OnTransportParametersSent,
+ (const TransportParameters&),
+ (override));
+
+ MOCK_METHOD(void,
+ OnTransportParametersReceived,
+ (const TransportParameters&),
+ (override));
};
class MockReceivedPacketManager : public QuicReceivedPacketManager {
@@ -1443,7 +1468,7 @@ class MockPacketCreatorDelegate : public QuicPacketCreator::DelegateInterface {
delete;
~MockPacketCreatorDelegate() override;
- MOCK_METHOD(char*, GetPacketBuffer, (), (override));
+ MOCK_METHOD(QuicPacketBuffer, GetPacketBuffer, (), (override));
MOCK_METHOD(void, OnSerializedPacket, (SerializedPacket), (override));
MOCK_METHOD(void,
OnUnrecoverableError,
@@ -1600,7 +1625,7 @@ QuicStreamId GetNthClientInitiatedUnidirectionalStreamId(
int n);
StreamType DetermineStreamType(QuicStreamId id,
- QuicTransportVersion version,
+ ParsedQuicVersion version,
Perspective perspective,
bool is_incoming,
StreamType default_type);
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc
index 3d2652fa7ed..8ec56dc9ed8 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc
@@ -204,6 +204,11 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface {
return true;
}
+ bool OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame) override {
+ ack_frequency_frames_.push_back(frame);
+ return true;
+ }
+
void OnPacketComplete() override {}
bool IsValidStatelessResetToken(QuicUint128 /*token*/) const override {
@@ -295,6 +300,7 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface {
std::vector<QuicNewTokenFrame> new_token_frames_;
std::vector<QuicMessageFrame> message_frames_;
std::vector<QuicHandshakeDoneFrame> handshake_done_frames_;
+ std::vector<QuicAckFrequencyFrame> ack_frequency_frames_;
std::vector<std::unique_ptr<std::string>> stream_data_;
std::vector<std::unique_ptr<std::string>> crypto_data_;
EncryptionLevel last_decrypted_level_;
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.cc
index 6a0cafb4177..94b8764a7bf 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.cc
@@ -34,6 +34,12 @@ std::unique_ptr<QuicResumptionState> SimpleSessionCache::Lookup(
if (it == cache_entries_.end()) {
return nullptr;
}
+
+ if (!it->second.session) {
+ cache_entries_.erase(it);
+ return nullptr;
+ }
+
auto state = std::make_unique<QuicResumptionState>();
state->tls_session = std::move(it->second.session);
state->application_state = it->second.application_state.get();
@@ -41,5 +47,10 @@ std::unique_ptr<QuicResumptionState> SimpleSessionCache::Lookup(
return state;
}
+void SimpleSessionCache::ClearEarlyData(const QuicServerId& /*server_id*/) {
+ // The simple session cache only stores 1 SSL ticket per entry, so no need to
+ // do anything here.
+}
+
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.h b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.h
index cfe3f4a5454..6043a439e4d 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.h
@@ -28,6 +28,7 @@ class SimpleSessionCache : public SessionCache {
const ApplicationState* application_state) override;
std::unique_ptr<QuicResumptionState> Lookup(const QuicServerId& server_id,
const SSL_CTX* ctx) override;
+ void ClearEarlyData(const QuicServerId& server_id) override;
private:
struct Entry {
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h
index 1237f424499..65afacebf3c 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h
@@ -78,6 +78,7 @@ class SimpleSessionNotifier : public SessionNotifierInterface {
bool IsFrameOutstanding(const QuicFrame& frame) const override;
bool HasUnackedCryptoData() const override;
bool HasUnackedStreamData() const override;
+ bool HasLostStreamData() const;
private:
struct StreamState {
@@ -124,8 +125,6 @@ class SimpleSessionNotifier : public SessionNotifierInterface {
bool HasBufferedControlFrames() const;
- bool HasLostStreamData() const;
-
bool StreamHasBufferedData(QuicStreamId id) const;
QuicCircularDeque<QuicFrame> control_frames_;
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/queue.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/queue.cc
index 3816fd4b0c0..52f7fe683b7 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/queue.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/queue.cc
@@ -20,6 +20,7 @@ Queue::Queue(Simulator* simulator, std::string name, QuicByteCount capacity)
aggregation_timeout_(QuicTime::Delta::Infinite()),
current_bundle_(0),
current_bundle_bytes_(0),
+ tx_port_(nullptr),
listener_(nullptr) {
aggregation_timeout_alarm_.reset(simulator_->GetAlarmFactory()->CreateAlarm(
new AggregationAlarmDelegate(this)));
@@ -116,7 +117,12 @@ void Queue::ScheduleNextPacketDequeue() {
return;
}
- Schedule(clock_->Now() + tx_port_->TimeUntilAvailable());
+ QuicTime::Delta time_until_available = QuicTime::Delta::Zero();
+ if (tx_port_) {
+ time_until_available = tx_port_->TimeUntilAvailable();
+ }
+
+ Schedule(clock_->Now() + time_until_available);
}
} // namespace simulator
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.cc
index c908f982abd..aba7b46a649 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.cc
@@ -11,6 +11,7 @@
#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test_output.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h"
@@ -55,6 +56,7 @@ QuicEndpoint::QuicEndpoint(Simulator* simulator,
// Skip version negotiation.
test::QuicConnectionPeer::SetNegotiatedVersion(connection_.get());
}
+ test::QuicConnectionPeer::SetAddressValidated(connection_.get());
connection_->SetDataProducer(&producer_);
connection_->SetSessionNotifier(this);
notifier_ = std::make_unique<test::SimpleSessionNotifier>(connection_.get());
@@ -74,6 +76,17 @@ QuicEndpoint::QuicEndpoint(Simulator* simulator,
peer_hello, perspective == Perspective::IS_CLIENT ? SERVER : CLIENT,
&error);
DCHECK_EQ(error_code, QUIC_NO_ERROR) << "Configuration failed: " << error;
+ if (connection_->version().AuthenticatesHandshakeConnectionIds()) {
+ if (connection_->perspective() == Perspective::IS_CLIENT) {
+ test::QuicConfigPeer::SetReceivedOriginalConnectionId(
+ &config, connection_->connection_id());
+ test::QuicConfigPeer::SetReceivedInitialSourceConnectionId(
+ &config, connection_->connection_id());
+ } else {
+ test::QuicConfigPeer::SetReceivedInitialSourceConnectionId(
+ &config, connection_->client_connection_id());
+ }
+ }
connection_->SetFromConfig(config);
}
@@ -153,9 +166,6 @@ bool QuicEndpoint::WillingAndAbleToWrite() const {
}
return bytes_to_transfer_ != 0;
}
-bool QuicEndpoint::HasPendingHandshake() const {
- return false;
-}
bool QuicEndpoint::ShouldKeepConnectionAlive() const {
return true;
}
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h
index 8b9fd1f480d..cb3c38644f7 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h
@@ -51,8 +51,12 @@ class QuicEndpoint : public QuicEndpointBase,
void OnCryptoFrame(const QuicCryptoFrame& frame) override;
void OnCanWrite() override;
bool SendProbingData() override;
+ bool ValidateStatelessReset(
+ const quic::QuicSocketAddress& /*self_address*/,
+ const quic::QuicSocketAddress& /*peer_address*/) override {
+ return true;
+ }
bool WillingAndAbleToWrite() const override;
- bool HasPendingHandshake() const override;
bool ShouldKeepConnectionAlive() const override;
void OnWindowUpdateFrame(const QuicWindowUpdateFrame& /*frame*/) override {}
@@ -72,11 +76,11 @@ class QuicEndpoint : public QuicEndpointBase,
void OnCongestionWindowChange(QuicTime /*now*/) override {}
void OnConnectionMigration(AddressChangeType /*type*/) override {}
void OnPathDegrading() override {}
+ void OnForwardProgressMadeAfterPathDegrading() override {}
void OnAckNeedsRetransmittableFrame() override {}
void SendPing() override {}
bool AllowSelfAddressChange() const override;
HandshakeState GetHandshakeState() const override;
- void OnForwardProgressConfirmed() override {}
bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& /*frame*/) override {
return true;
}
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.cc
index 21815d8fe31..c05740d6f00 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.cc
@@ -178,10 +178,10 @@ bool QuicEndpointBase::Writer::IsBatchMode() const {
return false;
}
-char* QuicEndpointBase::Writer::GetNextWriteLocation(
+QuicPacketBuffer QuicEndpointBase::Writer::GetNextWriteLocation(
const QuicIpAddress& /*self_address*/,
const QuicSocketAddress& /*peer_address*/) {
- return nullptr;
+ return {nullptr, nullptr};
}
WriteResult QuicEndpointBase::Writer::Flush() {
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h
index f4fe33be429..c9be24eb089 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h
@@ -87,8 +87,9 @@ class QuicEndpointBase : public Endpoint,
const QuicSocketAddress& peer_address) const override;
bool SupportsReleaseTime() const override;
bool IsBatchMode() const override;
- char* GetNextWriteLocation(const QuicIpAddress& self_address,
- const QuicSocketAddress& peer_address) override;
+ QuicPacketBuffer GetNextWriteLocation(
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address) override;
WriteResult Flush() override;
private:
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.cc b/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.cc
index 2a733b43ae9..d179d006329 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.cc
@@ -249,6 +249,34 @@ hTXMooR/wD7an6gtnXD8ixCh7bP0TyPiBhNsUb12WrvSEAm/UyciQbQlR7P+K0Z7
Cmn1Mj4hQ+pT0t+pw/DMOw==
-----END CERTIFICATE-----)";
+QUIC_CONST_INIT const char kTestCertWithUnknownSanTypePem[] =
+ R"(-----BEGIN CERTIFICATE-----
+MIIEYTCCA0mgAwIBAgIJAILStmLgUUcVMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNp
+c2NvMQ0wCwYDVQQKDARMeWZ0MRkwFwYDVQQLDBBMeWZ0IEVuZ2luZWVyaW5nMRAw
+DgYDVQQDDAdUZXN0IENBMB4XDTE4MTIxNzIwMTgwMFoXDTIwMTIxNjIwMTgwMFow
+gaYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1T
+YW4gRnJhbmNpc2NvMQ0wCwYDVQQKDARMeWZ0MRkwFwYDVQQLDBBMeWZ0IEVuZ2lu
+ZWVyaW5nMRowGAYDVQQDDBFUZXN0IEJhY2tlbmQgVGVhbTEkMCIGCSqGSIb3DQEJ
+ARYVYmFja2VuZC10ZWFtQGx5ZnQuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAuvPdQdmwZongPAgQho/Vipd3PZWrQ6BKxIb4l/RvqtVP321IUTLs
+4vVwpXoYJ+12L+XOO3jCInszs53tHjFpTI1GE8/sasmgR6LRr2krwSoVRHPqUoc9
+tzkDG1SzKP2TRTi1MTI3FO+TnLFahntO9Zstxhv1Epz5GZ/xQLE0/LLoRYzcynL/
+iflk18iL1KM8i0Hy4cKjclOaUdnh2nh753iJfxCSb5wJfx4FH1qverYHHT6FopYR
+V40Cg0yYXcYo8yNwrg+EBY8QAT2JOMDokXNKbZpmVKiBlh0QYMX6BBiW249v3sYl
+3Ve+fZvCkle3W0xP0xJw8PdX0NRbvGOrBQIDAQABo4HAMIG9MAwGA1UdEwEB/wQC
+MAAwCwYDVR0PBAQDAgXgMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATBB
+BgNVHREEOjA4hh5zcGlmZmU6Ly9seWZ0LmNvbS9iYWNrZW5kLXRlYW2CCGx5ZnQu
+Y29tggx3d3cubHlmdC5jb20wHQYDVR0OBBYEFLHmMm0DV9jCHJSWVRwyPYpBw62r
+MB8GA1UdIwQYMBaAFBQz1vaSbPuePL++7GTMqLAMtk3kMA0GCSqGSIb3DQEBCwUA
+A4IBAQAwx3/M2o00W8GlQ3OT4y/hQGb5K2aytxx8QeSmJaaZTJbvaHhe0x3/fLgq
+uWrW3WEWFtwasilySjOrFOtB9UNmJmNOHSJD3Bslbv5htRaWnoFPCXdwZtVMdoTq
+IHIQqLoos/xj3kVD5sJSYySrveMeKaeUILTkb5ZubSivye1X2yiJLR7AtuwuiMio
+CdIOqhn6xJqYhT7z0IhdKpLNPk4w1tBZSKOXqzrXS4uoJgTC67hWslWWZ2VC6IvZ
+FmKuuGZamCCj6F1QF2IjMVM8evl84hEnN0ajdkA/QWnil9kcWvBm15Ho+oTvvJ7s
+M8MD3RDSq/90FSiME4vbyNEyTmj0
+-----END CERTIFICATE-----)";
+
QUIC_CONST_INIT const char kTestCertificatePrivateKeyRaw[] = {
'\x30', '\x82', '\x04', '\xbc', '\x02', '\x01', '\x00', '\x30', '\x0d',
'\x06', '\x09', '\x2a', '\x86', '\x48', '\x86', '\xf7', '\x0d', '\x01',
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.h b/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.h
index ec4a4d407d5..e7d3035a610 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.h
@@ -20,6 +20,10 @@ QUIC_CONST_INIT extern const char kTestCertificatePem[];
// |kTestCertificatePem| with a PEM-encoded root appended to the end.
QUIC_CONST_INIT extern const char kTestCertificateChainPem[];
+// PEM-encoded certificate that contains a subjectAltName with an
+// unknown/unsupported type.
+QUIC_CONST_INIT extern const char kTestCertWithUnknownSanTypePem[];
+
// DER-encoded private key for |kTestCertificate|.
QUIC_CONST_INIT extern const quiche::QuicheStringPiece
kTestCertificatePrivateKey;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc
index 11edb195a9d..82b549faeef 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc
@@ -235,7 +235,7 @@ void QuicClientBase::WaitForStreamToClose(QuicStreamId id) {
}
}
-bool QuicClientBase::WaitForCryptoHandshakeConfirmed() {
+bool QuicClientBase::WaitForOneRttKeysAvailable() {
DCHECK(connected());
while (connected() && !session_->OneRttKeysAvailable()) {
@@ -247,6 +247,19 @@ bool QuicClientBase::WaitForCryptoHandshakeConfirmed() {
return connected();
}
+bool QuicClientBase::WaitForHandshakeConfirmed() {
+ if (!session_->connection()->version().HasHandshakeDone()) {
+ return WaitForOneRttKeysAvailable();
+ }
+ while (connected() && session_->GetHandshakeState() < HANDSHAKE_CONFIRMED) {
+ WaitForEvents();
+ }
+
+ // If the handshake fails due to a timeout, the connection will be closed.
+ QUIC_LOG_IF(ERROR, !connected()) << "Handshake with server failed.";
+ return connected();
+}
+
bool QuicClientBase::connected() const {
return session_.get() && session_->connection() &&
session_->connection()->connected();
@@ -290,21 +303,7 @@ QuicErrorCode QuicClientBase::connection_error() const {
}
QuicConnectionId QuicClientBase::GetNextConnectionId() {
- QuicConnectionId server_designated_id = GetNextServerDesignatedConnectionId();
- return !server_designated_id.IsEmpty() ? server_designated_id
- : GenerateNewConnectionId();
-}
-
-QuicConnectionId QuicClientBase::GetNextServerDesignatedConnectionId() {
- QuicCryptoClientConfig::CachedState* cached =
- crypto_config_.LookupOrCreate(server_id_);
- // If the cached state indicates that we should use a server-designated
- // connection ID, then return that connection ID.
- CHECK(cached != nullptr) << "QuicClientCryptoConfig::LookupOrCreate returned "
- << "unexpected nullptr.";
- return cached->has_server_designated_connection_id()
- ? cached->GetNextServerDesignatedConnectionId()
- : EmptyQuicConnectionId();
+ return GenerateNewConnectionId();
}
QuicConnectionId QuicClientBase::GenerateNewConnectionId() {
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h
index 0a40b82d64a..842afc6f14c 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h
@@ -102,9 +102,14 @@ class QuicClientBase {
// Wait for events until the stream with the given ID is closed.
void WaitForStreamToClose(QuicStreamId id);
- // Wait for events until the handshake is confirmed.
- // Returns true if the crypto handshake succeeds, false otherwise.
- QUIC_MUST_USE_RESULT bool WaitForCryptoHandshakeConfirmed();
+ // Wait for 1-RTT keys become available.
+ // Returns true once 1-RTT keys are available, false otherwise.
+ QUIC_MUST_USE_RESULT bool WaitForOneRttKeysAvailable();
+
+ // Wait for handshake state proceeds to HANDSHAKE_CONFIRMED.
+ // In QUIC crypto, this does the same as WaitForOneRttKeysAvailable, while in
+ // TLS, this waits for HANDSHAKE_DONE frame is received.
+ QUIC_MUST_USE_RESULT bool WaitForHandshakeConfirmed();
// Wait up to 50ms, and handle any events which occur.
// Returns true if there are any outstanding requests.
@@ -271,10 +276,6 @@ class QuicClientBase {
// returned. Otherwise, the next random ID will be returned.
QuicConnectionId GetNextConnectionId();
- // Returns the next server-designated ConnectionId from the cached config for
- // |server_id_|, if it exists. Otherwise, returns 0.
- QuicConnectionId GetNextServerDesignatedConnectionId();
-
// Generates a new, random connection ID (as opposed to a server-designated
// connection ID).
virtual QuicConnectionId GenerateNewConnectionId();
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc
index 803e313ea24..e6b9e73d473 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc
@@ -41,8 +41,13 @@ enum class Feature {
kConnectionClose,
// The connection was established using TLS resumption.
kResumption,
+ // 0-RTT data is being sent and acted on.
+ kZeroRtt,
// A RETRY packet was successfully processed.
kRetry,
+ // A handshake using a ClientHello that spans multiple packets completed
+ // successfully.
+ kQuantum,
// Second row of features (anything else protocol-related)
// We switched to a different port and the server migrated to it.
@@ -68,8 +73,12 @@ char MatrixLetter(Feature f) {
return 'C';
case Feature::kResumption:
return 'R';
+ case Feature::kZeroRtt:
+ return 'Z';
case Feature::kRetry:
return 'S';
+ case Feature::kQuantum:
+ return 'Q';
case Feature::kRebinding:
return 'B';
case Feature::kHttp3:
@@ -90,14 +99,23 @@ class QuicClientInteropRunner : QuicConnectionDebugVisitor {
// Attempts a resumption using |client| by disconnecting and reconnecting. If
// resumption is successful, |features_| is modified to add
// Feature::kResumption to it, otherwise it is left unmodified.
- void AttemptResumption(QuicClient* client);
+ void AttemptResumption(QuicClient* client, const std::string& authority);
void AttemptRequest(QuicSocketAddress addr,
std::string authority,
QuicServerId server_id,
ParsedQuicVersion version,
bool test_version_negotiation,
- bool attempt_rebind);
+ bool attempt_rebind,
+ bool attempt_multi_packet_chlo);
+
+ // Constructs a SpdyHeaderBlock containing the pseudo-headers needed to make a
+ // GET request to "/" on the hostname |authority|.
+ spdy::SpdyHeaderBlock ConstructHeaderBlock(const std::string& authority);
+
+ // Sends an HTTP request represented by |header_block| using |client|.
+ void SendRequest(QuicClient* client,
+ const spdy::SpdyHeaderBlock& header_block);
void OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override {
switch (frame.close_type) {
@@ -134,20 +152,37 @@ class QuicClientInteropRunner : QuicConnectionDebugVisitor {
std::set<Feature> features_;
};
-void QuicClientInteropRunner::AttemptResumption(QuicClient* client) {
+void QuicClientInteropRunner::AttemptResumption(QuicClient* client,
+ const std::string& authority) {
client->Disconnect();
if (!client->Initialize()) {
QUIC_LOG(ERROR) << "Failed to reinitialize client";
return;
}
- if (!client->Connect() || !client->session()->OneRttKeysAvailable()) {
+ if (!client->Connect()) {
+ return;
+ }
+
+ bool zero_rtt_attempt = !client->session()->OneRttKeysAvailable();
+
+ spdy::SpdyHeaderBlock header_block = ConstructHeaderBlock(authority);
+ SendRequest(client, header_block);
+
+ if (!client->session()->OneRttKeysAvailable()) {
return;
}
+
if (static_cast<QuicCryptoClientStream*>(
test::QuicSessionPeer::GetMutableCryptoStream(client->session()))
->IsResumption()) {
InsertFeature(Feature::kResumption);
}
+ if (static_cast<QuicCryptoClientStream*>(
+ test::QuicSessionPeer::GetMutableCryptoStream(client->session()))
+ ->EarlyDataAccepted() &&
+ zero_rtt_attempt && client->latest_response_code() != -1) {
+ InsertFeature(Feature::kZeroRtt);
+ }
}
void QuicClientInteropRunner::AttemptRequest(QuicSocketAddress addr,
@@ -155,7 +190,8 @@ void QuicClientInteropRunner::AttemptRequest(QuicSocketAddress addr,
QuicServerId server_id,
ParsedQuicVersion version,
bool test_version_negotiation,
- bool attempt_rebind) {
+ bool attempt_rebind,
+ bool attempt_multi_packet_chlo) {
ParsedQuicVersionVector versions = {version};
if (test_version_negotiation) {
versions.insert(versions.begin(), QuicVersionReservedForNegotiation());
@@ -168,6 +204,15 @@ void QuicClientInteropRunner::AttemptRequest(QuicSocketAddress addr,
QuicConfig config;
QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(20);
config.SetIdleNetworkTimeout(timeout);
+ if (attempt_multi_packet_chlo) {
+ // Make the ClientHello span multiple packets by adding a custom transport
+ // parameter.
+ constexpr auto kCustomParameter =
+ static_cast<TransportParameters::TransportParameterId>(0x173E);
+ std::string custom_value(2000, '?');
+ config.custom_transport_parameters_to_send()[kCustomParameter] =
+ custom_value;
+ }
auto client = std::make_unique<QuicClient>(
addr, server_id, versions, config, &epoll_server,
std::move(proof_verifier), std::move(session_cache));
@@ -192,34 +237,28 @@ void QuicClientInteropRunner::AttemptRequest(QuicSocketAddress addr,
if (test_version_negotiation && !connect_result) {
// Failed to negotiate version, retry without version negotiation.
AttemptRequest(addr, authority, server_id, version,
- /*test_version_negotiation=*/false, attempt_rebind);
+ /*test_version_negotiation=*/false, attempt_rebind,
+ attempt_multi_packet_chlo);
return;
}
if (!client->session()->OneRttKeysAvailable()) {
+ if (attempt_multi_packet_chlo) {
+ // Failed to handshake with multi-packet client hello, retry without it.
+ AttemptRequest(addr, authority, server_id, version,
+ test_version_negotiation, attempt_rebind,
+ /*attempt_multi_packet_chlo=*/false);
+ return;
+ }
return;
}
InsertFeature(Feature::kHandshake);
-
- // Construct and send a request.
- spdy::SpdyHeaderBlock header_block;
- header_block[":method"] = "GET";
- header_block[":scheme"] = "https";
- header_block[":authority"] = authority;
- header_block[":path"] = "/";
- client->set_store_response(true);
- client->SendRequestAndWaitForResponse(header_block, "", /*fin=*/true);
-
- client_stats = connection->GetStats();
- QuicSentPacketManager* sent_packet_manager =
- test::QuicConnectionPeer::GetSentPacketManager(connection);
- const bool received_forward_secure_ack =
- sent_packet_manager != nullptr &&
- sent_packet_manager->GetLargestAckedPacket(ENCRYPTION_FORWARD_SECURE)
- .IsInitialized();
- if (client_stats.stream_bytes_received > 0 && received_forward_secure_ack) {
- InsertFeature(Feature::kStreamData);
+ if (attempt_multi_packet_chlo) {
+ InsertFeature(Feature::kQuantum);
}
+ spdy::SpdyHeaderBlock header_block = ConstructHeaderBlock(authority);
+ SendRequest(client.get(), header_block);
+
if (!client->connected()) {
return;
}
@@ -238,7 +277,8 @@ void QuicClientInteropRunner::AttemptRequest(QuicSocketAddress addr,
if (!client->connected()) {
// Rebinding does not work, retry without attempting it.
AttemptRequest(addr, authority, server_id, version,
- test_version_negotiation, /*attempt_rebind=*/false);
+ test_version_negotiation, /*attempt_rebind=*/false,
+ attempt_multi_packet_chlo);
return;
}
InsertFeature(Feature::kRebinding);
@@ -259,7 +299,41 @@ void QuicClientInteropRunner::AttemptRequest(QuicSocketAddress addr,
InsertFeature(Feature::kConnectionClose);
}
- AttemptResumption(client.get());
+ AttemptResumption(client.get(), authority);
+}
+
+spdy::SpdyHeaderBlock QuicClientInteropRunner::ConstructHeaderBlock(
+ const std::string& authority) {
+ // Construct and send a request.
+ spdy::SpdyHeaderBlock header_block;
+ header_block[":method"] = "GET";
+ header_block[":scheme"] = "https";
+ header_block[":authority"] = authority;
+ header_block[":path"] = "/";
+ return header_block;
+}
+
+void QuicClientInteropRunner::SendRequest(
+ QuicClient* client,
+ const spdy::SpdyHeaderBlock& header_block) {
+ client->set_store_response(true);
+ client->SendRequestAndWaitForResponse(header_block, "", /*fin=*/true);
+
+ QuicConnection* connection = client->session()->connection();
+ if (connection == nullptr) {
+ QUIC_LOG(ERROR) << "No QuicConnection object";
+ return;
+ }
+ QuicConnectionStats client_stats = connection->GetStats();
+ QuicSentPacketManager* sent_packet_manager =
+ test::QuicConnectionPeer::GetSentPacketManager(connection);
+ const bool received_forward_secure_ack =
+ sent_packet_manager != nullptr &&
+ sent_packet_manager->GetLargestAckedPacket(ENCRYPTION_FORWARD_SECURE)
+ .IsInitialized();
+ if (client_stats.stream_bytes_received > 0 && received_forward_secure_ack) {
+ InsertFeature(Feature::kStreamData);
+ }
}
std::set<Feature> ServerSupport(std::string dns_host,
@@ -293,7 +367,8 @@ std::set<Feature> ServerSupport(std::string dns_host,
runner.AttemptRequest(addr, authority, server_id, version,
/*test_version_negotiation=*/true,
- /*attempt_rebind=*/true);
+ /*attempt_rebind=*/true,
+ /*attempt_multi_packet_chlo=*/true);
return runner.features();
}
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc
index 1751f4173ed..38dc582c1f3 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc
@@ -22,6 +22,7 @@ std::unique_ptr<QuicSpdyClientBase> QuicEpollClientFactory::CreateClient(
std::string host_for_lookup,
uint16_t port,
ParsedQuicVersionVector versions,
+ const QuicConfig& config,
std::unique_ptr<ProofVerifier> verifier) {
QuicSocketAddress addr =
tools::LookupAddress(host_for_lookup, quiche::QuicheStrCat(port));
@@ -30,8 +31,9 @@ std::unique_ptr<QuicSpdyClientBase> QuicEpollClientFactory::CreateClient(
return nullptr;
}
QuicServerId server_id(host_for_handshake, port, false);
- return std::make_unique<QuicClient>(addr, server_id, versions, &epoll_server_,
- std::move(verifier));
+ return std::make_unique<QuicClient>(addr, server_id, versions, config,
+ &epoll_server_, std::move(verifier),
+ nullptr);
}
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h
index 2ee26d9703c..392bd6cc47c 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h
@@ -18,6 +18,7 @@ class QuicEpollClientFactory : public QuicToyClient::ClientFactory {
std::string host_for_lookup,
uint16_t port,
ParsedQuicVersionVector versions,
+ const QuicConfig& config,
std::unique_ptr<ProofVerifier> verifier) override;
private:
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc
index 798b66e418e..3192d303c96 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc
@@ -207,6 +207,10 @@ class QuicPacketPrinter : public QuicFramerVisitorInterface {
std::cerr << "OnHandshakeDoneFrame: " << frame;
return true;
}
+ bool OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame) override {
+ std::cerr << "OnAckFrequencyFrame: " << frame;
+ return true;
+ }
void OnPacketComplete() override { std::cerr << "OnPacketComplete\n"; }
bool IsValidStatelessResetToken(QuicUint128 /*token*/) const override {
std::cerr << "IsValidStatelessResetToken\n";
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc
index f84a248cda8..387b3135d4d 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc
@@ -158,7 +158,7 @@ void QuicSimpleServerSession::HandleRstOnValidNonexistentStream(
// index for it in promised_streams_ can be calculated.
QuicStreamId next_stream_id = next_outgoing_unidirectional_stream_id();
if (VersionHasIetfQuicFrames(transport_version())) {
- DCHECK(!QuicUtils::IsBidirectionalStreamId(frame.stream_id));
+ DCHECK(!QuicUtils::IsBidirectionalStreamId(frame.stream_id, version()));
}
DCHECK_GE(frame.stream_id, next_stream_id);
size_t index = (frame.stream_id - next_stream_id) /
@@ -243,9 +243,9 @@ void QuicSimpleServerSession::OnCanCreateNewOutgoingStream(
}
void QuicSimpleServerSession::MaybeInitializeHttp3UnidirectionalStreams() {
- size_t previous_static_stream_count = num_outgoing_static_streams();
+ size_t previous_static_stream_count = num_static_streams();
QuicSpdySession::MaybeInitializeHttp3UnidirectionalStreams();
- size_t current_static_stream_count = num_outgoing_static_streams();
+ size_t current_static_stream_count = num_static_streams();
DCHECK_GE(current_static_stream_count, previous_static_stream_count);
highest_promised_stream_id_ +=
QuicUtils::StreamIdDelta(transport_version()) *
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc
index 3dfaa1e3d22..5c8408428e7 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc
@@ -18,6 +18,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h"
@@ -239,6 +240,9 @@ class QuicSimpleServerStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
session_.config()->SetInitialSessionFlowControlWindowToSend(
kInitialSessionFlowControlWindowForTest);
session_.Initialize();
+ if (connection_->version().SupportsAntiAmplificationLimit()) {
+ QuicConnectionPeer::SetAddressValidated(connection_);
+ }
stream_ = new StrictMock<TestStream>(
GetNthClientInitiatedBidirectionalStreamId(
connection_->transport_version(), 0),
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.cc
index 3301ef5d014..1e6cc54043a 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.cc
@@ -5,6 +5,7 @@
#include "net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.h"
#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
namespace quic {
@@ -24,20 +25,40 @@ QuicTcpLikeTraceConverter::StreamOffsetSegment::StreamOffsetSegment(
QuicTcpLikeTraceConverter::StreamInfo::StreamInfo() : fin(false) {}
+QuicIntervalSet<uint64_t> QuicTcpLikeTraceConverter::OnCryptoFrameSent(
+ EncryptionLevel level,
+ QuicStreamOffset offset,
+ QuicByteCount data_length) {
+ if (level >= NUM_ENCRYPTION_LEVELS) {
+ QUIC_BUG << "Invalid encryption level";
+ return {};
+ }
+ return OnFrameSent(offset, data_length, /*fin=*/false,
+ &crypto_frames_info_[level]);
+}
+
QuicIntervalSet<uint64_t> QuicTcpLikeTraceConverter::OnStreamFrameSent(
QuicStreamId stream_id,
QuicStreamOffset offset,
QuicByteCount data_length,
bool fin) {
+ return OnFrameSent(
+ offset, data_length, fin,
+ &streams_info_.emplace(stream_id, StreamInfo()).first->second);
+}
+
+QuicIntervalSet<uint64_t> QuicTcpLikeTraceConverter::OnFrameSent(
+ QuicStreamOffset offset,
+ QuicByteCount data_length,
+ bool fin,
+ StreamInfo* info) {
QuicIntervalSet<uint64_t> connection_offsets;
if (fin) {
// Stream fin consumes a connection offset.
++data_length;
}
- StreamInfo* stream_info =
- &streams_info_.emplace(stream_id, StreamInfo()).first->second;
// Get connection offsets of retransmission data in this frame.
- for (const auto& segment : stream_info->segments) {
+ for (const auto& segment : info->segments) {
QuicInterval<QuicStreamOffset> retransmission(offset, offset + data_length);
retransmission.IntersectWith(segment.stream_data);
if (retransmission.Empty()) {
@@ -50,15 +71,13 @@ QuicIntervalSet<uint64_t> QuicTcpLikeTraceConverter::OnStreamFrameSent(
connection_offset + retransmission.Length());
}
- if (stream_info->fin) {
+ if (info->fin) {
return connection_offsets;
}
// Get connection offsets of new data in this frame.
QuicStreamOffset least_unsent_offset =
- stream_info->segments.empty()
- ? 0
- : stream_info->segments.back().stream_data.max();
+ info->segments.empty() ? 0 : info->segments.back().stream_data.max();
if (least_unsent_offset >= offset + data_length) {
return connection_offsets;
}
@@ -68,20 +87,17 @@ QuicIntervalSet<uint64_t> QuicTcpLikeTraceConverter::OnStreamFrameSent(
QuicByteCount new_data_length = offset + data_length - new_data_offset;
connection_offsets.Add(connection_offset_,
connection_offset_ + new_data_length);
- if (!stream_info->segments.empty() &&
- new_data_offset == least_unsent_offset &&
- connection_offset_ ==
- stream_info->segments.back().connection_offset +
- stream_info->segments.back().stream_data.Length()) {
+ if (!info->segments.empty() && new_data_offset == least_unsent_offset &&
+ connection_offset_ == info->segments.back().connection_offset +
+ info->segments.back().stream_data.Length()) {
// Extend the last segment if both stream and connection offsets are
// contiguous.
- stream_info->segments.back().stream_data.SetMax(new_data_offset +
- new_data_length);
+ info->segments.back().stream_data.SetMax(new_data_offset + new_data_length);
} else {
- stream_info->segments.emplace_back(new_data_offset, connection_offset_,
- new_data_length);
+ info->segments.emplace_back(new_data_offset, connection_offset_,
+ new_data_length);
}
- stream_info->fin = fin;
+ info->fin = fin;
connection_offset_ += new_data_length;
return connection_offsets;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.h b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.h
index 46dd7954a25..1380296e0ea 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.h
@@ -37,6 +37,12 @@ class QuicTcpLikeTraceConverter {
~QuicTcpLikeTraceConverter() {}
+ // Called when a crypto frame is sent. Returns the corresponding connection
+ // offsets.
+ QuicIntervalSet<uint64_t> OnCryptoFrameSent(EncryptionLevel level,
+ QuicStreamOffset offset,
+ QuicByteCount data_length);
+
// Called when a stream frame is sent. Returns the corresponding connection
// offsets.
QuicIntervalSet<uint64_t> OnStreamFrameSent(QuicStreamId stream_id,
@@ -59,6 +65,14 @@ class QuicTcpLikeTraceConverter {
bool fin;
};
+ // Called when frame with |offset|, |data_length| and |fin| has been sent.
+ // Update |info| and returns connection offsets.
+ QuicIntervalSet<uint64_t> OnFrameSent(QuicStreamOffset offset,
+ QuicByteCount data_length,
+ bool fin,
+ StreamInfo* info);
+
+ StreamInfo crypto_frames_info_[NUM_ENCRYPTION_LEVELS];
QuicHashMap<QuicStreamId, StreamInfo> streams_info_;
QuicHashMap<QuicControlFrameId, QuicInterval<uint64_t>> control_frames_info_;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter_test.cc
index a6ce81a8dcd..fa751ae885e 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter_test.cc
@@ -98,6 +98,27 @@ TEST(QuicTcpLikeTraceConverterTest, FuzzerTest) {
EXPECT_EQ(expected, converter.OnStreamFrameSent(1, 50, 600, false));
}
+TEST(QuicTcpLikeTraceConverterTest, OnCryptoFrameSent) {
+ QuicTcpLikeTraceConverter converter;
+
+ EXPECT_EQ(QuicIntervalSet<uint64_t>(0, 100),
+ converter.OnCryptoFrameSent(ENCRYPTION_INITIAL, 0, 100));
+ EXPECT_EQ(QuicIntervalSet<uint64_t>(100, 200),
+ converter.OnStreamFrameSent(1, 0, 100, false));
+ EXPECT_EQ(QuicIntervalSet<uint64_t>(200, 300),
+ converter.OnStreamFrameSent(1, 100, 100, false));
+ EXPECT_EQ(QuicIntervalSet<uint64_t>(300, 400),
+ converter.OnCryptoFrameSent(ENCRYPTION_HANDSHAKE, 0, 100));
+ EXPECT_EQ(QuicIntervalSet<uint64_t>(400, 500),
+ converter.OnCryptoFrameSent(ENCRYPTION_HANDSHAKE, 100, 100));
+
+ // Verify crypto frame retransmission works as intended.
+ EXPECT_EQ(QuicIntervalSet<uint64_t>(0, 100),
+ converter.OnCryptoFrameSent(ENCRYPTION_INITIAL, 0, 100));
+ EXPECT_EQ(QuicIntervalSet<uint64_t>(400, 500),
+ converter.OnCryptoFrameSent(ENCRYPTION_HANDSHAKE, 100, 100));
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc
index 0018f0524b7..b42f967caf0 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc
@@ -109,6 +109,20 @@ DEFINE_QUIC_COMMAND_LINE_FLAG(
"versions are offered in the handshake. Also supports wire versions "
"such as Q043 or T099.");
+DEFINE_QUIC_COMMAND_LINE_FLAG(
+ std::string,
+ connection_options,
+ "",
+ "Connection options as ASCII tags separated by commas, "
+ "e.g. \"ABCD,EFGH\"");
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(
+ std::string,
+ client_connection_options,
+ "",
+ "Client connection options as ASCII tags separated by commas, "
+ "e.g. \"ABCD,EFGH\"");
+
DEFINE_QUIC_COMMAND_LINE_FLAG(bool,
quic_ietf_draft,
false,
@@ -232,9 +246,22 @@ int QuicToyClient::SendRequestsAndPrintResponses(
proof_verifier = quic::CreateDefaultProofVerifier(url.host());
}
+ QuicConfig config;
+ std::string connection_options_string = GetQuicFlag(FLAGS_connection_options);
+ if (!connection_options_string.empty()) {
+ config.SetConnectionOptionsToSend(
+ ParseQuicTagVector(connection_options_string));
+ }
+ std::string client_connection_options_string =
+ GetQuicFlag(FLAGS_client_connection_options);
+ if (!client_connection_options_string.empty()) {
+ config.SetClientConnectionOptions(
+ ParseQuicTagVector(client_connection_options_string));
+ }
+
// Build the client, and try to connect.
std::unique_ptr<QuicSpdyClientBase> client = client_factory_->CreateClient(
- url.host(), host, port, versions, std::move(proof_verifier));
+ url.host(), host, port, versions, config, std::move(proof_verifier));
if (client == nullptr) {
std::cerr << "Failed to create client." << std::endl;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h
index 1a201225a58..d9d8ecaf87a 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h
@@ -26,6 +26,7 @@ class QuicToyClient {
std::string host_for_lookup,
uint16_t port,
ParsedQuicVersionVector versions,
+ const QuicConfig& config,
std::unique_ptr<ProofVerifier> verifier) = 0;
};
diff --git a/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler.h b/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler.h
index a2c69890459..7b318911007 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler.h
+++ b/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler.h
@@ -29,6 +29,8 @@ class FifoWriteScheduler : public WriteScheduler<StreamIdType> {
const StreamPrecedenceType& precedence) override;
void UnregisterStream(StreamIdType stream_id) override;
bool StreamRegistered(StreamIdType stream_id) const override;
+ // Stream precedence is available but note that it is not used for scheduling
+ // in this scheduler.
StreamPrecedenceType GetStreamPrecedence(
StreamIdType stream_id) const override;
void UpdateStreamPrecedence(StreamIdType stream_id,
@@ -51,20 +53,26 @@ class FifoWriteScheduler : public WriteScheduler<StreamIdType> {
std::string DebugString() const override;
private:
+ struct StreamInfo {
+ SpdyPriority priority;
+ int64_t event_time; // read/write event time (us since Unix epoch).
+ };
+
std::set<StreamIdType> ready_streams_;
- // This map maps stream ID to read/write event time (us since Unix epoch).
- std::map<StreamIdType, int64_t> registered_streams_;
+ std::map<StreamIdType, StreamInfo> registered_streams_;
};
template <typename StreamIdType>
void FifoWriteScheduler<StreamIdType>::RegisterStream(
StreamIdType stream_id,
- const StreamPrecedenceType& /*precedence*/) {
+ const StreamPrecedenceType& precedence) {
if (StreamRegistered(stream_id)) {
SPDY_BUG << "Stream " << stream_id << " already registered";
return;
}
- registered_streams_.emplace_hint(registered_streams_.end(), stream_id, 0);
+ registered_streams_.emplace_hint(
+ registered_streams_.end(), stream_id,
+ StreamInfo{/*priority=*/precedence.spdy3_priority(), /*event_time=*/0});
}
template <typename StreamIdType>
@@ -88,14 +96,26 @@ bool FifoWriteScheduler<StreamIdType>::StreamRegistered(
template <typename StreamIdType>
typename FifoWriteScheduler<StreamIdType>::StreamPrecedenceType
FifoWriteScheduler<StreamIdType>::GetStreamPrecedence(
- StreamIdType /*stream_id*/) const {
- return StreamPrecedenceType(kV3LowestPriority);
+ StreamIdType stream_id) const {
+ auto it = registered_streams_.find(stream_id);
+ if (it == registered_streams_.end()) {
+ SPDY_DVLOG(1) << "Stream " << stream_id << " not registered";
+ return StreamPrecedenceType(kV3LowestPriority);
+ }
+ return StreamPrecedenceType(it->second.priority);
}
template <typename StreamIdType>
void FifoWriteScheduler<StreamIdType>::UpdateStreamPrecedence(
- StreamIdType /*stream_id*/,
- const StreamPrecedenceType& /*precedence*/) {}
+ StreamIdType stream_id,
+ const StreamPrecedenceType& precedence) {
+ auto it = registered_streams_.find(stream_id);
+ if (it == registered_streams_.end()) {
+ SPDY_DVLOG(1) << "Stream " << stream_id << " not registered";
+ return;
+ }
+ it->second.priority = precedence.spdy3_priority();
+}
template <typename StreamIdType>
std::vector<StreamIdType> FifoWriteScheduler<StreamIdType>::GetStreamChildren(
@@ -109,7 +129,7 @@ void FifoWriteScheduler<StreamIdType>::RecordStreamEventTime(
int64_t now_in_usec) {
auto it = registered_streams_.find(stream_id);
if (it != registered_streams_.end()) {
- it->second = now_in_usec;
+ it->second.event_time = now_in_usec;
} else {
SPDY_BUG << "Stream " << stream_id << " is not registered";
}
@@ -128,7 +148,8 @@ int64_t FifoWriteScheduler<StreamIdType>::GetLatestEventWithPrecedence(
if (stream_id <= it->first) {
break;
}
- latest_event_time_us = std::max(latest_event_time_us, it->second);
+ latest_event_time_us =
+ std::max(latest_event_time_us, it->second.event_time);
}
return latest_event_time_us;
}
diff --git a/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler_test.cc b/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler_test.cc
index 950b6414d1d..d1dd066d6e9 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler_test.cc
@@ -80,6 +80,24 @@ TEST(FifoWriteSchedulerTest, GetLatestEventTest) {
EXPECT_EQ(0, fifo.GetLatestEventWithPrecedence(1));
}
+TEST(FifoWriteSchedulerTest, GetStreamPrecedence) {
+ FifoWriteScheduler<SpdyStreamId> fifo;
+ // Return lowest priority for unknown stream.
+ EXPECT_EQ(kV3LowestPriority, fifo.GetStreamPrecedence(1).spdy3_priority());
+
+ fifo.RegisterStream(1, SpdyStreamPrecedence(3));
+ EXPECT_TRUE(fifo.GetStreamPrecedence(1).is_spdy3_priority());
+ EXPECT_EQ(3, fifo.GetStreamPrecedence(1).spdy3_priority());
+
+ // Redundant registration shouldn't change stream priority.
+ EXPECT_SPDY_BUG(fifo.RegisterStream(1, SpdyStreamPrecedence(4)),
+ "Stream 1 already registered");
+ EXPECT_EQ(3, fifo.GetStreamPrecedence(1).spdy3_priority());
+
+ fifo.UpdateStreamPrecedence(1, SpdyStreamPrecedence(5));
+ EXPECT_EQ(5, fifo.GetStreamPrecedence(1).spdy3_priority());
+}
+
} // namespace test
} // namespace spdy
diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.cc
index e3bf8f64c15..71b94a37f3f 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.cc
@@ -176,16 +176,9 @@ void HpackEncoder::EmitNonIndexedLiteral(const Representation& representation,
SPDY_DVLOG(2) << "Emitting nonindexed literal: (" << representation.first
<< ", " << representation.second << ")";
output_stream_.AppendPrefix(kLiteralNoIndexOpcode);
- if (GetSpdyReloadableFlag(spdy_hpack_use_indexed_name)) {
- SPDY_CODE_COUNT(spdy_hpack_use_indexed_name);
- const HpackEntry* name_entry =
- header_table_.GetByName(representation.first);
- if (enable_compression && name_entry != nullptr) {
- output_stream_.AppendUint32(header_table_.IndexOf(name_entry));
- } else {
- output_stream_.AppendUint32(0);
- EmitString(representation.first);
- }
+ const HpackEntry* name_entry = header_table_.GetByName(representation.first);
+ if (enable_compression && name_entry != nullptr) {
+ output_stream_.AppendUint32(header_table_.IndexOf(name_entry));
} else {
output_stream_.AppendUint32(0);
EmitString(representation.first);
diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder_test.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder_test.cc
index 2b1efe973b8..f6f9f87a1c0 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder_test.cc
@@ -274,12 +274,8 @@ TEST_F(HpackEncoderTestBase, EncodeRepresentations) {
{"accept", "text/html, text/plain,application/xml"},
{"cookie", "val4"},
{"withnul", quiche::QuicheStringPiece("one\0two", 7)}};
- if (GetSpdyReloadableFlag(spdy_hpack_use_indexed_name)) {
- ExpectNonIndexedLiteralWithNameIndex(peer_.table()->GetByName(":path"),
- "/home");
- } else {
- ExpectNonIndexedLiteral(":path", "/home");
- }
+ ExpectNonIndexedLiteralWithNameIndex(peer_.table()->GetByName(":path"),
+ "/home");
ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "val1");
ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "val2");
ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "val3");
@@ -566,12 +562,8 @@ TEST_P(HpackEncoderTest, PseudoHeadersFirst) {
// Headers are indexed in the order in which they were added.
// This entry pushes "cookie: a=bb" back to 63.
- if (GetSpdyReloadableFlag(spdy_hpack_use_indexed_name)) {
- ExpectNonIndexedLiteralWithNameIndex(peer_.table()->GetByName(":path"),
- "/spam/eggs.html");
- } else {
- ExpectNonIndexedLiteral(":path", "/spam/eggs.html");
- }
+ ExpectNonIndexedLiteralWithNameIndex(peer_.table()->GetByName(":path"),
+ "/spam/eggs.html");
ExpectIndexedLiteral(peer_.table()->GetByName(":authority"),
"www.example.com");
ExpectIndexedLiteral("-foo", "bar");
diff --git a/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler.h b/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler.h
index 405ccf5387b..d2e7fcfb847 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler.h
+++ b/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler.h
@@ -5,6 +5,7 @@
#ifndef QUICHE_SPDY_CORE_LIFO_WRITE_SCHEDULER_H_
#define QUICHE_SPDY_CORE_LIFO_WRITE_SCHEDULER_H_
+#include <cstdint>
#include <map>
#include <set>
#include <string>
@@ -40,15 +41,13 @@ class LifoWriteScheduler : public WriteScheduler<StreamIdType> {
return registered_streams_.find(stream_id) != registered_streams_.end();
}
- // Stream precedence is not supported by this scheduler.
+ // Stream precedence is available but note that it is not used for scheduling
+ // in this scheduler.
StreamPrecedenceType GetStreamPrecedence(
- StreamIdType /*stream_id*/) const override {
- return StreamPrecedenceType(kV3LowestPriority);
- }
+ StreamIdType stream_id) const override;
- void UpdateStreamPrecedence(
- StreamIdType /*stream_id*/,
- const StreamPrecedenceType& /*precedence*/) override {}
+ void UpdateStreamPrecedence(StreamIdType stream_id,
+ const StreamPrecedenceType& precedence) override;
std::vector<StreamIdType> GetStreamChildren(
StreamIdType /*stream_id*/) const override {
@@ -85,19 +84,26 @@ class LifoWriteScheduler : public WriteScheduler<StreamIdType> {
private:
friend class test::LifoWriteSchedulerPeer<StreamIdType>;
+ struct StreamInfo {
+ SpdyPriority priority;
+ int64_t event_time; // read/write event time (us since Unix epoch).
+ };
+
std::set<StreamIdType> ready_streams_;
- std::map<StreamIdType, int64_t> registered_streams_;
+ std::map<StreamIdType, StreamInfo> registered_streams_;
};
template <typename StreamIdType>
void LifoWriteScheduler<StreamIdType>::RegisterStream(
StreamIdType stream_id,
- const StreamPrecedenceType& /*precedence*/) {
+ const StreamPrecedenceType& precedence) {
if (StreamRegistered(stream_id)) {
SPDY_BUG << "Stream " << stream_id << " already registered";
return;
}
- registered_streams_.emplace_hint(registered_streams_.end(), stream_id, 0);
+ registered_streams_.emplace_hint(
+ registered_streams_.end(), stream_id,
+ StreamInfo{/*priority=*/precedence.spdy3_priority(), /*event_time=*/0});
}
template <typename StreamIdType>
@@ -112,12 +118,36 @@ void LifoWriteScheduler<StreamIdType>::UnregisterStream(
}
template <typename StreamIdType>
+typename LifoWriteScheduler<StreamIdType>::StreamPrecedenceType
+LifoWriteScheduler<StreamIdType>::GetStreamPrecedence(
+ StreamIdType stream_id) const {
+ auto it = registered_streams_.find(stream_id);
+ if (it == registered_streams_.end()) {
+ SPDY_DVLOG(1) << "Stream " << stream_id << " not registered";
+ return StreamPrecedenceType(kV3LowestPriority);
+ }
+ return StreamPrecedenceType(it->second.priority);
+}
+
+template <typename StreamIdType>
+void LifoWriteScheduler<StreamIdType>::UpdateStreamPrecedence(
+ StreamIdType stream_id,
+ const StreamPrecedenceType& precedence) {
+ auto it = registered_streams_.find(stream_id);
+ if (it == registered_streams_.end()) {
+ SPDY_DVLOG(1) << "Stream " << stream_id << " not registered";
+ return;
+ }
+ it->second.priority = precedence.spdy3_priority();
+}
+
+template <typename StreamIdType>
void LifoWriteScheduler<StreamIdType>::RecordStreamEventTime(
StreamIdType stream_id,
int64_t now_in_usec) {
auto it = registered_streams_.find(stream_id);
if (it != registered_streams_.end()) {
- it->second = now_in_usec;
+ it->second.event_time = now_in_usec;
} else {
SPDY_BUG << "Stream " << stream_id << " is not registered";
}
@@ -134,8 +164,8 @@ int64_t LifoWriteScheduler<StreamIdType>::GetLatestEventWithPrecedence(
for (auto it = registered_streams_.rbegin(); it != registered_streams_.rend();
++it) {
if (stream_id < it->first) {
- if (it->second > latest_event_time_us) {
- latest_event_time_us = it->second;
+ if (it->second.event_time > latest_event_time_us) {
+ latest_event_time_us = it->second.event_time;
}
} else {
break;
diff --git a/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler_test.cc b/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler_test.cc
index 1d7ecbf8e32..744ee136521 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler_test.cc
@@ -151,6 +151,24 @@ TEST(LifoWriteSchedulerTest, GetLatestEventTest) {
"Stream 11 is not registered");
}
+TEST(LifoWriteSchedulerTest, GetStreamPrecedence) {
+ LifoWriteScheduler<SpdyStreamId> lifo;
+ // Return lowest priority for unknown stream.
+ EXPECT_EQ(kV3LowestPriority, lifo.GetStreamPrecedence(1).spdy3_priority());
+
+ lifo.RegisterStream(1, SpdyStreamPrecedence(3));
+ EXPECT_TRUE(lifo.GetStreamPrecedence(1).is_spdy3_priority());
+ EXPECT_EQ(3, lifo.GetStreamPrecedence(1).spdy3_priority());
+
+ // Redundant registration shouldn't change stream priority.
+ EXPECT_SPDY_BUG(lifo.RegisterStream(1, SpdyStreamPrecedence(4)),
+ "Stream 1 already registered");
+ EXPECT_EQ(3, lifo.GetStreamPrecedence(1).spdy3_priority());
+
+ lifo.UpdateStreamPrecedence(1, SpdyStreamPrecedence(5));
+ EXPECT_EQ(5, lifo.GetStreamPrecedence(1).spdy3_priority());
+}
+
} // namespace test
} // namespace spdy