bpo-35545: Fix asyncio discarding IPv6 scopes #11271
Conversation
|
Please add a NEWS file. |
|
@asvetlov what do you think? |
asvetlov
left a comment
There was a problem hiding this comment.
I think we need NEWs entry, everything is fine.
|
@lepaperwan there is a possibility to merge the PR as is but if you add a simple regression test it would be awesome! |
|
Thanks for the PR. From my understanding, the test can create asyncio local server, connect to it and check the socket peer name or something like this. |
|
Sure, I can't get around to it today but I'll fix the tests to avoid mocks
sometime this week.
…On Tue, May 14, 2019, 14:50 Andrew Svetlov ***@***.***> wrote:
Thanks for the PR.
I know asyncio is full of mock-based tests but we are working to get rid
of them where is possible.
The reason is: *real* tests are much more stable on changing asyncio
internals but mocked tests require fixes to reflect new objects
structure/methods/signatures etc.
From my understanding, the test can create asyncio local server, connect
to it and check the socket peer name or something like this.
Would you try this strategy?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#11271?email_source=notifications&email_token=ACB2HO3VS533R36J6QDIER3PVKYPVA5CNFSM4GLUJVY2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODVLLVCQ#issuecomment-492223114>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ACB2HO77MBGWPQ3AFRUDFVDPVKYPVANCNFSM4GLUJVYQ>
.
|
|
I hadn't thought this through the other night while answering so I'll try to make this as complete as possible. Testing that the scope is properly kept through the internals of Should it be the case, the test would have to either dynamically acquire that IP and use it to bind the server, or know it beforehand and have it hardcoded. Binding to an invalid address, of course, fails. >>> import socket
>>> s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
>>> s.bind(("fe80::1", 80, 0, 1))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 99] Cannot assign requested addressAnother solution is to rely on scoped IPs failing to be used if the scope ID is not explicitly given. >>> import socket
>>> s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
>>> s.connect(("fe80::1", 80))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 22] Invalid argumentHowever if there is no server to answer, as expected, the call fails as well. >>> import socket
>>> s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
>>> s.connect(("fe80::1", 80, 0, 1))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ConnectionRefusedError: [Errno 111] Connection refusedAnd if that interface doesn't have a scoped address, it fails as well. >>> import socket
>>> s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
>>> s.connect(("fe80::1", 80, 0, 1))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 101] Network is unreachableThe >>> import asyncio
>>> asyncio.run(asyncio.open_connection("fe80::1%1", 80))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.7/asyncio/runners.py", line 43, in run
return loop.run_until_complete(main)
File "/usr/local/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
return future.result()
File "/usr/local/lib/python3.7/asyncio/streams.py", line 77, in open_connection
lambda: protocol, host, port, **kwds)
File "/usr/local/lib/python3.7/asyncio/base_events.py", line 959, in create_connection
raise exceptions[0]
File "/usr/local/lib/python3.7/asyncio/base_events.py", line 946, in create_connection
await self.sock_connect(sock, address)
File "/usr/local/lib/python3.7/asyncio/selector_events.py", line 464, in sock_connect
return await fut
File "/usr/local/lib/python3.7/asyncio/selector_events.py", line 469, in _sock_connect
sock.connect(address)
OSError: [Errno 22] Invalid argumentImposing additional constraints on the test host isn't ideal because while it might be possible to setup the CIs appropriately, it isn't desirable and contributors might not have identical setups. I'm not certain what Python's test policy is at this stage. I'd assume expecting errors for anything other than error detection/handling isn't great, constraining the test host isn't great, and mocks aren't great either. If anyone has ideas on how to best go about testing this please chime in :) |
|
Sorry, I've missed the fact that IPv6 scopes require specific host configuration. Thank you very much for your contribution! |
|
Thanks @lepaperwan for the PR 🌮🎉.. I'm working now to backport this PR to: 3.7. |
|
GH-13379 is a backport of this pull request to the 3.7 branch. |
This PR proposes a solution to [bpo-35545](https://bugs.python.org/issue35545) by adding an optional `flowinfo` and `scopeid` to `asyncio.base_events._ipaddr_info` to carry the full address information into `_ipaddr_info` and avoid discarding IPv6 specific information. Changelog entry & regression tests to come. https://bugs.python.org/issue35545 (cherry picked from commit ac8eb8f) Co-authored-by: Erwan Le Pape <lepaperwan@users.noreply.github.com>
This PR proposes a solution to [bpo-35545](https://bugs.python.org/issue35545) by adding an optional `flowinfo` and `scopeid` to `asyncio.base_events._ipaddr_info` to carry the full address information into `_ipaddr_info` and avoid discarding IPv6 specific information. Changelog entry & regression tests to come. https://bugs.python.org/issue35545 (cherry picked from commit ac8eb8f) Co-authored-by: Erwan Le Pape <lepaperwan@users.noreply.github.com>
This PR proposes a solution to bpo-35545 by adding an optional
flowinfoandscopeidtoasyncio.base_events._ipaddr_infoto carry the full address information into_ipaddr_infoand avoid discarding IPv6 specific information.Changelog entry & regression tests to come.
https://bugs.python.org/issue35545