@@ -1809,6 +1809,47 @@ 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 must still
1815+ # result in connection_lost() being called eventually, instead of
1816+ # leaving the transport hanging forever. Two failing writes are
1817+ # used so that the first failure's error_received() call closes
1818+ # the transport while the second is still queued (close() defers
1819+ # to the write loop), and the second failure then empties the
1820+ # buffer with self._closing already True and no write in flight
1821+ # -- exercising the `self._closing` half of the
1822+ # `if self._buffer or self._closing:` condition in _loop_writing.
1823+ loop = self .loop
1824+
1825+ class Protocol (asyncio .DatagramProtocol ):
1826+ def connection_made (self , transport ):
1827+ self .transport = transport
1828+ self .errors = []
1829+ self .lost = loop .create_future ()
1830+
1831+ def error_received (self , exc ):
1832+ self .errors .append (exc )
1833+ self .transport .close ()
1834+
1835+ def connection_lost (self , exc ):
1836+ if not self .lost .done ():
1837+ self .lost .set_result (exc )
1838+
1839+ sock = socket .socket (socket .AF_INET , socket .SOCK_DGRAM )
1840+ sock .setblocking (False )
1841+ sock .bind (('127.0.0.1' , 0 ))
1842+ transport , protocol = loop .run_until_complete (
1843+ loop .create_datagram_endpoint (Protocol , sock = sock ))
1844+ addr = sock .getsockname ()
1845+
1846+ oversized = b'\x00 ' * 70000
1847+ transport .sendto (oversized , addr )
1848+ transport .sendto (oversized , addr )
1849+
1850+ loop .run_until_complete (asyncio .wait_for (protocol .lost , 10 ))
1851+ self .assertEqual (len (protocol .errors ), 2 )
1852+
18121853 def test_datagram_recvfrom_connection_reset_recovers (self ):
18131854 # gh-127057: a UDP socket that sent a datagram to an address that
18141855 # wasn't listening can raise ConnectionResetError on a later
0 commit comments