From d8638bbcad2eeadb613696386bd81c5c4896e573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeremy=20Lain=C3=A9?= Date: Sat, 4 Nov 2023 14:39:01 +0100 Subject: [PATCH] Use `max_datagram_size` instead of `max_packet_size` This is more consistent with RFC 9002. Lower the default max datagram size to 1200, in line with RFC 9000. --- examples/http3_client.py | 21 +++++----- examples/http3_server.py | 23 ++++++----- src/aioquic/asyncio/server.py | 4 +- src/aioquic/quic/configuration.py | 6 ++- src/aioquic/quic/connection.py | 36 ++++++++++------- src/aioquic/quic/packet_builder.py | 9 ++--- src/aioquic/quic/recovery.py | 26 ++++++------ tests/test_connection.py | 53 ++++++++++++------------- tests/test_packet_builder.py | 64 +++++++++++++++--------------- tests/test_recovery.py | 4 +- 10 files changed, 126 insertions(+), 120 deletions(-) diff --git a/examples/http3_client.py b/examples/http3_client.py index ae5d8dec4..3dcae805f 100644 --- a/examples/http3_client.py +++ b/examples/http3_client.py @@ -22,10 +22,9 @@ HeadersReceived, PushPromiseReceived, ) -from aioquic.quic.configuration import QuicConfiguration +from aioquic.quic.configuration import SMALLEST_MAX_DATAGRAM_SIZE, QuicConfiguration from aioquic.quic.events import QuicEvent from aioquic.quic.logger import QuicFileLogger -from aioquic.quic.packet_builder import PACKET_MAX_SIZE from aioquic.tls import CipherSuite, SessionTicket try: @@ -428,12 +427,12 @@ async def main( client._quic.close(error_code=ErrorCode.H3_NO_ERROR) -def check_packet_size(arg): +def check_max_datagram_size(arg): iarg = int(arg) - if iarg < PACKET_MAX_SIZE: + if iarg < SMALLEST_MAX_DATAGRAM_SIZE: raise argparse.ArgumentTypeError( - f"The specified packet size {iarg} is smaller than the " - f"minimum allowed maximum packet size {PACKET_MAX_SIZE}." + f"The specified datagram size {iarg} is less than the smallest " + f"allowed maximum datagram size {SMALLEST_MAX_DATAGRAM_SIZE}." ) return iarg @@ -515,10 +514,10 @@ def check_packet_size(arg): help="local port to bind for connections", ) parser.add_argument( - "--packet-size", - type=check_packet_size, - default=PACKET_MAX_SIZE, - help="specify custom packet size", + "--max-datagram-size", + type=check_max_datagram_size, + default=defaults.max_datagram_size, + help="maximum datagram size to send, excluding UDP or IP overhead", ) parser.add_argument( "--zero-rtt", action="store_true", help="try to send requests using 0-RTT" @@ -538,7 +537,7 @@ def check_packet_size(arg): configuration = QuicConfiguration( is_client=True, alpn_protocols=H0_ALPN if args.legacy_http else H3_ALPN, - max_packet_size=args.packet_size, + max_datagram_size=args.max_datagram_size, ) if args.ca_certs: configuration.load_verify_locations(args.ca_certs) diff --git a/examples/http3_server.py b/examples/http3_server.py index 1399732a8..f3e099d68 100644 --- a/examples/http3_server.py +++ b/examples/http3_server.py @@ -21,10 +21,9 @@ WebTransportStreamDataReceived, ) from aioquic.h3.exceptions import NoAvailablePushIDError -from aioquic.quic.configuration import QuicConfiguration +from aioquic.quic.configuration import SMALLEST_MAX_DATAGRAM_SIZE, QuicConfiguration from aioquic.quic.events import DatagramFrameReceived, ProtocolNegotiated, QuicEvent from aioquic.quic.logger import QuicFileLogger -from aioquic.quic.packet_builder import PACKET_MAX_SIZE from aioquic.tls import SessionTicket try: @@ -495,17 +494,19 @@ async def main( await asyncio.Future() -def check_packet_size(arg): +def check_max_datagram_size(arg): iarg = int(arg) - if iarg < PACKET_MAX_SIZE: + if iarg < SMALLEST_MAX_DATAGRAM_SIZE: raise argparse.ArgumentTypeError( - f"The specified packet size {iarg} is smaller than the " - f"minimum allowed maximum packet size {PACKET_MAX_SIZE}." + f"The specified datagram size {iarg} is less than the smallest " + f"allowed maximum datagram size {SMALLEST_MAX_DATAGRAM_SIZE}." ) return iarg if __name__ == "__main__": + defaults = QuicConfiguration(is_client=False) + parser = argparse.ArgumentParser(description="QUIC server") parser.add_argument( "app", @@ -546,10 +547,10 @@ def check_packet_size(arg): help="log secrets to a file, for use with Wireshark", ) parser.add_argument( - "--packet-size", - type=check_packet_size, - default=PACKET_MAX_SIZE, - help="specify custom packet size", + "--max-datagram-size", + type=check_max_datagram_size, + default=defaults.max_datagram_size, + help="maximum datagram size to send, excluding UDP or IP overhead", ) parser.add_argument( "-q", @@ -593,7 +594,7 @@ def check_packet_size(arg): alpn_protocols=H3_ALPN + H0_ALPN + ["siduck"], is_client=False, max_datagram_frame_size=65536, - max_packet_size=args.packet_size, + max_datagram_size=args.max_datagram_size, quic_logger=quic_logger, secrets_log_file=secrets_log_file, ) diff --git a/src/aioquic/asyncio/server.py b/src/aioquic/asyncio/server.py index c647258ae..b5f6cd8d7 100644 --- a/src/aioquic/asyncio/server.py +++ b/src/aioquic/asyncio/server.py @@ -4,7 +4,7 @@ from typing import Callable, Dict, Optional, Text, Union, cast from ..buffer import Buffer -from ..quic.configuration import QuicConfiguration +from ..quic.configuration import SMALLEST_MAX_DATAGRAM_SIZE, QuicConfiguration from ..quic.connection import NetworkAddress, QuicConnection from ..quic.packet import ( PACKET_TYPE_INITIAL, @@ -85,7 +85,7 @@ def datagram_received(self, data: Union[bytes, Text], addr: NetworkAddress) -> N retry_source_connection_id: Optional[bytes] = None if ( protocol is None - and len(data) >= 1200 + and len(data) >= SMALLEST_MAX_DATAGRAM_SIZE and header.packet_type == PACKET_TYPE_INITIAL ): # retry diff --git a/src/aioquic/quic/configuration.py b/src/aioquic/quic/configuration.py index 4f6e4a07c..17bd9a380 100644 --- a/src/aioquic/quic/configuration.py +++ b/src/aioquic/quic/configuration.py @@ -12,6 +12,8 @@ from .logger import QuicLogger from .packet import QuicProtocolVersion +SMALLEST_MAX_DATAGRAM_SIZE = 1200 + @dataclass class QuicConfiguration: @@ -46,9 +48,9 @@ class QuicConfiguration: Connection-wide flow control limit. """ - max_packet_size: int = 1280 + max_datagram_size: int = SMALLEST_MAX_DATAGRAM_SIZE """ - Maximum size of QUIC packets. + The maximum QUIC payload size in bytes, excluding UDP or IP overhead. """ max_stream_data: int = 1048576 diff --git a/src/aioquic/quic/connection.py b/src/aioquic/quic/connection.py index dda6baa5f..ea66c63af 100644 --- a/src/aioquic/quic/connection.py +++ b/src/aioquic/quic/connection.py @@ -16,7 +16,7 @@ size_uint_var, ) from . import events -from .configuration import QuicConfiguration +from .configuration import SMALLEST_MAX_DATAGRAM_SIZE, QuicConfiguration from .crypto import CryptoError, CryptoPair, KeyUnavailableError from .logger import QuicLoggerTrace from .packet import ( @@ -240,6 +240,10 @@ def __init__( session_ticket_fetcher: Optional[tls.SessionTicketFetcher] = None, session_ticket_handler: Optional[tls.SessionTicketHandler] = None, ) -> None: + assert configuration.max_datagram_size >= SMALLEST_MAX_DATAGRAM_SIZE, ( + "The smallest allowed maximum packet size is " + f"{SMALLEST_MAX_DATAGRAM_SIZE} bytes" + ) if configuration.is_client: assert ( original_destination_connection_id is None @@ -303,10 +307,7 @@ def __init__( frame_type=QuicFrameType.MAX_STREAMS_UNI, name="max_streams_uni", value=128 ) self._loss_at: Optional[float] = None - assert ( - configuration.max_packet_size >= 1200 - ), "The smallest allowed maximum packet size is 1200 bytes" - self._max_packet_size = configuration.max_packet_size + self._max_datagram_size = configuration.max_datagram_size self._network_paths: List[QuicNetworkPath] = [] self._pacing_at: Optional[float] = None self._packet_number = 0 @@ -363,7 +364,7 @@ def __init__( # loss recovery self._loss = QuicPacketRecovery( initial_rtt=configuration.initial_rtt, - max_packet_size=self._max_packet_size, + max_datagram_size=self._max_datagram_size, peer_completed_address_validation=not self._is_client, quic_logger=self._quic_logger, send_probe=self._send_probe, @@ -505,7 +506,7 @@ def datagrams_to_send(self, now: float) -> List[Tuple[bytes, NetworkAddress]]: builder = QuicPacketBuilder( host_cid=self.host_cid, is_client=self._is_client, - max_packet_size=self._max_packet_size, + max_datagram_size=self._max_datagram_size, packet_number=self._packet_number, peer_cid=self._peer_cid.cid, peer_token=self._peer_token, @@ -544,8 +545,11 @@ def datagrams_to_send(self, now: float) -> List[Tuple[bytes, NetworkAddress]]: builder.max_flight_bytes = ( self._loss.congestion_window - self._loss.bytes_in_flight ) - if self._probe_pending and builder.max_flight_bytes < self._max_packet_size: - builder.max_flight_bytes = self._max_packet_size + if ( + self._probe_pending + and builder.max_flight_bytes < self._max_datagram_size + ): + builder.max_flight_bytes = self._max_datagram_size # limit data on un-validated network paths if not network_path.is_validated: @@ -2462,14 +2466,16 @@ def _parse_transport_parameters( frame_type=QuicFrameType.CRYPTO, reason_phrase="max_ack_delay must be < 2^14", ) - if ( - quic_transport_parameters.max_udp_payload_size is not None - and quic_transport_parameters.max_udp_payload_size < 1200 + if quic_transport_parameters.max_udp_payload_size is not None and ( + quic_transport_parameters.max_udp_payload_size + < SMALLEST_MAX_DATAGRAM_SIZE ): raise QuicConnectionError( error_code=QuicErrorCode.TRANSPORT_PARAMETER_ERROR, frame_type=QuicFrameType.CRYPTO, - reason_phrase="max_udp_payload_size must be >= 1200", + reason_phrase=( + f"max_udp_payload_size must be >= {SMALLEST_MAX_DATAGRAM_SIZE}" + ), ) # store remote parameters @@ -2526,7 +2532,7 @@ def _serialize_transport_parameters(self) -> bytes: initial_source_connection_id=self._local_initial_source_connection_id, max_ack_delay=25, max_datagram_frame_size=self._configuration.max_datagram_frame_size, - quantum_readiness=b"Q" * 1200 + quantum_readiness=b"Q" * SMALLEST_MAX_DATAGRAM_SIZE if self._configuration.quantum_readiness_test else None, stateless_reset_token=self._host_cids[0].stateless_reset_token, @@ -2549,7 +2555,7 @@ def _serialize_transport_parameters(self) -> bytes: ), ) - buf = Buffer(capacity=3 * self._max_packet_size) + buf = Buffer(capacity=3 * self._max_datagram_size) push_quic_transport_parameters(buf, quic_transport_parameters) return buf.data diff --git a/src/aioquic/quic/packet_builder.py b/src/aioquic/quic/packet_builder.py index 10fed31ca..6fd92cb14 100644 --- a/src/aioquic/quic/packet_builder.py +++ b/src/aioquic/quic/packet_builder.py @@ -17,7 +17,6 @@ is_long_header, ) -PACKET_MAX_SIZE = 1280 PACKET_LENGTH_SEND_SIZE = 2 PACKET_NUMBER_SEND_SIZE = 2 @@ -64,7 +63,7 @@ def __init__( peer_cid: bytes, version: int, is_client: bool, - max_packet_size: int, + max_datagram_size: int, packet_number: int = 0, peer_token: bytes = b"", quic_logger: Optional[QuicLoggerTrace] = None, @@ -99,9 +98,9 @@ def __init__( self._packet_start = 0 self._packet_type = 0 - self._buffer = Buffer(max_packet_size) - self._buffer_capacity = max_packet_size - self._flight_capacity = max_packet_size + self._buffer = Buffer(max_datagram_size) + self._buffer_capacity = max_datagram_size + self._flight_capacity = max_datagram_size @property def packet_is_empty(self) -> bool: diff --git a/src/aioquic/quic/recovery.py b/src/aioquic/quic/recovery.py index 2c7614e5e..2a95c8590 100644 --- a/src/aioquic/quic/recovery.py +++ b/src/aioquic/quic/recovery.py @@ -36,8 +36,8 @@ def __init__(self) -> None: class QuicPacketPacer: - def __init__(self, *, max_packet_size: int) -> None: - self._max_packet_size = max_packet_size + def __init__(self, *, max_datagram_size: int) -> None: + self._max_datagram_size = max_datagram_size self.bucket_max: float = 0.0 self.bucket_time: float = 0.0 self.evaluation_time: float = 0.0 @@ -68,13 +68,13 @@ def update_bucket(self, now: float) -> None: def update_rate(self, congestion_window: int, smoothed_rtt: float) -> None: pacing_rate = congestion_window / max(smoothed_rtt, K_MICRO_SECOND) self.packet_time = max( - K_MICRO_SECOND, min(self._max_packet_size / pacing_rate, K_SECOND) + K_MICRO_SECOND, min(self._max_datagram_size / pacing_rate, K_SECOND) ) self.bucket_max = ( max( - 2 * self._max_packet_size, - min(congestion_window // 4, 16 * self._max_packet_size), + 2 * self._max_datagram_size, + min(congestion_window // 4, 16 * self._max_datagram_size), ) / pacing_rate ) @@ -87,10 +87,10 @@ class QuicCongestionControl: New Reno congestion control. """ - def __init__(self, *, max_packet_size: int) -> None: - self._max_packet_size = max_packet_size + def __init__(self, *, max_datagram_size: int) -> None: + self._max_datagram_size = max_datagram_size self.bytes_in_flight = 0 - self.congestion_window = K_INITIAL_WINDOW * self._max_packet_size + self.congestion_window = K_INITIAL_WINDOW * self._max_datagram_size self._congestion_recovery_start_time = 0.0 self._congestion_stash = 0 self._rtt_monitor = QuicRttMonitor() @@ -112,7 +112,7 @@ def on_packet_acked(self, packet: QuicSentPacket) -> None: count = self._congestion_stash // self.congestion_window if count: self._congestion_stash -= count * self.congestion_window - self.congestion_window += count * self._max_packet_size + self.congestion_window += count * self._max_datagram_size def on_packet_sent(self, packet: QuicSentPacket) -> None: self.bytes_in_flight += packet.sent_bytes @@ -133,7 +133,7 @@ def on_packets_lost(self, packets: Iterable[QuicSentPacket], now: float) -> None self._congestion_recovery_start_time = now self.congestion_window = max( int(self.congestion_window * K_LOSS_REDUCTION_FACTOR), - K_MINIMUM_WINDOW * self._max_packet_size, + K_MINIMUM_WINDOW * self._max_datagram_size, ) self.ssthresh = self.congestion_window @@ -155,7 +155,7 @@ class QuicPacketRecovery: def __init__( self, initial_rtt: float, - max_packet_size: int, + max_datagram_size: int, peer_completed_address_validation: bool, send_probe: Callable[[], None], logger: Optional[logging.LoggerAdapter] = None, @@ -181,8 +181,8 @@ def __init__( self._time_of_last_sent_ack_eliciting_packet = 0.0 # congestion control - self._cc = QuicCongestionControl(max_packet_size=max_packet_size) - self._pacer = QuicPacketPacer(max_packet_size=max_packet_size) + self._cc = QuicCongestionControl(max_datagram_size=max_datagram_size) + self._pacer = QuicPacketPacer(max_datagram_size=max_datagram_size) @property def bytes_in_flight(self) -> int: diff --git a/tests/test_connection.py b/tests/test_connection.py index 72b3f5ce0..b7a7c9c9b 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -8,7 +8,7 @@ from aioquic import tls from aioquic.buffer import UINT_VAR_MAX, Buffer, encode_uint_var from aioquic.quic import events -from aioquic.quic.configuration import QuicConfiguration +from aioquic.quic.configuration import SMALLEST_MAX_DATAGRAM_SIZE, QuicConfiguration from aioquic.quic.connection import ( STREAM_COUNT_MAX, NetworkAddress, @@ -30,7 +30,6 @@ push_quic_transport_parameters, ) from aioquic.quic.packet_builder import ( - PACKET_MAX_SIZE, QuicDeliveryState, QuicPacketBuilder, ) @@ -150,7 +149,7 @@ def client_and_server( def disable_packet_pacing(connection): class DummyPacketPacer(QuicPacketPacer): def __init__(self): - super().__init__(max_packet_size=PACKET_MAX_SIZE) + super().__init__(max_datagram_size=SMALLEST_MAX_DATAGRAM_SIZE) def next_send_time(self, now): return None @@ -361,7 +360,7 @@ def test_connect_with_custom_packet_size(self): packet size configuration. """ - client_configuration = QuicConfiguration(is_client=True, max_packet_size=1480) + client_configuration = QuicConfiguration(is_client=True, max_datagram_size=1480) client_configuration.load_verify_locations(cafile=SERVER_CACERTFILE) client = QuicConnection(configuration=client_configuration) @@ -397,21 +396,21 @@ def test_connect_with_loss_1(self): now = 0.0 client.connect(SERVER_ADDR, now=now) items = client.datagrams_to_send(now=now) - self.assertEqual(datagram_sizes(items), [1280]) + self.assertEqual(datagram_sizes(items), [1200]) self.assertEqual(client.get_timer(), 0.2) # INITIAL is lost now = client.get_timer() client.handle_timer(now=now) items = client.datagrams_to_send(now=now) - self.assertEqual(datagram_sizes(items), [1280]) + self.assertEqual(datagram_sizes(items), [1200]) self.assertAlmostEqual(client.get_timer(), 0.6) # server receives INITIAL, sends INITIAL + HANDSHAKE now += TICK server.receive_datagram(items[0][0], CLIENT_ADDR, now=now) items = server.datagrams_to_send(now=now) - self.assertEqual(datagram_sizes(items), [1280, 1068]) + self.assertEqual(datagram_sizes(items), [1200, 1148]) self.assertAlmostEqual(server.get_timer(), 0.45) self.assertEqual(len(server._loss.spaces[0].sent_packets), 1) self.assertEqual(len(server._loss.spaces[1].sent_packets), 2) @@ -472,14 +471,14 @@ def test_connect_with_loss_2(self): now = 0.0 client.connect(SERVER_ADDR, now=now) items = client.datagrams_to_send(now=now) - self.assertEqual(datagram_sizes(items), [1280]) + self.assertEqual(datagram_sizes(items), [1200]) self.assertEqual(client.get_timer(), 0.2) # server receives INITIAL, sends INITIAL + HANDSHAKE but first datagram is lost now += TICK server.receive_datagram(items[0][0], CLIENT_ADDR, now=now) items = server.datagrams_to_send(now=now) - self.assertEqual(datagram_sizes(items), [1280, 1068]) + self.assertEqual(datagram_sizes(items), [1200, 1148]) self.assertEqual(server.get_timer(), 0.25) self.assertEqual(len(server._loss.spaces[0].sent_packets), 1) self.assertEqual(len(server._loss.spaces[1].sent_packets), 2) @@ -490,7 +489,7 @@ def test_connect_with_loss_2(self): now += TICK client.receive_datagram(items[1][0], SERVER_ADDR, now=now) items = client.datagrams_to_send(now=now) - self.assertEqual(datagram_sizes(items), [1280]) + self.assertEqual(datagram_sizes(items), [1200]) self.assertAlmostEqual(client.get_timer(), 0.3) self.assertIsNone(client.next_event()) @@ -498,7 +497,7 @@ def test_connect_with_loss_2(self): now += TICK server.receive_datagram(items[0][0], CLIENT_ADDR, now=now) items = server.datagrams_to_send(now=now) - self.assertEqual(datagram_sizes(items), [1280, 1068]) + self.assertEqual(datagram_sizes(items), [1200, 1148]) self.assertAlmostEqual(server.get_timer(), 0.35) self.assertEqual(len(server._loss.spaces[0].sent_packets), 1) self.assertEqual(len(server._loss.spaces[1].sent_packets), 2) @@ -558,14 +557,14 @@ def test_connect_with_loss_3(self): now = 0.0 client.connect(SERVER_ADDR, now=now) items = client.datagrams_to_send(now=now) - self.assertEqual(datagram_sizes(items), [1280]) + self.assertEqual(datagram_sizes(items), [1200]) self.assertEqual(client.get_timer(), 0.2) # server receives INITIAL, sends INITIAL + HANDSHAKE now += TICK server.receive_datagram(items[0][0], CLIENT_ADDR, now=now) items = server.datagrams_to_send(now=now) - self.assertEqual(datagram_sizes(items), [1280, 1068]) + self.assertEqual(datagram_sizes(items), [1200, 1148]) self.assertEqual(server.get_timer(), 0.25) self.assertEqual(len(server._loss.spaces[0].sent_packets), 1) self.assertEqual(len(server._loss.spaces[1].sent_packets), 2) @@ -576,7 +575,7 @@ def test_connect_with_loss_3(self): now = client.get_timer() client.handle_timer(now=now) items = client.datagrams_to_send(now=now) - self.assertEqual(datagram_sizes(items), [1280]) + self.assertEqual(datagram_sizes(items), [1200]) self.assertAlmostEqual(client.get_timer(), 0.6) self.assertIsNone(client.next_event()) @@ -584,7 +583,7 @@ def test_connect_with_loss_3(self): now += TICK server.receive_datagram(items[0][0], CLIENT_ADDR, now=now) items = server.datagrams_to_send(now=now) - self.assertEqual(datagram_sizes(items), [1280, 1068]) + self.assertEqual(datagram_sizes(items), [1200, 1148]) self.assertEqual(server.get_timer(), 0.45) self.assertEqual(len(server._loss.spaces[0].sent_packets), 1) self.assertEqual(len(server._loss.spaces[1].sent_packets), 2) @@ -639,14 +638,14 @@ def test_connect_with_loss_4(self): now = 0.0 client.connect(SERVER_ADDR, now=now) items = client.datagrams_to_send(now=now) - self.assertEqual(datagram_sizes(items), [1280]) + self.assertEqual(datagram_sizes(items), [1200]) self.assertEqual(client.get_timer(), 0.2) # server receives INITIAL, sends INITIAL + HANDSHAKE but second datagram is lost now += TICK server.receive_datagram(items[0][0], CLIENT_ADDR, now=now) items = server.datagrams_to_send(now=now) - self.assertEqual(datagram_sizes(items), [1280, 1068]) + self.assertEqual(datagram_sizes(items), [1200, 1148]) self.assertEqual(server.get_timer(), 0.25) self.assertEqual(len(server._loss.spaces[0].sent_packets), 1) self.assertEqual(len(server._loss.spaces[1].sent_packets), 2) @@ -683,7 +682,7 @@ def test_connect_with_loss_4(self): now = server.get_timer() server.handle_timer(now=now) items = server.datagrams_to_send(now=now) - self.assertEqual(datagram_sizes(items), [1280, 892]) + self.assertEqual(datagram_sizes(items), [1200, 972]) self.assertAlmostEqual(server.get_timer(), 0.65) self.assertEqual(len(server._loss.spaces[0].sent_packets), 0) self.assertEqual(len(server._loss.spaces[1].sent_packets), 3) @@ -736,14 +735,14 @@ def test_connect_with_loss_5(self): now = 0.0 client.connect(SERVER_ADDR, now=now) items = client.datagrams_to_send(now=now) - self.assertEqual(datagram_sizes(items), [1280]) + self.assertEqual(datagram_sizes(items), [1200]) self.assertEqual(client.get_timer(), 0.2) # server receives INITIAL, sends INITIAL + HANDSHAKE now += TICK server.receive_datagram(items[0][0], CLIENT_ADDR, now=now) items = server.datagrams_to_send(now=now) - self.assertEqual(datagram_sizes(items), [1280, 1068]) + self.assertEqual(datagram_sizes(items), [1200, 1148]) self.assertEqual(server.get_timer(), 0.25) self.assertEqual(len(server._loss.spaces[0].sent_packets), 1) self.assertEqual(len(server._loss.spaces[1].sent_packets), 2) @@ -1020,7 +1019,7 @@ def test_datagram_frame(self): def test_datagram_frame_2(self): # payload which exactly fills an entire packet - payload = b"Z" * 1250 + payload = b"Z" * 1170 with client_and_server( client_options={"max_datagram_frame_size": 65536}, @@ -1100,7 +1099,7 @@ def test_receive_datagram_reserved_bits_non_zero(self): builder = QuicPacketBuilder( host_cid=client._peer_cid.cid, is_client=False, - max_packet_size=PACKET_MAX_SIZE, + max_datagram_size=SMALLEST_MAX_DATAGRAM_SIZE, peer_cid=client.host_cid, version=client._version, ) @@ -1141,7 +1140,7 @@ def test_receive_datagram_wrong_version(self): builder = QuicPacketBuilder( host_cid=client._peer_cid.cid, is_client=False, - max_packet_size=PACKET_MAX_SIZE, + max_datagram_size=SMALLEST_MAX_DATAGRAM_SIZE, peer_cid=client.host_cid, version=0xFF000011, # DRAFT_16 ) @@ -2308,7 +2307,7 @@ def test_payload_received_padding_only(self): with client_and_server() as (client, server): # client receives padding only is_ack_eliciting, is_probing = client._payload_received( - client_receive_context(client), b"\x00" * 1200 + client_receive_context(client), b"\x00" * SMALLEST_MAX_DATAGRAM_SIZE ) self.assertFalse(is_ack_eliciting) self.assertTrue(is_probing) @@ -2350,14 +2349,14 @@ def test_send_max_data_blocked_by_cc(self): with client_and_server() as (client, server): # check congestion control self.assertEqual(client._loss.bytes_in_flight, 0) - self.assertEqual(client._loss.congestion_window, 14303) + self.assertEqual(client._loss.congestion_window, 13423) # artificially raise received data counter client._local_max_data_used = client._local_max_data self.assertEqual(server._remote_max_data, 1048576) # artificially raise bytes in flight - client._loss._cc.bytes_in_flight = 14303 + client._loss._cc.bytes_in_flight = 13423 # MAX_DATA is not sent due to congestion control self.assertEqual(drop(client), 0) @@ -2735,7 +2734,7 @@ def test_write_connection_close_early(self): builder = QuicPacketBuilder( host_cid=client.host_cid, is_client=True, - max_packet_size=PACKET_MAX_SIZE, + max_datagram_size=SMALLEST_MAX_DATAGRAM_SIZE, peer_cid=client._peer_cid.cid, version=client._version, ) diff --git a/tests/test_packet_builder.py b/tests/test_packet_builder.py index abf6ed6ec..60482c295 100644 --- a/tests/test_packet_builder.py +++ b/tests/test_packet_builder.py @@ -1,5 +1,6 @@ from unittest import TestCase +from aioquic.quic.configuration import SMALLEST_MAX_DATAGRAM_SIZE from aioquic.quic.crypto import CryptoPair from aioquic.quic.packet import ( PACKET_TYPE_HANDSHAKE, @@ -9,7 +10,6 @@ QuicProtocolVersion, ) from aioquic.quic.packet_builder import ( - PACKET_MAX_SIZE, QuicPacketBuilder, QuicPacketBuilderStop, QuicSentPacket, @@ -21,7 +21,7 @@ def create_builder(is_client=False): return QuicPacketBuilder( host_cid=bytes(8), is_client=is_client, - max_packet_size=PACKET_MAX_SIZE, + max_datagram_size=SMALLEST_MAX_DATAGRAM_SIZE, packet_number=0, peer_cid=bytes(8), peer_token=b"", @@ -44,7 +44,7 @@ def test_long_header_empty(self): crypto = create_crypto() builder.start_packet(PACKET_TYPE_INITIAL, crypto) - self.assertEqual(builder.remaining_flight_space, 1236) + self.assertEqual(builder.remaining_flight_space, 1156) self.assertTrue(builder.packet_is_empty) # check datagrams @@ -61,7 +61,7 @@ def test_long_header_padding(self): # INITIAL, fully padded builder.start_packet(PACKET_TYPE_INITIAL, crypto) - self.assertEqual(builder.remaining_flight_space, 1236) + self.assertEqual(builder.remaining_flight_space, 1156) buf = builder.start_frame(QuicFrameType.CRYPTO) buf.push_bytes(bytes(100)) self.assertFalse(builder.packet_is_empty) @@ -73,7 +73,7 @@ def test_long_header_padding(self): # check datagrams datagrams, packets = builder.flush() self.assertEqual(len(datagrams), 1) - self.assertEqual(len(datagrams[0]), 1280) + self.assertEqual(len(datagrams[0]), 1200) self.assertEqual( packets, [ @@ -84,7 +84,7 @@ def test_long_header_padding(self): is_crypto_packet=True, packet_number=0, packet_type=PACKET_TYPE_INITIAL, - sent_bytes=1280, + sent_bytes=1200, ) ], ) @@ -98,14 +98,14 @@ def test_long_header_initial_client_2(self): # INITIAL, full length builder.start_packet(PACKET_TYPE_INITIAL, crypto) - self.assertEqual(builder.remaining_flight_space, 1236) + self.assertEqual(builder.remaining_flight_space, 1156) buf = builder.start_frame(QuicFrameType.CRYPTO) buf.push_bytes(bytes(builder.remaining_flight_space)) self.assertFalse(builder.packet_is_empty) # INITIAL builder.start_packet(PACKET_TYPE_INITIAL, crypto) - self.assertEqual(builder.remaining_flight_space, 1236) + self.assertEqual(builder.remaining_flight_space, 1156) buf = builder.start_frame(QuicFrameType.CRYPTO) buf.push_bytes(bytes(100)) self.assertFalse(builder.packet_is_empty) @@ -117,8 +117,8 @@ def test_long_header_initial_client_2(self): # check datagrams datagrams, packets = builder.flush() self.assertEqual(len(datagrams), 2) - self.assertEqual(len(datagrams[0]), 1280) - self.assertEqual(len(datagrams[1]), 1280) + self.assertEqual(len(datagrams[0]), 1200) + self.assertEqual(len(datagrams[1]), 1200) self.assertEqual( packets, [ @@ -129,7 +129,7 @@ def test_long_header_initial_client_2(self): is_crypto_packet=True, packet_number=0, packet_type=PACKET_TYPE_INITIAL, - sent_bytes=1280, + sent_bytes=1200, ), QuicSentPacket( epoch=Epoch.INITIAL, @@ -138,7 +138,7 @@ def test_long_header_initial_client_2(self): is_crypto_packet=True, packet_number=1, packet_type=PACKET_TYPE_INITIAL, - sent_bytes=1280, + sent_bytes=1200, ), ], ) @@ -152,7 +152,7 @@ def test_long_header_initial_server(self): # INITIAL builder.start_packet(PACKET_TYPE_INITIAL, crypto) - self.assertEqual(builder.remaining_flight_space, 1236) + self.assertEqual(builder.remaining_flight_space, 1156) buf = builder.start_frame(QuicFrameType.CRYPTO) buf.push_bytes(bytes(100)) self.assertFalse(builder.packet_is_empty) @@ -221,7 +221,7 @@ def test_long_header_then_short_header(self): # INITIAL, full length builder.start_packet(PACKET_TYPE_INITIAL, crypto) - self.assertEqual(builder.remaining_flight_space, 1236) + self.assertEqual(builder.remaining_flight_space, 1156) buf = builder.start_frame(QuicFrameType.CRYPTO) buf.push_bytes(bytes(builder.remaining_flight_space)) self.assertFalse(builder.packet_is_empty) @@ -232,7 +232,7 @@ def test_long_header_then_short_header(self): # ONE_RTT, full length builder.start_packet(PACKET_TYPE_ONE_RTT, crypto) - self.assertEqual(builder.remaining_flight_space, 1253) + self.assertEqual(builder.remaining_flight_space, 1173) buf = builder.start_frame(QuicFrameType.STREAM_BASE) buf.push_bytes(bytes(builder.remaining_flight_space)) self.assertFalse(builder.packet_is_empty) @@ -244,8 +244,8 @@ def test_long_header_then_short_header(self): # check datagrams datagrams, packets = builder.flush() self.assertEqual(len(datagrams), 2) - self.assertEqual(len(datagrams[0]), 1280) - self.assertEqual(len(datagrams[1]), 1280) + self.assertEqual(len(datagrams[0]), 1200) + self.assertEqual(len(datagrams[1]), 1200) self.assertEqual( packets, [ @@ -256,7 +256,7 @@ def test_long_header_then_short_header(self): is_crypto_packet=True, packet_number=0, packet_type=PACKET_TYPE_INITIAL, - sent_bytes=1280, + sent_bytes=1200, ), QuicSentPacket( epoch=Epoch.ONE_RTT, @@ -265,7 +265,7 @@ def test_long_header_then_short_header(self): is_crypto_packet=False, packet_number=1, packet_type=PACKET_TYPE_ONE_RTT, - sent_bytes=1280, + sent_bytes=1200, ), ], ) @@ -279,21 +279,21 @@ def test_long_header_then_long_header(self): # INITIAL builder.start_packet(PACKET_TYPE_INITIAL, crypto) - self.assertEqual(builder.remaining_flight_space, 1236) + self.assertEqual(builder.remaining_flight_space, 1156) buf = builder.start_frame(QuicFrameType.CRYPTO) buf.push_bytes(bytes(199)) self.assertFalse(builder.packet_is_empty) # HANDSHAKE builder.start_packet(PACKET_TYPE_HANDSHAKE, crypto) - self.assertEqual(builder.remaining_flight_space, 993) + self.assertEqual(builder.remaining_flight_space, 913) buf = builder.start_frame(QuicFrameType.CRYPTO) buf.push_bytes(bytes(299)) self.assertFalse(builder.packet_is_empty) # ONE_RTT builder.start_packet(PACKET_TYPE_ONE_RTT, crypto) - self.assertEqual(builder.remaining_flight_space, 666) + self.assertEqual(builder.remaining_flight_space, 586) buf = builder.start_frame(QuicFrameType.CRYPTO) buf.push_bytes(bytes(299)) self.assertFalse(builder.packet_is_empty) @@ -343,7 +343,7 @@ def test_short_header_empty(self): crypto = create_crypto() builder.start_packet(PACKET_TYPE_ONE_RTT, crypto) - self.assertEqual(builder.remaining_flight_space, 1253) + self.assertEqual(builder.remaining_flight_space, 1173) self.assertTrue(builder.packet_is_empty) # check datagrams @@ -360,7 +360,7 @@ def test_short_header_padding(self): # ONE_RTT, full length builder.start_packet(PACKET_TYPE_ONE_RTT, crypto) - self.assertEqual(builder.remaining_flight_space, 1253) + self.assertEqual(builder.remaining_flight_space, 1173) buf = builder.start_frame(QuicFrameType.CRYPTO) buf.push_bytes(bytes(builder.remaining_flight_space)) self.assertFalse(builder.packet_is_empty) @@ -368,7 +368,7 @@ def test_short_header_padding(self): # check datagrams datagrams, packets = builder.flush() self.assertEqual(len(datagrams), 1) - self.assertEqual(len(datagrams[0]), 1280) + self.assertEqual(len(datagrams[0]), 1200) self.assertEqual( packets, [ @@ -379,7 +379,7 @@ def test_short_header_padding(self): is_crypto_packet=True, packet_number=0, packet_type=PACKET_TYPE_ONE_RTT, - sent_bytes=1280, + sent_bytes=1200, ) ], ) @@ -558,13 +558,13 @@ def test_short_header_max_total_bytes_3(self): crypto = create_crypto() builder.start_packet(PACKET_TYPE_ONE_RTT, crypto) - self.assertEqual(builder.remaining_flight_space, 1253) + self.assertEqual(builder.remaining_flight_space, 1173) buf = builder.start_frame(QuicFrameType.CRYPTO) buf.push_bytes(bytes(builder.remaining_flight_space)) self.assertFalse(builder.packet_is_empty) builder.start_packet(PACKET_TYPE_ONE_RTT, crypto) - self.assertEqual(builder.remaining_flight_space, 693) + self.assertEqual(builder.remaining_flight_space, 773) buf = builder.start_frame(QuicFrameType.CRYPTO) buf.push_bytes(bytes(builder.remaining_flight_space)) self.assertFalse(builder.packet_is_empty) @@ -575,8 +575,8 @@ def test_short_header_max_total_bytes_3(self): # check datagrams datagrams, packets = builder.flush() self.assertEqual(len(datagrams), 2) - self.assertEqual(len(datagrams[0]), 1280) - self.assertEqual(len(datagrams[1]), 720) + self.assertEqual(len(datagrams[0]), 1200) + self.assertEqual(len(datagrams[1]), 800) self.assertEqual( packets, [ @@ -587,7 +587,7 @@ def test_short_header_max_total_bytes_3(self): is_crypto_packet=True, packet_number=0, packet_type=PACKET_TYPE_ONE_RTT, - sent_bytes=1280, + sent_bytes=1200, ), QuicSentPacket( epoch=Epoch.ONE_RTT, @@ -596,7 +596,7 @@ def test_short_header_max_total_bytes_3(self): is_crypto_packet=True, packet_number=1, packet_type=PACKET_TYPE_ONE_RTT, - sent_bytes=720, + sent_bytes=800, ), ], ) diff --git a/tests/test_recovery.py b/tests/test_recovery.py index c6d4837df..086016e59 100644 --- a/tests/test_recovery.py +++ b/tests/test_recovery.py @@ -19,7 +19,7 @@ def send_probe(): class QuicPacketPacerTest(TestCase): def setUp(self): - self.pacer = QuicPacketPacer(max_packet_size=1280) + self.pacer = QuicPacketPacer(max_datagram_size=1280) def test_no_measurement(self): self.assertIsNone(self.pacer.next_send_time(now=0.0)) @@ -69,7 +69,7 @@ def setUp(self): self.recovery = QuicPacketRecovery( initial_rtt=0.1, - max_packet_size=1280, + max_datagram_size=1280, peer_completed_address_validation=True, send_probe=send_probe, )