gh-91227: Ignore ERROR_PORT_UNREACHABLE in proactor recvfrom() (#32011)

This commit is contained in:
Erik Soma 2024-03-23 11:39:35 -04:00 committed by GitHub
parent 9967b568ed
commit f11d0d8be8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 174 additions and 12 deletions

View file

@ -1378,6 +1378,80 @@ class EventLoopTestsMixin:
tr.close()
self.loop.run_until_complete(pr.done)
def test_datagram_send_to_non_listening_address(self):
# see:
# https://github.com/python/cpython/issues/91227
# https://github.com/python/cpython/issues/88906
# https://bugs.python.org/issue47071
# https://bugs.python.org/issue44743
# The Proactor event loop would fail to receive datagram messages after
# sending a message to an address that wasn't listening.
loop = self.loop
class Protocol(asyncio.DatagramProtocol):
_received_datagram = None
def datagram_received(self, data, addr):
self._received_datagram.set_result(data)
async def wait_for_datagram_received(self):
self._received_datagram = loop.create_future()
result = await asyncio.wait_for(self._received_datagram, 10)
self._received_datagram = None
return result
def create_socket():
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setblocking(False)
sock.bind(('127.0.0.1', 0))
return sock
socket_1 = create_socket()
transport_1, protocol_1 = loop.run_until_complete(
loop.create_datagram_endpoint(Protocol, sock=socket_1)
)
addr_1 = socket_1.getsockname()
socket_2 = create_socket()
transport_2, protocol_2 = loop.run_until_complete(
loop.create_datagram_endpoint(Protocol, sock=socket_2)
)
addr_2 = socket_2.getsockname()
# creating and immediately closing this to try to get an address that
# is not listening
socket_3 = create_socket()
transport_3, protocol_3 = loop.run_until_complete(
loop.create_datagram_endpoint(Protocol, sock=socket_3)
)
addr_3 = socket_3.getsockname()
transport_3.abort()
transport_1.sendto(b'a', addr=addr_2)
self.assertEqual(loop.run_until_complete(
protocol_2.wait_for_datagram_received()
), b'a')
transport_2.sendto(b'b', addr=addr_1)
self.assertEqual(loop.run_until_complete(
protocol_1.wait_for_datagram_received()
), b'b')
# this should send to an address that isn't listening
transport_1.sendto(b'c', addr=addr_3)
loop.run_until_complete(asyncio.sleep(0))
# transport 1 should still be able to receive messages after sending to
# an address that wasn't listening
transport_2.sendto(b'd', addr=addr_1)
self.assertEqual(loop.run_until_complete(
protocol_1.wait_for_datagram_received()
), b'd')
transport_1.close()
transport_2.close()
def test_internal_fds(self):
loop = self.create_event_loop()
if not isinstance(loop, selector_events.BaseSelectorEventLoop):