7373MQTT_PKT_TYPE_MASK = const (0xF0 )
7474
7575
76+ CONNACK_ERROR_INCORRECT_PROTOCOL = const (0x01 )
77+ CONNACK_ERROR_ID_REJECTED = const (0x02 )
78+ CONNACK_ERROR_SERVER_UNAVAILABLE = const (0x03 )
79+ CONNACK_ERROR_INCORECT_USERNAME_PASSWORD = const (0x04 )
80+ CONNACK_ERROR_UNAUTHORIZED = const (0x05 )
81+
7682CONNACK_ERRORS = {
77- const ( 0x01 ) : "Connection Refused - Incorrect Protocol Version" ,
78- const ( 0x02 ) : "Connection Refused - ID Rejected" ,
79- const ( 0x03 ) : "Connection Refused - Server unavailable" ,
80- const ( 0x04 ) : "Connection Refused - Incorrect username/password" ,
81- const ( 0x05 ) : "Connection Refused - Unauthorized" ,
83+ CONNACK_ERROR_INCORRECT_PROTOCOL : "Connection Refused - Incorrect Protocol Version" ,
84+ CONNACK_ERROR_ID_REJECTED : "Connection Refused - ID Rejected" ,
85+ CONNACK_ERROR_SERVER_UNAVAILABLE : "Connection Refused - Server unavailable" ,
86+ CONNACK_ERROR_INCORECT_USERNAME_PASSWORD : "Connection Refused - Incorrect username/password" ,
87+ CONNACK_ERROR_UNAUTHORIZED : "Connection Refused - Unauthorized" ,
8288}
8389
8490_default_sock = None # pylint: disable=invalid-name
8894class MMQTTException (Exception ):
8995 """MiniMQTT Exception class."""
9096
97+ def __init__ (self , error , code = None ):
98+ super ().__init__ (error , code )
99+ self .code = code
100+
91101
92102class NullLogger :
93103 """Fake logger class that does not do anything"""
@@ -397,21 +407,31 @@ def connect(
397407 )
398408 self ._reset_reconnect_backoff ()
399409 return ret
400- except RuntimeError as e :
410+ except (MemoryError , OSError , RuntimeError ) as e :
411+ if isinstance (e , RuntimeError ) and e .args == ("pystack exhausted" ,):
412+ raise
401413 self .logger .warning (f"Socket error when connecting: { e } " )
414+ last_exception = e
402415 backoff = False
403416 except MMQTTException as e :
404- last_exception = e
417+ self . _close_socket ()
405418 self .logger .info (f"MMQT error: { e } " )
419+ if e .code in [
420+ CONNACK_ERROR_INCORECT_USERNAME_PASSWORD ,
421+ CONNACK_ERROR_UNAUTHORIZED ,
422+ ]:
423+ # No sense trying these again, re-raise
424+ raise
425+ last_exception = e
406426 backoff = True
407427
408428 if self ._reconnect_attempts_max > 1 :
409429 exc_msg = "Repeated connect failures"
410430 else :
411431 exc_msg = "Connect failure"
432+
412433 if last_exception :
413434 raise MMQTTException (exc_msg ) from last_exception
414-
415435 raise MMQTTException (exc_msg )
416436
417437 # pylint: disable=too-many-branches, too-many-statements, too-many-locals
@@ -508,7 +528,7 @@ def _connect(
508528 rc = self ._sock_exact_recv (3 )
509529 assert rc [0 ] == 0x02
510530 if rc [2 ] != 0x00 :
511- raise MMQTTException (CONNACK_ERRORS [rc [2 ]])
531+ raise MMQTTException (CONNACK_ERRORS [rc [2 ]], code = rc [ 2 ] )
512532 self ._is_connected = True
513533 result = rc [0 ] & 1
514534 if self .on_connect is not None :
@@ -522,6 +542,12 @@ def _connect(
522542 f"No data received from broker for { self ._recv_timeout } seconds."
523543 )
524544
545+ def _close_socket (self ):
546+ if self ._sock :
547+ self .logger .debug ("Closing socket" )
548+ self ._connection_manager .close_socket (self ._sock )
549+ self ._sock = None
550+
525551 # pylint: disable=no-self-use
526552 def _encode_remaining_length (
527553 self , fixed_header : bytearray , remaining_length : int
@@ -550,8 +576,7 @@ def disconnect(self) -> None:
550576 self ._sock .send (MQTT_DISCONNECT )
551577 except RuntimeError as e :
552578 self .logger .warning (f"Unable to send DISCONNECT packet: { e } " )
553- self .logger .debug ("Closing socket" )
554- self ._connection_manager .close_socket (self ._sock )
579+ self ._close_socket ()
555580 self ._is_connected = False
556581 self ._subscribed_topics = []
557582 self ._last_msg_sent_timestamp = 0
@@ -568,6 +593,7 @@ def ping(self) -> list[int]:
568593 self ._sock .send (MQTT_PINGREQ )
569594 ping_timeout = self .keep_alive
570595 stamp = ticks_ms ()
596+
571597 self ._last_msg_sent_timestamp = stamp
572598 rc , rcs = None , []
573599 while rc != MQTT_PINGRESP :
@@ -946,7 +972,7 @@ def _wait_for_msg(self, timeout: Optional[float] = None) -> Optional[int]:
946972 res = self ._sock_exact_recv (1 )
947973 except self ._socket_pool .timeout :
948974 return None
949- else : # socketpool, esp32spi
975+ else : # socketpool, esp32spi, wiznet5k
950976 try :
951977 res = self ._sock_exact_recv (1 , timeout = timeout )
952978 except OSError as error :
@@ -1035,14 +1061,14 @@ def _sock_exact_recv(
10351061 """
10361062 stamp = ticks_ms ()
10371063 if not self ._backwards_compatible_sock :
1038- # CPython/Socketpool Impl.
1064+ # CPython, socketpool, esp32spi, wiznet5k
10391065 rc = bytearray (bufsize )
10401066 mv = memoryview (rc )
10411067 recv_len = self ._sock .recv_into (rc , bufsize )
10421068 to_read = bufsize - recv_len
10431069 if to_read < 0 :
10441070 raise MMQTTException (f"negative number of bytes to read: { to_read } " )
1045- read_timeout = timeout if timeout is not None else self .keep_alive
1071+ read_timeout = timeout if timeout is not None else self ._recv_timeout
10461072 mv = mv [recv_len :]
10471073 while to_read > 0 :
10481074 recv_len = self ._sock .recv_into (mv , to_read )
@@ -1052,8 +1078,8 @@ def _sock_exact_recv(
10521078 raise MMQTTException (
10531079 f"Unable to receive { to_read } bytes within { read_timeout } seconds."
10541080 )
1055- else : # ESP32SPI Impl.
1056- # This will timeout with socket timeout (not keepalive timeout)
1081+ else : # Legacy: fona, esp_atcontrol
1082+ # This will time out with socket timeout (not receive timeout).
10571083 rc = self ._sock .recv (bufsize )
10581084 if not rc :
10591085 self .logger .debug ("_sock_exact_recv timeout" )
@@ -1063,7 +1089,7 @@ def _sock_exact_recv(
10631089 # or raise exception if wait longer than read_timeout
10641090 to_read = bufsize - len (rc )
10651091 assert to_read >= 0
1066- read_timeout = self .keep_alive
1092+ read_timeout = self ._recv_timeout
10671093 while to_read > 0 :
10681094 recv = self ._sock .recv (to_read )
10691095 to_read -= len (recv )
0 commit comments