I am using:
listen = '127.0.0.1:6543 [::1]:6543'
Now, if I do not have internet connectivity (aeroplane coding mode for example), waitress crashes with:
Traceback (most recent call last):
File "/.../venv/lib/python3.5/site-packages/waitress/adjustments.py", line 258, in __init__
socket.AI_PASSIVE | socket.AI_ADDRCONFIG
File "/usr/lib/python3.5/socket.py", line 732, in getaddrinfo
for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno -9] Address family for hostname not supported
This even though the reverses for 127.0.0.1 and ::1 are in /etc/hosts, and they are the names that are displayed on the Serving message. That is, if I change them to localhost123 and ip6-localhost123, and I have internet connectivity, waitress displays:
Serving on http://localhost123:6543
Serving on http://ip6-localhost123:6543
This is because of AI_ADDRCONFIG:
If hints.ai_flags includes the AI_ADDRCONFIG flag, then IPv4 addresses are returned in the list pointed to by res only if the local system has at least one IPv4 address configured, and IPv6
addresses are returned only if the local system has at least one IPv6 address configured. The loopback address is not considered for this case as valid as a configured address. This flag is
useful on, for example, IPv4-only systems, to ensure that getaddrinfo() does not return IPv6 socket addresses that would always fail in connect(2) or bind(2).
and since there is no internet connectivity, no IP address is configured on any other interface except loopback. Perhaps it should be changed so that if AI_ADDRCONFIG fails then either
Now I believe the correct option should be to drop AI_ADDRCONFIG altogether. The reason for using AI_ADDRCONFIG is to ensure that you're not resolving only IPv6 addresses on a machine that doesn't have IPv6 connection to outside, or IPv4 on a machine with no IPv4 connectivity. Since all of the resolved addresses are bound to, it doesn't matter whether they're only internal. The only case is if you have only IPv6 addressing inside your network with no IPv4 addressing within the network and only IPv4 addressing outside and you're binding by a hostname, or you have IPv6 completely disabled on your system, even on localhost, but getaddrinfo still offering IPv6 address for loopback interface.
I went back and forth on adding AI_ADDRCONFIG. It's probably the wrong thing to do when explicitly requesting localhost (either ::1 or 127.0.0.1) but when using a hostname that is then resolved using getaddrinfo() it is potentially the right thing to do...
For example, on OS X you could set your listen parameter to:
Where alexandra.network.lan is your local machines name, and a DNS entry that resolves. If the DNS server has stale data due to DHCPv6 not having updated it, it's possible it will return an IPv6 address that is invalid for the machine and attempting to bind() to all results without AI_ADDRCONFIG would do the wrong thing. I'll admit it is an example of a broken local network, but it is an issue I ran into.
At this point, I can agree to dropping AI_ADDRCONFIG, if your local network is misconfigured that's not something I really should try to protect against. I will NOT be adding AI_NUMERICHOST because it disallows the use of hostnames in getaddrfinfo() and I want to allow the user to say listen = localhost:8080 and listen on whatever addresses are returned for that (generally 127.0.0.1 and ::1 unless you are on some flavour of linux that uses ip6-localhost).
listen = localhost:8080
Regarding the "Serving on" messages. Those are found by getting the name info for the IP address that is bound to, basically doing a reverse DNS query, including what is in /etc/hosts.
Thanks for your report, will get a fix out by the end of today! Appreciate the testing!
Ah, the AI_NUMERICHOST would have been
addressses = getaddrinfo(...|AI_ADDRCONFIG)
addresses = getaddrinfo(...|AI_NUMERICHOST)
and let the exception propagate only when both of them fail.
It's not really required though, by default getaddrinfo does the right thing when you pass it a numeric host or non-numeric. Also that still wouldn't support the use case of:
listen = localhost:8080
Because it would fail on theAI_ ADDRCONFIG when the user has no network connectivity, and it isn't a numeric host so it would fail on the AI_NUMERICHOST.