|
1 | 1 | # The MIT License (MIT)
|
2 | 2 | #
|
3 |
| -# Copyright (c) 2019 Brent Rubell for Adafruit Industries |
| 3 | +# Copyright (c) 2019-2021 Brent Rubell for Adafruit Industries |
4 | 4 | #
|
5 | 5 | # Original Work Copyright (c) 2016 Paul Sokolovsky, uMQTT
|
6 | 6 | # Modified Work Copyright (c) 2019 Bradley Beach, esp32spi_mqtt
|
|
36 | 36 |
|
37 | 37 | Adapted from https://github.com/micropython/micropython-lib/tree/master/umqtt.simple/umqtt
|
38 | 38 |
|
39 |
| -micropython-lib consists of multiple modules from different sources and |
40 |
| -authors. Each module comes under its own licensing terms. Short name of |
41 |
| -a license can be found in a file within a module directory (usually |
42 |
| -metadata.txt or setup.py). Complete text of each license used is provided |
43 |
| -at https://github.com/micropython/micropython-lib/blob/master/LICENSE |
44 |
| -
|
45 |
| -author='Paul Sokolovsky' |
46 |
| -license='MIT' |
47 | 39 | **Software and Dependencies:**
|
48 | 40 |
|
49 | 41 | * Adafruit CircuitPython firmware for the supported boards:
|
@@ -95,8 +87,7 @@ class MMQTTException(Exception):
|
95 | 87 | # pass
|
96 | 88 |
|
97 | 89 |
|
98 |
| -# Legacy Socket API |
99 |
| - |
| 90 | +# Legacy ESP32SPI Socket API |
100 | 91 | def set_socket(sock, iface=None):
|
101 | 92 | """Legacy API for setting the socket and network interface, use a `Session` instead.
|
102 | 93 |
|
@@ -237,8 +228,6 @@ def __init__(
|
237 | 228 | self.on_subscribe = None
|
238 | 229 | self.on_unsubscribe = None
|
239 | 230 |
|
240 |
| - # Shared buffer |
241 |
| - self._rx_length = 0 |
242 | 231 | self._rx_buffer = bytearray(32)
|
243 | 232 |
|
244 | 233 | # Socket helpers
|
@@ -516,14 +505,14 @@ def connect(self, clean_session=True, host=None, port=None, keep_alive=None):
|
516 | 505 | while True:
|
517 | 506 | op = self._wait_for_msg()
|
518 | 507 | if op == 32:
|
519 |
| - self._recv_into(buf, 3) |
520 |
| - assert buf[0] == 0x02 |
521 |
| - if buf[2] != 0x00: |
522 |
| - raise MMQTTException(CONNACK_ERRORS[buf[2]]) |
| 508 | + rc = self._sock_exact_recv(3) |
| 509 | + assert rc[0] == 0x02 |
| 510 | + if rc[2] != 0x00: |
| 511 | + raise MMQTTException(CONNACK_ERRORS[rc[2]]) |
523 | 512 | self._is_connected = True
|
524 |
| - result = buf[0] & 1 |
| 513 | + result = rc[0] & 1 |
525 | 514 | if self.on_connect is not None:
|
526 |
| - self.on_connect(self, self._user_data, result, buf[2]) |
| 515 | + self.on_connect(self, self._user_data, result, rc[2]) |
527 | 516 | return result
|
528 | 517 |
|
529 | 518 | def disconnect(self):
|
@@ -945,6 +934,41 @@ def _recv_into(self, buf, size=0):
|
945 | 934 | return read_size
|
946 | 935 | return self._sock.recv_into(buf, size)
|
947 | 936 |
|
| 937 | + def _sock_exact_recv(self, bufsize): |
| 938 | + """Reads _exact_ number of bytes from the connected socket. Will only return |
| 939 | + string with the exact number of bytes requested. |
| 940 | +
|
| 941 | + The semantics of native socket receive is that it returns no more than the |
| 942 | + specified number of bytes (i.e. max size). However, it makes no guarantees in |
| 943 | + terms of the minimum size of the buffer, which could be 1 byte. This is a |
| 944 | + wrapper for socket recv() to ensure that no less than the expected number of |
| 945 | + bytes is returned or trigger a timeout exception. |
| 946 | + :param int bufsize: number of bytes to receive |
| 947 | +
|
| 948 | + """ |
| 949 | + if not self._backwards_compatible_sock: |
| 950 | + # CPython/Socketpool Impl. |
| 951 | + rc = bytearray(bufsize) |
| 952 | + self._sock.recv_into(rc, bufsize) |
| 953 | + else: # ESP32SPI Impl. |
| 954 | + stamp = time.monotonic() |
| 955 | + read_timeout = self.keep_alive |
| 956 | + rc = self._sock.recv(bufsize) |
| 957 | + to_read = bufsize - len(rc) |
| 958 | + assert to_read >= 0 |
| 959 | + read_timeout = self.keep_alive |
| 960 | + while to_read > 0: |
| 961 | + recv = self._sock.recv(to_read) |
| 962 | + to_read -= len(recv) |
| 963 | + rc += recv |
| 964 | + if time.monotonic() - stamp > read_timeout: |
| 965 | + raise MMQTTException( |
| 966 | + "Unable to receive {} bytes within {} seconds.".format( |
| 967 | + to_read, read_timeout |
| 968 | + ) |
| 969 | + ) |
| 970 | + return rc |
| 971 | + |
948 | 972 | def _send_str(self, string):
|
949 | 973 | """Packs and encodes a string to a socket.
|
950 | 974 |
|
|
0 commit comments