chrysn / aiocoap

The Python CoAP library
Other
262 stars 119 forks source link

CoAP-over-WebSockets stalls on unclean shutdown #315

Open chrysn opened 11 months ago

chrysn commented 11 months ago

Start at this setup:

$ ./aiocoap-rd --proxy-domain proxy.example.net &
$ ./aiocoap-widgets --register coap+ws://localhost:8683 --anyport --register-proxy

(similar to #314). GETting some resource through a proxy works fine, and it also works fine if the WebSocket connection is shut down cleanly (as it happens with aiocoap-widgets when Ctrl-C is pressed or the window is closed). However, when the process is kill -9'd, which terminates the TCP connection without going through the CoAP shutdown dance, we get this error situation:

ERROR:coap-server:Sending to a WebSocket should not raise errors
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/websockets/legacy/protocol.py", line 968, in transfer_data
    message = await self.read_message()
              ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/websockets/legacy/protocol.py", line 1038, in read_message
    frame = await self.read_data_frame(max_size=self.max_size)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/websockets/legacy/protocol.py", line 1113, in read_data_frame
    frame = await self.read_frame(max_size)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/websockets/legacy/protocol.py", line 1170, in read_frame
    frame = await Frame.read(
            ^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/websockets/legacy/framing.py", line 69, in read
    data = await reader(2)
           ^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/asyncio/streams.py", line 727, in readexactly
    raise exceptions.IncompleteReadError(incomplete, n)
asyncio.exceptions.IncompleteReadError: 0 bytes read on a total of 2 expected bytes

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/chrysn/git/aiocoap/aiocoap/transports/ws.py", line 174, in send
    await self._connection.send(_serialize(msg))
  File "/usr/lib/python3/dist-packages/websockets/legacy/protocol.py", line 635, in send
    await self.ensure_open()
  File "/usr/lib/python3/dist-packages/websockets/legacy/protocol.py", line 944, in ensure_open
    raise self.connection_closed_exc()
websockets.exceptions.ConnectionClosedError: no close frame received or sent

The proper behavior would be to err as in all clean shutdown situations; at most, there should be an info or warning message in the RD's log.