Skip to content

Commit 53b1412

Browse files
authored
Merge pull request #190 from vladak/recv_timeout_vs_keep_alive
honor recv_timeout in _sock_exact_recv() and ping()
2 parents d412e9a + 5814fd0 commit 53b1412

File tree

2 files changed

+63
-5
lines changed

2 files changed

+63
-5
lines changed

adafruit_minimqtt/adafruit_minimqtt.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@ def ping(self) -> list[int]:
615615
self._connected()
616616
self.logger.debug("Sending PINGREQ")
617617
self._sock.send(MQTT_PINGREQ)
618-
ping_timeout = self.keep_alive
618+
ping_timeout = self._recv_timeout
619619
stamp = self.get_monotonic_time()
620620
self._last_msg_sent_timestamp = stamp
621621
rc, rcs = None, []
@@ -624,7 +624,9 @@ def ping(self) -> list[int]:
624624
if rc:
625625
rcs.append(rc)
626626
if self.get_monotonic_time() - stamp > ping_timeout:
627-
raise MMQTTException("PINGRESP not returned from broker.")
627+
raise MMQTTException(
628+
f"PINGRESP not returned from broker within {ping_timeout} seconds."
629+
)
628630
return rcs
629631

630632
# pylint: disable=too-many-branches, too-many-statements
@@ -1090,7 +1092,7 @@ def _sock_exact_recv(
10901092
to_read = bufsize - recv_len
10911093
if to_read < 0:
10921094
raise MMQTTException(f"negative number of bytes to read: {to_read}")
1093-
read_timeout = timeout if timeout is not None else self.keep_alive
1095+
read_timeout = timeout if timeout is not None else self._recv_timeout
10941096
mv = mv[recv_len:]
10951097
while to_read > 0:
10961098
recv_len = self._sock.recv_into(mv, to_read)
@@ -1101,7 +1103,7 @@ def _sock_exact_recv(
11011103
f"Unable to receive {to_read} bytes within {read_timeout} seconds."
11021104
)
11031105
else: # ESP32SPI Impl.
1104-
# This will timeout with socket timeout (not keepalive timeout)
1106+
# This will time out with socket timeout (not receive timeout).
11051107
rc = self._sock.recv(bufsize)
11061108
if not rc:
11071109
self.logger.debug("_sock_exact_recv timeout")
@@ -1111,7 +1113,7 @@ def _sock_exact_recv(
11111113
# or raise exception if wait longer than read_timeout
11121114
to_read = bufsize - len(rc)
11131115
assert to_read >= 0
1114-
read_timeout = self.keep_alive
1116+
read_timeout = self._recv_timeout
11151117
while to_read > 0:
11161118
recv = self._sock.recv(to_read)
11171119
to_read -= len(recv)

tests/test_recv_timeout.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# SPDX-FileCopyrightText: 2024 Vladimír Kotal
2+
#
3+
# SPDX-License-Identifier: Unlicense
4+
5+
"""receive timeout tests"""
6+
7+
import socket
8+
import time
9+
from unittest import TestCase, main
10+
from unittest.mock import Mock
11+
12+
import adafruit_minimqtt.adafruit_minimqtt as MQTT
13+
14+
15+
class RecvTimeout(TestCase):
16+
"""This class contains tests for receive timeout handling."""
17+
18+
def test_recv_timeout_vs_keepalive(self) -> None:
19+
"""verify that receive timeout as used via ping() is different to keep alive timeout"""
20+
21+
for side_effect in [lambda ret_buf, buf_size: 0, socket.timeout]:
22+
with self.subTest():
23+
host = "127.0.0.1"
24+
25+
recv_timeout = 4
26+
keep_alive = recv_timeout * 2
27+
mqtt_client = MQTT.MQTT(
28+
broker=host,
29+
socket_pool=socket,
30+
connect_retries=1,
31+
socket_timeout=recv_timeout // 2,
32+
recv_timeout=recv_timeout,
33+
keep_alive=keep_alive,
34+
)
35+
36+
# Create a mock socket that will accept anything and return nothing.
37+
socket_mock = Mock()
38+
socket_mock.recv_into = Mock(side_effect=side_effect)
39+
# pylint: disable=protected-access
40+
mqtt_client._sock = socket_mock
41+
42+
mqtt_client._connected = lambda: True
43+
start = time.monotonic()
44+
with self.assertRaises(MQTT.MMQTTException):
45+
mqtt_client.ping()
46+
47+
# Verify the mock interactions.
48+
socket_mock.send.assert_called_once()
49+
socket_mock.recv_into.assert_called()
50+
51+
now = time.monotonic()
52+
assert recv_timeout <= (now - start) < keep_alive
53+
54+
55+
if __name__ == "__main__":
56+
main()

0 commit comments

Comments
 (0)