aiozeroconf icon indicating copy to clipboard operation
aiozeroconf copied to clipboard

Error when setting up on lo0

Open robbiet480 opened this issue 6 years ago • 13 comments

I initialize aiozeroconf like this:

from aiozeroconf import Zeroconf, ServiceInfo

zeroconf_name = '{}.{}'.format(hass.config.location_name, ZEROCONF_TYPE)

params = {
    'version': __version__,
    'base_url': hass.config.api.base_url,
    # always needs authentication
    'requires_api_password': True,
}

info = ServiceInfo(ZEROCONF_TYPE, zeroconf_name,
                   port=hass.http.server_port, properties=params)

zeroconf = Zeroconf(hass.loop)

await zeroconf.register_service(info)

I get this error upon launching (I slightly changed the Zeroconf.initialize function to set up interfaces one by one to isolate what went wrong): [aiozeroconf.aiozeroconf] initializing comm af 30 on interfaces ['lo0']: [Errno 49] Can't assign requested address.

Shortly after startup I get these errors too:

2019-05-15 14:27:17 ERROR (MainThread) [homeassistant.core] Error doing job: Exception in callback _SelectorDatagramTransport._read_ready()
Traceback (most recent call last):
  File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/events.py", line 88, in _run
    self._context.run(self._callback, *self._args)
  File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/selector_events.py", line 962, in _read_ready
    self._protocol.datagram_received(data, addr)
  File "/Users/robbiet480/Repos/HomeAssistant/home-assistant/venv/lib/python3.7/site-packages/aiozeroconf/aiozeroconf.py", line 1115, in datagram_received
    self.zc.handle_query(msg, resp_addr, _MDNS_PORT)
  File "/Users/robbiet480/Repos/HomeAssistant/home-assistant/venv/lib/python3.7/site-packages/aiozeroconf/aiozeroconf.py", line 2081, in handle_query
    self.send(out, addr, port)
  File "/Users/robbiet480/Repos/HomeAssistant/home-assistant/venv/lib/python3.7/site-packages/aiozeroconf/aiozeroconf.py", line 2085, in send
    packet = out.packet()
  File "/Users/robbiet480/Repos/HomeAssistant/home-assistant/venv/lib/python3.7/site-packages/aiozeroconf/aiozeroconf.py", line 998, in packet
    overrun_additionals += self.write_record(additional, 0)
  File "/Users/robbiet480/Repos/HomeAssistant/home-assistant/venv/lib/python3.7/site-packages/aiozeroconf/aiozeroconf.py", line 966, in write_record
    record.write(self)
  File "/Users/robbiet480/Repos/HomeAssistant/home-assistant/venv/lib/python3.7/site-packages/aiozeroconf/aiozeroconf.py", line 489, in write
    out.write_string(self.address)
  File "/Users/robbiet480/Repos/HomeAssistant/home-assistant/venv/lib/python3.7/site-packages/aiozeroconf/aiozeroconf.py", line 872, in write_string
    assert isinstance(value, bytes)
AssertionError

I'm on macOS 10.14.4.

$ ifconfig lo0
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
	options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
	inet 127.0.0.1 netmask 0xff000000
	inet6 ::1 prefixlen 128
	inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
	nd6 options=201<PERFORMNUD,DAD>

robbiet480 avatar May 15 '19 21:05 robbiet480

It looks like that error Error doing job: Exception in callback _SelectorDatagramTransport._read_ready() is related to me setting up interfaces one at a time to debug, so don't worry about that one.

robbiet480 avatar May 15 '19 21:05 robbiet480

I won't worry ;) In any case, using this library on lo0 is probably not really useful.

frawau avatar May 16 '19 05:05 frawau

@frawau Sure, but it throws a big red error message that's going to confuse our users. Can you either filter out that error message for lo0 or lower the log level from error to something not as scary?

robbiet480 avatar May 16 '19 05:05 robbiet480

I can also submit the PR to not throw the error on lo0 if you want.

robbiet480 avatar May 16 '19 05:05 robbiet480

Please do. I am one of the organisers of PyCon Thailand, and really busy right now.

frawau avatar May 16 '19 12:05 frawau

I dug more into this and this is what is happening:

aiozeroconf will detect it's own broadcasted service on each interface, and for some interfaces this is adddress will be None. Example:

ServiceInfo(type='_home-assistant._tcp.local.', name='Home._home-assistant._tcp.local.', address=None, port=8123, weight=0, priority=0, server='Home._home-assistant._tcp.local.', properties={'version': '0.94.0.dev0', 'base_url': 'http://192.168.1.234:8123', 'requires_api_password': True})

balloob avatar May 21 '19 12:05 balloob

Adding an interface ban list is not going to help, as we won't know in advance which interfaces will misbehave. (I have multiple that misbehave)

balloob avatar May 21 '19 12:05 balloob

This patch hides the error. I don't know if it hides an underlying issue though.

diff --git a/aiozeroconf/aiozeroconf.py b/aiozeroconf/aiozeroconf.py
index 8662c60..e1711b8 100644
--- a/aiozeroconf/aiozeroconf.py
+++ b/aiozeroconf/aiozeroconf.py
@@ -2068,7 +2068,8 @@ class Zeroconf(QuietLogger):
                         out.add_answer(msg, DNSText(
                             question.name, _TYPE_TXT, _CLASS_IN | _CLASS_UNIQUE,
                             _DNS_TTL, service.text))
-                    if question.type == _TYPE_SRV:
+                    if (question.type == _TYPE_SRV and
+                            service.address is not None):
                         out.add_additional_answer(DNSAddress(
                             service.server, _TYPE_A, _CLASS_IN | _CLASS_UNIQUE,
                             _DNS_TTL, service.address))

balloob avatar May 21 '19 12:05 balloob

Hi Paulus,

I had a look, and I am still not entirely sure what is going on. But I think I have a simple workaround.

Do something like

info = ServiceInfo(ZEROCONF_TYPE, zeroconf_name, address=b"", port=8123, properties=params)

For services you register. Just adding the address with an empty byte string.

I think it has to do with the fact that when receiving a "A" or "SRV" query, it should respond with the address of the interface on which the query was received, and that should be provided in the ServiceInfo.

But I am not entirely sure....

Regards, François

frawau avatar May 21 '19 14:05 frawau

If I add an empty byte string, I end up breaking a zeroconf consumer that I had running, which is trying to convert the address to an IP address using the ipaddress package in Python. So I think that it is a good indicator that passing an empty byte string is not a good idea.

I noticed this PR on python-zeroconf in which they behave the same as with my diff above: not forward any DNSAddress.

I don't know enough about zeroconf specifics, but isn't it weird that the code registering a service needs to know the IP address on each interface ?

balloob avatar May 21 '19 16:05 balloob

From the look of it, that PR adds "addresses", a list, and creates a record for each address in the list. But it does look that you still have to provide the addresses when creating the ServiceInfo.

I don't disagree with you, we should be able to automatically add the address of the interface that advertises the service. I did not work with this code for quite some time, and I am busy with PyCon Thailand (remember? I did ask you uf you could be a keynote). Hopefully I will find sometime this WE.

Cheers

frawau avatar May 22 '19 04:05 frawau

remember? I did ask you uf you could be a keynote

I remembered when I saw you mentioned it the first time 👍 Good luck with the conference !

balloob avatar May 23 '19 15:05 balloob

Hi,

I have a test version in branch dev_ha. This handles multiple A and AAAA records. When publishing a service, if no address is specified, it will add A and AAAA records for all the addresses of all the interfaces being used.

Be sure to read the commit message. Breaking change.

Let me know how it works.

Regards, François

frawau avatar May 25 '19 05:05 frawau