chrysn / aiocoap

The Python CoAP library
Other
264 stars 119 forks source link

Multiple server contexts with selected transports #269

Closed roysjosh closed 2 years ago

roysjosh commented 2 years ago

I'm working on a Home Assistant component that needs to communicate with several devices at the same time. Additionally, the devices can push notifications which seems to require a server context with a Site attached to receive them. Unfortunately, another user who has the ws transport enabled is getting the following upon the creation of the second server context:

Traceback (most recent call last):
  File "/config/deps/lib/python3.9/site-packages/aiohomekit/controller/coap/connection.py", line 602, in connect
    await self.do_pair_verify(pairing_data)
  File "/config/deps/lib/python3.9/site-packages/aiohomekit/controller/coap/connection.py", line 557, in do_pair_verify
    coapClient = await Context.create_server_context(root, bind=('::',0))
  File "/usr/local/lib/python3.9/site-packages/aiocoap/protocol.py", line 293, in create_server_context
    await self._append_tokenmanaged_transport(
  File "/usr/local/lib/python3.9/site-packages/aiocoap/protocol.py", line 157, in _append_tokenmanaged_transport
    transport = await token_interface_constructor(tman)
  File "/usr/local/lib/python3.9/site-packages/aiocoap/transports/ws.py", line 191, in create_transport
    server = await websockets.serve(
  File "/usr/local/lib/python3.9/site-packages/websockets/legacy/server.py", line 1086, in __await_impl__
    server = await self._create_server()
  File "/usr/local/lib/python3.9/asyncio/base_events.py", line 1494, in create_server
    raise OSError(err.errno, 'error while attempting '
OSError: [Errno 98] error while attempting to bind on address ('::', 3000, 0, 0): address in use

This is in spite of me passing a bind=('::',0) parameter to the create_server_context call asking for a random port: https://github.com/Jc2k/aiohomekit/pull/52/files#diff-4d3bce65cb96997bae448f68447d41b128f33e8fbdffb019c73caa183ce28833R480

It looks like the ws transport doesn't know that 0 means random as it adds a fixed value of 3000 to ports that aren't None: https://github.com/chrysn/aiocoap/blob/master/aiocoap/transports/ws.py#L190

I don't think using an environment variable is a good solution here as that is process-wide and I don't know what other HA plugins might require. Do you think a transport= parameter to create_server_context would be an appropriate solution? Or would you prefer a fix to the ws transport? Both? Looking forward to your thoughts here. Thanks!

Python version: 3.9.9 (main, Nov 19 2021, 00:00:00)
[GCC 11.2.1 20210728 (Red Hat 11.2.1-1)]
aiocoap version: 0.4.1
Modules missing for subsystems:
    dtls: missing DTLSSocket
    oscore: missing cbor2, ge25519
    linkheader: missing LinkHeader
    prettyprint: missing LinkHeader, cbor2, termcolor, pygments
Python platform: linux
Default server transports:  tcpserver:tcpclient:tlsserver:tlsclient:udp6
Selected server transports: tcpserver:tcpclient:tlsserver:tlsclient:udp6
Default client transports:  tcpclient:tlsclient:udp6
Selected client transports: tcpclient:tlsclient:udp6
SO_REUSEPORT available (default, selected): True, True
TFenby commented 2 years ago

This is still referenced in the popular HASS thread about getting Nanoleaf working over HAP: https://community.home-assistant.io/t/homekit-accessory-protocol-hap-over-coap-udp-was-nanoleaf-essentials-bulb-via-thread-coap/335167/93

Just curious if @chrysn has seen this yet.

Jc2k commented 2 years ago

@roysjosh Until upstream responds, what happens if we just pass in -3000 instead of 0