2 ******************************************************************* 3 Copyright (c) 2013, 2018 IBM Corp. 5 All rights reserved. This program and the accompanying materials 6 are made available under the terms of the Eclipse Public License v2.0 7 and Eclipse Distribution License v1.0 which accompany this distribution. 9 The Eclipse Public License is available at 10 https://www.eclipse.org/legal/epl-2.0/ 11 and the Eclipse Distribution License is available at 12 http://www.eclipse.org/org/documents/edl-v10.php. 15 Ian Craggs - initial implementation and/or documentation 16 ******************************************************************* 21 Assertions are used to validate incoming data, but are omitted from outgoing packets. This is 22 so that the tests that use this package can send invalid data for error testing. 28 logger = logging.getLogger(
"mqttsas")
37 CONNECT, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL, \
38 PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, \
39 PINGREQ, PINGRESP, DISCONNECT = range(1, 15)
41 packetNames = [
"reserved", \
42 "Connect",
"Connack",
"Publish",
"Puback",
"Pubrec",
"Pubrel", \
43 "Pubcomp",
"Subscribe",
"Suback",
"Unsubscribe",
"Unsuback", \
44 "Pingreq",
"Pingresp",
"Disconnect"]
46 classNames = [
"reserved", \
47 "Connects",
"Connacks",
"Publishes",
"Pubacks",
"Pubrecs",
"Pubrels", \
48 "Pubcomps",
"Subscribes",
"Subacks",
"Unsubscribes",
"Unsubacks", \
49 "Pingreqs",
"Pingresps",
"Disconnects"]
61 "receive the next packet" 65 if str(aSocket).
find(
"[closed]") != -1:
75 next = aSocket.recv(1)
77 next = aSocket.recv(1)
80 remlength += (digit & 127) * multiplier
87 while len(rest) < remlength:
88 rest += aSocket.recv(remlength-
len(rest))
89 assert len(rest) == remlength
104 self.
DUP == fh.DUP
and \
105 self.
QoS == fh.QoS
and \
110 "return printable stresentation of our data" 112 ", QoS="+str(self.
QoS)+
", Retain="+str(self.
RETAIN)
115 "pack data into string buffer ready for transmission down socket" 119 buffer += self.
encode(length)
123 assert 0 <= x <= 268435455
130 buffer +=
bytes([digit])
136 "unpack data from string buffer into separate fields" 139 self.
DUP = ((b0 >> 3) & 0x01) == 1
140 self.
QoS = (b0 >> 1) & 0x03
141 self.
RETAIN = (b0 & 0x01) == 1
153 value += (digit & 127) * multiplier
157 return (value, bytes)
161 return bytes([length // 256, length % 256])
164 return buf[0]*256 + buf[1]
168 return writeInt16(
len(data)) + (data
if type(data) == type(b
"")
else bytes(data,
"utf-8"))
178 buf = buffer[2:2+length].
decode(
"utf-8")
179 logger.info(
"[MQTT-4.7.3-2] topic names and filters not include null")
180 zz = buf.find(
"\x00")
182 raise MQTTException(
"[MQTT-1.5.3-2] Null found in UTF data "+buf)
183 for c
in range (0xD800, 0xDFFF):
184 zz = buf.find(chr(c))
186 raise MQTTException(
"[MQTT-1.5.3-1] D800-DFFF found in UTF data "+buf)
187 if buf.find(
"\uFEFF") != -1:
188 logger.info(
"[MQTT-1.5.3-3] U+FEFF in UTF string")
196 return buffer[2:2+length]
202 buffer = self.fh.pack(0)
209 return self.
fh == packet.fh
if packet
else False 252 buffer = self.fh.pack(
len(buffer)) + buffer
256 assert len(buffer) >= 2
260 fhlen = self.fh.unpack(buffer)
261 packlen = fhlen + self.fh.remainingLength
262 assert len(buffer) >= packlen,
"buffer length %d packet length %d" % (
len(buffer), packlen)
264 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1]" 265 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1] QoS was not 0, was %d" % self.fh.QoS
266 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1]" 275 connectFlags = buffer[curlen]
276 assert (connectFlags & 0x01) == 0,
"[MQTT-3.1.2-3] reserved connect flag must be 0" 278 self.
WillFlag = ((connectFlags >> 2) & 0x01) == 1
279 self.
WillQoS = (connectFlags >> 3) & 0x03
286 assert self.
WillQoS in [0, 1, 2],
"[MQTT-3.1.2-14] will qos must not be 3" 288 assert self.
WillQoS == 0,
"[MQTT-3.1.2-13] will qos must be 0, if will flag is false" 289 assert self.
WillRETAIN ==
False,
"[MQTT-3.1.2-14] will retain must be false, if will flag is false" 293 logger.info(
"[MQTT-3.1.3-3] Clientid must be present, and first field")
294 logger.info(
"[MQTT-3.1.3-4] Clientid must be Unicode, and between 0 and 65535 bytes long")
303 logger.info(
"[[MQTT-3.1.2-9] will topic and will message fields must be present")
308 assert len(buffer) > curlen+2,
"Buffer too short to read username length" 311 logger.info(
"[MQTT-3.1.2-19] username must be in payload if user name flag is 1")
313 logger.info(
"[MQTT-3.1.2-18] username must not be in payload if user name flag is 0")
314 assert self.
passwordFlag ==
False,
"[MQTT-3.1.2-22] password flag must be 0 if username flag is 0" 317 assert len(buffer) > curlen+2,
"Buffer too short to read password length" 320 logger.info(
"[MQTT-3.1.2-21] password must be in payload if password flag is 0")
322 logger.info(
"[MQTT-3.1.2-20] password must not be in payload if password flag is 0")
325 logger.info(
"[MQTT-3.1.3-1] clientid, will topic, will message, username and password all present")
327 assert curlen == packlen,
"Packet is wrong length curlen %d != packlen %d" 329 logger.exception(
"[MQTT-3.1.4-1] server must validate connect packet and close connection without connack if it does not conform")
335 buf = str(self.
fh)+
", ProtocolName="+str(self.
ProtocolName)+
", ProtocolVersion=" +\
337 ", WillFlag="+str(self.
WillFlag)+
", KeepAliveTimer=" +\
341 buf +=
", WillQoS=" + str(self.
WillQoS) +\
348 buf +=
", password="+str(self.
password)
352 rc = Packets.__eq__(self, packet)
and \
356 self.
WillFlag == packet.WillFlag
and \
361 rc = self.
WillQoS == packet.WillQoS
and \
370 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, ReturnCode=0):
374 self.fh.Retain = Retain
382 buffer = self.fh.pack(
len(buffer)) + buffer
386 assert len(buffer) >= 4
388 self.fh.unpack(buffer)
389 assert self.fh.remainingLength == 2,
"Connack packet is wrong length %d" % self.fh.remainingLength
390 assert buffer[2]
in [0, 1],
"Connect Acknowledge Flags" 392 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1]" 393 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1]" 394 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1]" 397 return str(self.
fh)+
", Session present="+str((self.
flags & 0x01) == 1)+
", ReturnCode="+str(self.
returnCode)+
")" 400 return Packets.__eq__(self, packet)
and \
406 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False):
410 self.fh.Retain = Retain
415 assert len(buffer) >= 2
417 self.fh.unpack(buffer)
418 assert self.fh.remainingLength == 0,
"Disconnect packet is wrong length %d" % self.fh.remainingLength
419 logger.info(
"[MQTT-3.14.1-1] disconnect reserved bits must be 0")
420 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1]" 421 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1]" 422 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1]" 425 return str(self.
fh)+
")" 430 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0, TopicName="", Payload=b""):
434 self.fh.Retain = Retain
448 buffer = self.fh.pack(
len(buffer)) + buffer
452 assert len(buffer) >= 2
454 fhlen = self.fh.unpack(buffer)
455 assert self.fh.QoS
in [0, 1, 2],
"QoS in Publish must be 0, 1, or 2" 456 packlen = fhlen + self.fh.remainingLength
457 assert len(buffer) >= packlen
461 except UnicodeDecodeError:
462 logger.info(
"[MQTT-3.3.2-1] topic name in publish must be utf-8")
467 logger.info(
"[MQTT-2.3.1-1] packet indentifier must be in publish if QoS is 1 or 2")
469 assert self.
messageIdentifier > 0,
"[MQTT-2.3.1-1] packet indentifier must be > 0" 471 logger.info(
"[MQTT-2.3.1-5] no packet indentifier in publish if QoS is 0")
473 self.
data = buffer[curlen:fhlen + self.fh.remainingLength]
475 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-4]" 476 return fhlen + self.fh.remainingLength
482 rc +=
", TopicName="+str(self.
topicName)+
", Payload="+str(self.
data)+
")" 486 rc = Packets.__eq__(self, packet)
and \
488 self.
data == packet.data
489 if rc
and self.fh.QoS != 0:
496 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0):
500 self.fh.Retain = Retain
508 buffer = self.fh.pack(
len(buffer)) + buffer
512 assert len(buffer) >= 2
514 fhlen = self.fh.unpack(buffer)
515 assert self.fh.remainingLength == 2,
"Puback packet is wrong length %d" % self.fh.remainingLength
516 assert len(buffer) >= fhlen + self.fh.remainingLength
518 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1] Puback reserved bits must be 0" 519 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1] Puback reserved bits must be 0" 520 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1] Puback reserved bits must be 0" 527 return Packets.__eq__(self, packet)
and \
533 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0):
537 self.fh.Retain = Retain
545 buffer = self.fh.pack(
len(buffer)) + buffer
549 assert len(buffer) >= 2
551 fhlen = self.fh.unpack(buffer)
552 assert self.fh.remainingLength == 2,
"Pubrec packet is wrong length %d" % self.fh.remainingLength
553 assert len(buffer) >= fhlen + self.fh.remainingLength
555 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1] Pubrec reserved bits must be 0" 556 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1] Pubrec reserved bits must be 0" 557 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1] Pubrec reserved bits must be 0" 564 return Packets.__eq__(self, packet)
and \
570 def __init__(self, buffer=None, DUP=False, QoS=1, Retain=False, MsgId=0):
574 self.fh.Retain = Retain
582 buffer = self.fh.pack(
len(buffer)) + buffer
586 assert len(buffer) >= 2
588 fhlen = self.fh.unpack(buffer)
589 assert self.fh.remainingLength == 2,
"Pubrel packet is wrong length %d" % self.fh.remainingLength
590 assert len(buffer) >= fhlen + self.fh.remainingLength
592 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1] DUP should be False in PUBREL" 593 assert self.fh.QoS == 1,
"[MQTT-2.1.2-1] QoS should be 1 in PUBREL" 594 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1] RETAIN should be False in PUBREL" 595 logger.info(
"[MQTT-3.6.1-1] bits in fixed header for pubrel are ok")
602 return Packets.__eq__(self, packet)
and \
608 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0):
612 self.fh.Retain = Retain
620 buffer = self.fh.pack(
len(buffer)) + buffer
624 assert len(buffer) >= 2
626 fhlen = self.fh.unpack(buffer)
627 assert len(buffer) >= fhlen + self.fh.remainingLength
628 assert self.fh.remainingLength == 2,
"Pubcomp packet is wrong length %d" % self.fh.remainingLength
630 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1] DUP should be False in Pubcomp" 631 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1] QoS should be 0 in Pubcomp" 632 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1] Retain should be false in Pubcomp" 639 return Packets.__eq__(self, packet)
and \
645 def __init__(self, buffer=None, DUP=False, QoS=1, Retain=False, MsgId=0, Data=[]):
649 self.fh.Retain = Retain
661 buffer = self.fh.pack(
len(buffer)) + buffer
665 assert len(buffer) >= 2
667 fhlen = self.fh.unpack(buffer)
668 assert len(buffer) >= fhlen + self.fh.remainingLength
669 logger.info(
"[MQTT-2.3.1-1] packet indentifier must be in subscribe")
671 assert self.
messageIdentifier > 0,
"[MQTT-2.3.1-1] packet indentifier must be > 0" 672 leftlen = self.fh.remainingLength - 2
675 topic =
readUTF(buffer[-leftlen:], leftlen)
676 leftlen -=
len(topic) + 2
677 qos = buffer[-leftlen]
678 assert qos
in [0, 1, 2],
"[MQTT-3-8.3-2] reserved bits must be zero" 680 self.data.append((topic, qos))
681 assert len(self.
data) > 0,
"[MQTT-3.8.3-1] at least one topic, qos pair must be in subscribe" 683 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1] DUP must be false in subscribe" 684 assert self.fh.QoS == 1,
"[MQTT-2.1.2-1] QoS must be 1 in subscribe" 685 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1] RETAIN must be false in subscribe" 686 return fhlen + self.fh.remainingLength
690 ", Data="+str(self.
data)+
")" 693 return Packets.__eq__(self, packet)
and \
695 self.
data == packet.data
700 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0, Data=[]):
704 self.fh.Retain = Retain
716 buffer = self.fh.pack(
len(buffer)) + buffer
720 assert len(buffer) >= 2
722 fhlen = self.fh.unpack(buffer)
723 assert len(buffer) >= fhlen + self.fh.remainingLength
725 leftlen = self.fh.remainingLength - 2
728 qos = buffer[-leftlen]
729 assert qos
in [0, 1, 2, 0x80],
"[MQTT-3.9.3-2] return code in QoS must be 0, 1, 2 or 0x80" 731 self.data.append(qos)
733 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1] DUP should be false in suback" 734 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1] QoS should be 0 in suback" 735 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1] Retain should be false in suback" 736 return fhlen + self.fh.remainingLength
740 ", Data="+str(self.
data)+
")" 743 return Packets.__eq__(self, packet)
and \
745 self.
data == packet.data
750 def __init__(self, buffer=None, DUP=False, QoS=1, Retain=False, MsgId=0, Data=[]):
754 self.fh.Retain = Retain
766 buffer = self.fh.pack(
len(buffer)) + buffer
770 assert len(buffer) >= 2
772 fhlen = self.fh.unpack(buffer)
773 assert len(buffer) >= fhlen + self.fh.remainingLength
774 logger.info(
"[MQTT-2.3.1-1] packet indentifier must be in unsubscribe")
776 assert self.
messageIdentifier > 0,
"[MQTT-2.3.1-1] packet indentifier must be > 0" 777 leftlen = self.fh.remainingLength - 2
780 topic =
readUTF(buffer[-leftlen:], leftlen)
781 leftlen -=
len(topic) + 2
782 self.data.append(topic)
784 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1]" 785 assert self.fh.QoS == 1,
"[MQTT-2.1.2-1]" 786 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1]" 787 logger.info(
"[MQTT-3-10.1-1] fixed header bits are 0,0,1,0")
788 return fhlen + self.fh.remainingLength
792 ", Data="+str(self.
data)+
")" 795 return Packets.__eq__(self, packet)
and \
797 self.
data == packet.data
802 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0):
806 self.fh.Retain = Retain
814 buffer = self.fh.pack(
len(buffer)) + buffer
818 assert len(buffer) >= 2
820 fhlen = self.fh.unpack(buffer)
821 assert len(buffer) >= fhlen + self.fh.remainingLength
823 assert self.
messageIdentifier > 0,
"[MQTT-2.3.1-1] packet indentifier must be > 0" 825 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1]" 826 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1]" 827 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1]" 828 return fhlen + self.fh.remainingLength
834 return Packets.__eq__(self, packet)
and \
840 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False):
844 self.fh.Retain = Retain
849 assert len(buffer) >= 2
851 fhlen = self.fh.unpack(buffer)
852 assert self.fh.remainingLength == 0
853 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1]" 854 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1]" 855 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1]" 859 return str(self.
fh)+
")" 864 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False):
868 self.fh.Retain = Retain
873 assert len(buffer) >= 2
875 fhlen = self.fh.unpack(buffer)
876 assert self.fh.remainingLength == 0
877 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1]" 878 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1]" 879 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1]" 883 return str(self.
fh)+
")" 885 classes = [
None, Connects, Connacks, Publishes, Pubacks, Pubrecs,
886 Pubrels, Pubcomps, Subscribes, Subacks, Unsubscribes,
887 Unsubacks, Pingreqs, Pingresps, Disconnects]
892 packet.unpack(buffer)
897 if __name__ ==
"__main__":
899 tests = [0, 56, 127, 128, 8888, 16383, 16384, 65535, 2097151, 2097152,
900 20555666, 268435454, 268435455]
903 assert x == fh.decode(fh.encode(x))[0]
904 except AssertionError:
905 print(
"Test failed for x =", x, fh.decode(fh.encode(x)))
907 fh.decode(fh.encode(268435456))
909 except AssertionError:
912 for packet
in classes[1:]:
913 before = str(packet())
916 assert before == after
918 print(
"before:", before,
"\nafter:", after)
def __init__(self, buffer=None)
def __init__(self, buffer=None, DUP=False, QoS=1, Retain=False, MsgId=0, Data=[])
def __init__(self, buffer=None, DUP=False, QoS=1, Retain=False, MsgId=0, Data=[])
def __init__(self, buffer=None, DUP=False, QoS=1, Retain=False, MsgId=0)
def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0, TopicName="", Payload=b"")
def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False)
void print(std::FILE *f, const S &format_str, Args &&...args)
FMT_CONSTEXPR bool find(Ptr first, Ptr last, T value, Ptr &out)
def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0)
def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0)
def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0)
def readUTF(buffer, maxlen)
def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False)
def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0, Data=[])
def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False)
def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0)
def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, ReturnCode=0)