classification
Title: loop.create_server does not detect if the interface is IPv6 enabled
Type: behavior Stage:
Components: asyncio Versions: Python 3.7, Python 3.6, Python 3.5
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: cecton, pitrou, yselivanov
Priority: normal Keywords: patch

Created on 2017-07-17 10:04 by cecton, last changed 2017-07-20 12:46 by pitrou.

Files
File name Uploaded Description Edit
test_ipv6.py cecton, 2017-07-17 10:04 Example file to reproduce the issue
eaddrnotavail_asyncio.patch pitrou, 2017-07-20 11:34
Messages (6)
msg298474 - (view) Author: Cecile Tonglet (cecton) Date: 2017-07-17 10:04
The IPv6 detection in asyncio.base_events.create_server only detect if IPv6 is available instead of checking if the interface can actually support it.

I noticed that by using Python in a Docker container (example code to reproduce in attachment):


docker run -it --rm -v /tmp/test_ipv6.py:/src/test_ipv6.py python:3.6 python /src/test_ipv6.py


Will result in:


Traceback (most recent call last):
  File "/usr/local/lib/python3.6/asyncio/base_events.py", line 1043, in create_server
    sock.bind(sa)
OSError: [Errno 99] Cannot assign requested address

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/src/test_ipv6.py", line 11, in <module>
    server = loop.run_until_complete(server_creation)
  File "/usr/local/lib/python3.6/asyncio/base_events.py", line 466, in run_until_complete
    return future.result()
  File "/usr/local/lib/python3.6/asyncio/base_events.py", line 1047, in create_server
    % (sa, err.strerror.lower()))
OSError: [Errno 99] error while attempting to bind on address ('::1', 27015, 0, 0): cannot assign requested address


By default Docker containers have only IPv4 enabled:


1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
38: eth0@if39: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 scope global eth0
       valid_lft forever preferred_lft forever


I believe this detection mechanism should rely on the interface requested. I found this on the web for Python 2 that manage to get the info per interface: https://pastebin.com/VEnhF1Ht but it's using an external library.

However if you change the hostname to 127.0.0.1 it works normally.
msg298683 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2017-07-19 17:51
Better than trying to detect IPv6 compatibility beforehand would probably to recognize the error and simply ignore it.

Note: errno 99 is EADDRNOTAVAIL.

Something like this could work (untested):

diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py
index 33b8f48..413161a 100644
--- a/Lib/asyncio/base_events.py
+++ b/Lib/asyncio/base_events.py
@@ -1038,6 +1038,11 @@ class BaseEventLoop(events.AbstractEventLoop):
                     try:
                         sock.bind(sa)
                     except OSError as err:
+                        if err.errno == errno.EADDRNOTAVAIL:
+                            # See bpo-30945
+                            sockets.pop()
+                            sock.close()
+                            continue
                         raise OSError(err.errno, 'error while attempting '
                                       'to bind on address %r: %s'
                                       % (sa, err.strerror.lower())) from None
msg298684 - (view) Author: Yury Selivanov (yselivanov) * (Python committer) Date: 2017-07-19 17:54
> Better than trying to detect IPv6 compatibility beforehand would probably to recognize the error and simply ignore it.


+1
msg298714 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2017-07-20 11:34
Cécile, could you try the following patch?  I have no easy way to test here.
msg298716 - (view) Author: Cecile Tonglet (cecton) Date: 2017-07-20 11:57
Sure! It seems to work, the process returns an exit code of 0 and I see no traceback but the message is still displayed in the terminal.

(Also I did something weird because your patch applies on branch master and I ran it with Python 3.6... I suppose it shouldn't be a problem)


[0] [11:54:13] /tmp > d run -it --rm -v /tmp:/tmp:ro -v ~/repos/cpython/Lib/asyncio:/usr/local/lib/python3.6/asyncio:ro python:3.6 python /tmp/test_ipv6.py
error while attempting to bind on address ('::1', 27015, 0, 0): cannot assign requested address
[0] [11:54:19] /tmp > d run -it --rm -v /tmp:/tmp:ro python:3.6 python /tmp/test_ipv6.py
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/asyncio/base_events.py", line 1043, in create_server
    sock.bind(sa)
OSError: [Errno 99] Cannot assign requested address

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/tmp/test_ipv6.py", line 11, in <module>
    server = loop.run_until_complete(server_creation)
  File "/usr/local/lib/python3.6/asyncio/base_events.py", line 466, in run_until_complete
    return future.result()
  File "/usr/local/lib/python3.6/asyncio/base_events.py", line 1047, in create_server
    % (sa, err.strerror.lower()))
OSError: [Errno 99] error while attempting to bind on address ('::1', 27015, 0, 0): cannot assign requested address
[1] [11:54:52] /tmp >
msg298718 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2017-07-20 12:46
Cécile, thank you.  The reason the message is still displayed is that I turned the error into a warning (in other words, it is expected).
History
Date User Action Args
2017-07-20 12:46:05pitrousetmessages: + msg298718
2017-07-20 11:57:41cectonsetmessages: + msg298716
2017-07-20 11:34:42pitrousetfiles: + eaddrnotavail_asyncio.patch
keywords: + patch
messages: + msg298714
2017-07-19 17:54:25yselivanovsetmessages: + msg298684
2017-07-19 17:51:14pitrousetnosy: + pitrou

messages: + msg298683
versions: + Python 3.7, - Python 3.4
2017-07-17 10:04:34cectoncreate