@@ -1809,6 +1809,46 @@ def connection_lost(self, exc):
18091809 loop .run_until_complete (asyncio .wait_for (protocol .lost , 10 ))
18101810 self .assertTrue (protocol .errors )
18111811
1812+ def test_datagram_write_error_close_from_callback (self ):
1813+ # See https://github.com/python/cpython/issues/156920: an
1814+ # error_received() callback that closes the transport while data
1815+ # is still queued behind the failing write must still result in
1816+ # connection_lost() being called eventually, instead of leaving
1817+ # the transport (and its buffered data) hanging forever.
1818+ loop = self .loop
1819+
1820+ class Protocol (asyncio .DatagramProtocol ):
1821+ def connection_made (self , transport ):
1822+ self .transport = transport
1823+ self .errors = []
1824+ self .lost = loop .create_future ()
1825+
1826+ def error_received (self , exc ):
1827+ self .errors .append (exc )
1828+ self .transport .close ()
1829+
1830+ def connection_lost (self , exc ):
1831+ if not self .lost .done ():
1832+ self .lost .set_result (exc )
1833+
1834+ sock = socket .socket (socket .AF_INET , socket .SOCK_DGRAM )
1835+ sock .setblocking (False )
1836+ sock .bind (('127.0.0.1' , 0 ))
1837+ transport , protocol = loop .run_until_complete (
1838+ loop .create_datagram_endpoint (Protocol , sock = sock ))
1839+ addr = sock .getsockname ()
1840+
1841+ # queue an oversized (failing) datagram followed by one that
1842+ # would otherwise succeed, so the buffer is still non-empty when
1843+ # error_received() closes the transport.
1844+ oversized = b'\x00 ' * 70000
1845+ transport .sendto (oversized , addr )
1846+ transport .sendto (b'queued' , addr )
1847+
1848+ loop .run_until_complete (asyncio .wait_for (protocol .lost , 10 ))
1849+ self .assertTrue (protocol .errors )
1850+ self .assertIsInstance (protocol .errors [0 ], OSError )
1851+
18121852 def test_datagram_recvfrom_connection_reset_recovers (self ):
18131853 # gh-127057: a UDP socket that sent a datagram to an address that
18141854 # wasn't listening can raise ConnectionResetError on a later
0 commit comments