adafruit / Adafruit_CircuitPython_MiniMQTT

MQTT Client Library for CircuitPython
Other
80 stars 49 forks source link

_wait_for_msg() on CPython with TLS connection raises ssl.SSLWantReadError on timeout #154

Open vladak opened 1 year ago

vladak commented 1 year ago

When connected via TLS, i.e. the socket is wrapped using the ssl_context and if there is nothing to be read in the loop, it results in:

Traceback (most recent call last):
  File "c.py", line 132, in <module>
    mqtt_client.loop()
  File "/Users/vladimirkotal/Pi/Adafruit_CircuitPython_MiniMQTT/adafruit_minimqtt/adafruit_minimqtt.py", line 955, in loop
    rc = self._wait_for_msg(timeout)
  File "/Users/vladimirkotal/Pi/Adafruit_CircuitPython_MiniMQTT/adafruit_minimqtt/adafruit_minimqtt.py", line 976, in _wait_for_msg
    res = self._sock_exact_recv(1)
  File "/Users/vladimirkotal/Pi/Adafruit_CircuitPython_MiniMQTT/adafruit_minimqtt/adafruit_minimqtt.py", line 1077, in _sock_exact_recv
    recv_len = self._sock.recv_into(rc, bufsize)
  File "/usr/local/Cellar/python@3.9/3.9.13_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/ssl.py", line 1242, in recv_into
    return self.read(nbytes, buffer)
  File "/usr/local/Cellar/python@3.9/3.9.13_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/ssl.py", line 1100, in read
    return self._sslobj.read(len, buffer)
ssl.SSLWantReadError: The operation did not complete (read) (_ssl.c:2633)

In such case, _wait_for_msg() should return None, however the ssl exception fires through: https://github.com/adafruit/Adafruit_CircuitPython_MiniMQTT/blob/342b8c99b2c8f10b605cc8311bf5f394f4d18e92/adafruit_minimqtt/adafruit_minimqtt.py#L967-L972

Note that the line numbers do not match because I am using minimqtt code for one of my PRs, however that should not matter.

Trouble is that the ssl.SSLWantReadError does not seem to be reachable from the ssl context passed to MQTT() init function. The exception class is based on OSError, however catching that would be too generic, I think.

brentru commented 1 year ago

@vladak This seems resolved via https://github.com/adafruit/circuitpython/pull/7632 and https://github.com/adafruit/circuitpython/pull/7779. Are you able to test on CircuitPython 8.1.0 Beta 1?

vladak commented 1 year ago

Actually, looking at the stack trace, this is a problem that seems to happen only with CPython.

brentru commented 1 year ago

@vladak
1) Could you clarify - are you expecting messages to be received? The REPL shows you exit from the loop() ("out from loop?"). 2) The issue title lists "CPython". Are you interested in re-testing that? If not, it's ok, I will.

brentru commented 1 year ago

@vladak btw - Thank you for your work, PRs, and issues reported on this library.

I've had different priorities since writing it (mostly working on Adafruit WipperSnapper). I am getting back to resolving issues with MiniMQTT and enhancing it starting next week.

vladak commented 1 year ago
  1. Could you clarify - are you expecting messages to be received? The REPL shows you exit from the loop() ("out from loop?").

The "Out from loop()" message simply means that the mqtt_client.loop(timeout=3) returned, so next iteration of the cycle will be done. See the code above.

For this case, I am not expecting any messages to be received withing the loop() (besides PINGRESP behind the scenes).

  1. The issue title lists "CPython". Are you interested in re-testing that? If not, it's ok, I will.

I've just tried that, still hitting the same issue.

vladak commented 1 year ago

btw - Thank you for your work, PRs, and issues reported on this library.

You are certainly welcome, I had fun doing that.

I've had different priorities since writing it (mostly working on Adafruit WipperSnapper). I am getting back to resolving issues with MiniMQTT and enhancing it starting next week.

Cool !