4747# MQTT Commands
4848MQTT_PINGREQ = b"\xc0 \0 "
4949MQTT_PINGRESP = const (0xD0 )
50+ MQTT_PUBLISH = const (0x30 )
5051MQTT_SUB = b"\x82 "
5152MQTT_UNSUB = b"\xA2 "
5253MQTT_DISCONNECT = b"\xe0 \0 "
5354
55+ MQTT_PKT_TYPE_MASK = const (0xF0 )
56+
5457# Variable CONNECT header [MQTT 3.1.2]
5558MQTT_HDR_CONNECT = bytearray (b"\x04 MQTT\x04 \x02 \0 \0 " )
5659
@@ -210,7 +213,6 @@ def __init__(
210213 # LWT
211214 self ._lw_topic = None
212215 self ._lw_qos = 0
213- self ._lw_topic = None
214216 self ._lw_msg = None
215217 self ._lw_retain = False
216218
@@ -628,7 +630,7 @@ def publish(self, topic, msg, retain=False, qos=0):
628630 ), "Quality of Service Level 2 is unsupported by this library."
629631
630632 # fixed header. [3.3.1.2], [3.3.1.3]
631- pub_hdr_fixed = bytearray ([0x30 | retain | qos << 1 ])
633+ pub_hdr_fixed = bytearray ([MQTT_PUBLISH | retain | qos << 1 ])
632634
633635 # variable header = 2-byte Topic length (big endian)
634636 pub_hdr_var = bytearray (struct .pack (">H" , len (topic .encode ("utf-8" ))))
@@ -877,7 +879,9 @@ def loop(self, timeout=0):
877879 def _wait_for_msg (self , timeout = 0.1 ):
878880 # pylint: disable = too-many-return-statements
879881
880- """Reads and processes network events."""
882+ """Reads and processes network events.
883+ Return the packet type or None if there is nothing to be received.
884+ """
881885 # CPython socket module contains a timeout attribute
882886 if hasattr (self ._socket_pool , "timeout" ):
883887 try :
@@ -898,7 +902,7 @@ def _wait_for_msg(self, timeout=0.1):
898902 if res in [None , b"" , b"\x00 " ]:
899903 # If we get here, it means that there is nothing to be received
900904 return None
901- if res [0 ] == MQTT_PINGRESP :
905+ if res [0 ] & MQTT_PKT_TYPE_MASK == MQTT_PINGRESP :
902906 if self .logger is not None :
903907 self .logger .debug ("Got PINGRESP" )
904908 sz = self ._sock_exact_recv (1 )[0 ]
@@ -907,12 +911,21 @@ def _wait_for_msg(self, timeout=0.1):
907911 "Unexpected PINGRESP returned from broker: {}." .format (sz )
908912 )
909913 return MQTT_PINGRESP
910- if res [0 ] & 0xF0 != 0x30 :
914+
915+ if res [0 ] & MQTT_PKT_TYPE_MASK != MQTT_PUBLISH :
911916 return res [0 ]
917+
918+ # Handle only the PUBLISH packet type from now on.
912919 sz = self ._recv_len ()
913920 # topic length MSB & LSB
914921 topic_len = self ._sock_exact_recv (2 )
915922 topic_len = (topic_len [0 ] << 8 ) | topic_len [1 ]
923+
924+ if topic_len > sz - 2 :
925+ raise MMQTTException (
926+ f"Topic length { topic_len } in PUBLISH packet exceeds remaining length { sz } - 2"
927+ )
928+
916929 topic = self ._sock_exact_recv (topic_len )
917930 topic = str (topic , "utf-8" )
918931 sz -= topic_len + 2
@@ -921,12 +934,13 @@ def _wait_for_msg(self, timeout=0.1):
921934 pid = self ._sock_exact_recv (2 )
922935 pid = pid [0 ] << 0x08 | pid [1 ]
923936 sz -= 0x02
937+
924938 # read message contents
925939 raw_msg = self ._sock_exact_recv (sz )
926940 msg = raw_msg if self ._use_binary_mode else str (raw_msg , "utf-8" )
927941 if self .logger is not None :
928942 self .logger .debug (
929- "Receiving SUBSCRIBE \n Topic: %s\n Msg: %s\n " , topic , raw_msg
943+ "Receiving PUBLISH \n Topic: %s\n Msg: %s\n " , topic , raw_msg
930944 )
931945 self ._handle_on_message (self , topic , msg )
932946 if res [0 ] & 0x06 == 0x02 :
@@ -935,6 +949,7 @@ def _wait_for_msg(self, timeout=0.1):
935949 self ._sock .send (pkt )
936950 elif res [0 ] & 6 == 4 :
937951 assert 0
952+
938953 return res [0 ]
939954
940955 def _recv_len (self ):
0 commit comments