@@ -1373,6 +1373,80 @@ def test_create_datagram_endpoint_sock(self):
1373
1373
self .assertIsInstance (pr , MyDatagramProto )
1374
1374
tr .close ()
1375
1375
self .loop .run_until_complete (pr .done )
1376
+
1377
+ def test_datagram_send_to_non_listening_address (self ):
1378
+ # see:
1379
+ # https://github.com/python/cpython/issues/91227
1380
+ # https://github.com/python/cpython/issues/88906
1381
+ # https://bugs.python.org/issue47071
1382
+ # https://bugs.python.org/issue44743
1383
+ # The Proactor event loop would fail to receive datagram messages after
1384
+ # sending a message to an address that wasn't listening.
1385
+ loop = self .loop
1386
+
1387
+ class Protocol (asyncio .DatagramProtocol ):
1388
+
1389
+ _received_datagram = None
1390
+
1391
+ def datagram_received (self , data , addr ):
1392
+ self ._received_datagram .set_result (data )
1393
+
1394
+ async def wait_for_datagram_received (self ):
1395
+ self ._received_datagram = loop .create_future ()
1396
+ result = await asyncio .wait_for (self ._recevied_datagram , 10 )
1397
+ self ._received_datagram = None
1398
+ return result
1399
+
1400
+ transport_1 , protocol_1 = loop .run_until_complete (
1401
+ loop .create_datagram_endpoint (
1402
+ Protocol ,
1403
+ local_addr = ('127.0.0.1' , 0 )
1404
+ )
1405
+ )
1406
+ addr_1 = transport_1 .sockets [0 ].getsockname ()
1407
+
1408
+ transport_2 , protocol_2 = loop .run_until_complete (
1409
+ loop .create_datagram_endpoint (
1410
+ Protocol ,
1411
+ local_addr = ('127.0.0.1' , 0 )
1412
+ )
1413
+ )[0 ]
1414
+ addr_2 = transport_1 .sockets [0 ].getsockname ()
1415
+
1416
+ # creating and immediately closing this to try to get an address that
1417
+ # is not listening
1418
+ transport_3 , protocol_3 = loop .run_until_complete (
1419
+ loop .create_datagram_endpoint (
1420
+ Protocol ,
1421
+ local_addr = ('127.0.0.1' , 0 )
1422
+ )
1423
+ )[0 ]
1424
+ addr_3 = transport_1 .sockets [0 ].getsockname ()
1425
+ loop .run_until_complete (transport_3 .wait_closed ())
1426
+
1427
+ transport_1 .sendto (b'a' , addr = addr_2 )
1428
+ assert loop .run_until_complete (
1429
+ protocol_2 .wait_for_datagram_received ()
1430
+ ) == b'a'
1431
+
1432
+ transport_2 .sendto (b'b' , addr = addr_1 )
1433
+ assert loop .run_until_complete (
1434
+ protocol_1 .wait_for_datagram_received ()
1435
+ ) == b'b'
1436
+
1437
+ # this should send to an address that isn't listening
1438
+ transport_1 .sendto (b'c' , addr = addr_3 )
1439
+ loop .run_until_complete (asyncio .sleep (0 ))
1440
+
1441
+ # transport 1 should still be able to receive messages after sending to
1442
+ # an address that wasn't listening
1443
+ transport_2 .sendto (b'd' , addr = addr_1 )
1444
+ assert loop .run_until_complete (
1445
+ protocol_1 .wait_for_datagram_received ()
1446
+ ) == b'd'
1447
+
1448
+ loop .run_until_complete (transport_1 .wait_closed ())
1449
+ loop .run_until_complete (transport_2 .wait_closed ())
1376
1450
1377
1451
def test_internal_fds (self ):
1378
1452
loop = self .create_event_loop ()
0 commit comments