2 ******************************************************************* 3 Copyright (c) 2013, 2014 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 ******************************************************************* 18 from __future__
import print_function
22 Assertions are used to validate incoming data, but are omitted from outgoing packets. This is 23 so that the tests that use this package can send invalid data for error testing. 30 logger = logging.getLogger(
"mqttsas")
39 CONNECT, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL, \
40 PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, \
41 PINGREQ, PINGRESP, DISCONNECT = range(1, 15)
43 packetNames = [
"reserved", \
44 "Connect",
"Connack",
"Publish",
"Puback",
"Pubrec",
"Pubrel", \
45 "Pubcomp",
"Subscribe",
"Suback",
"Unsubscribe",
"Unsuback", \
46 "Pingreq",
"Pingresp",
"Disconnect"]
48 classNames = [
"reserved", \
49 "Connects",
"Connacks",
"Publishes",
"Pubacks",
"Pubrecs",
"Pubrels", \
50 "Pubcomps",
"Subscribes",
"Subacks",
"Unsubscribes",
"Unsubacks", \
51 "Pingreqs",
"Pingresps",
"Disconnects"]
56 rc = ord(byte[0]) >> 4
63 "receive the next packet" 67 if str(aSocket).
find(
"[closed]") != -1:
77 next = aSocket.recv(1)
79 next = aSocket.recv(1)
82 remlength += (digit & 127) * multiplier
89 while len(rest) < remlength:
90 rest += aSocket.recv(remlength-
len(rest))
91 assert len(rest) == remlength
106 self.
DUP == fh.DUP
and \
107 self.
QoS == fh.QoS
and \
112 "return printable representation of our data" 114 ", QoS="+repr(self.
QoS)+
", Retain="+repr(self.
RETAIN)
117 "pack data into string buffer ready for transmission down socket" 121 buffer += self.
encode(length)
125 assert 0 <= x <= 268435455
132 buffer +=
bytes([digit])
138 "unpack data from string buffer into separate fields" 141 self.
DUP = ((b0 >> 3) & 0x01) == 1
142 self.
QoS = (b0 >> 1) & 0x03
143 self.
RETAIN = (b0 & 0x01) == 1
153 digit = ord(buffer[0])
155 value += (digit & 127) * multiplier
159 return (value, bytes)
163 return bytes([length // 256, length % 256])
166 return ord(buf[0])*256 + ord(buf[1])
170 return writeInt16(
len(data)) + (data
if type(data) == type(b
"")
else bytes(data,
"utf-8"))
180 buf = buffer[2:2+length].
decode(
"utf-8")
181 logger.info(
"[MQTT-4.7.3-2] topic names and filters not include null")
182 zz = buf.find(
"\x00")
184 raise MQTTException(
"[MQTT-1.5.3-2] Null found in UTF data "+buf)
185 """for c in range (0xD800, 0xDFFF): 186 zz = buf.find(chr(c)) # look for D800-DFFF in the UTF string 188 raise MQTTException("[MQTT-1.5.3-1] D800-DFFF found in UTF data "+buf) 190 if buf.find(
"\uFEFF") != -1:
191 logger.info(
"[MQTT-1.5.3-3] U+FEFF in UTF string")
199 return buffer[2:2+length]
205 buffer = self.fh.pack(0)
212 return self.
fh == packet.fh
if packet
else False 255 buffer = self.fh.pack(
len(buffer)) + buffer
259 assert len(buffer) >= 2
263 fhlen = self.fh.unpack(buffer)
264 packlen = fhlen + self.fh.remainingLength
265 assert len(buffer) >= packlen,
"buffer length %d packet length %d" % (
len(buffer), packlen)
267 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1]" 268 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1] QoS was not 0, was %d" % self.fh.QoS
269 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1]" 278 connectFlags = ord(buffer[curlen])
279 assert (connectFlags & 0x01) == 0,
"[MQTT-3.1.2-3] reserved connect flag must be 0" 281 self.
WillFlag = ((connectFlags >> 2) & 0x01) == 1
282 self.
WillQoS = (connectFlags >> 3) & 0x03
289 assert self.
WillQoS in [0, 1, 2],
"[MQTT-3.1.2-14] will qos must not be 3" 291 assert self.
WillQoS == 0,
"[MQTT-3.1.2-13] will qos must be 0, if will flag is false" 292 assert self.
WillRETAIN ==
False,
"[MQTT-3.1.2-14] will retain must be false, if will flag is false" 296 logger.info(
"[MQTT-3.1.3-3] Clientid must be present, and first field")
297 logger.info(
"[MQTT-3.1.3-4] Clientid must be Unicode, and between 0 and 65535 bytes long")
306 logger.info(
"[[MQTT-3.1.2-9] will topic and will message fields must be present")
311 assert len(buffer) > curlen+2,
"Buffer too short to read username length" 314 logger.info(
"[MQTT-3.1.2-19] username must be in payload if user name flag is 1")
316 logger.info(
"[MQTT-3.1.2-18] username must not be in payload if user name flag is 0")
317 assert self.
passwordFlag ==
False,
"[MQTT-3.1.2-22] password flag must be 0 if username flag is 0" 320 assert len(buffer) > curlen+2,
"Buffer too short to read password length" 323 logger.info(
"[MQTT-3.1.2-21] password must be in payload if password flag is 0")
325 logger.info(
"[MQTT-3.1.2-20] password must not be in payload if password flag is 0")
328 logger.info(
"[MQTT-3.1.3-1] clientid, will topic, will message, username and password all present")
330 assert curlen == packlen,
"Packet is wrong length curlen %d != packlen %d" 332 logger.exception(
"[MQTT-3.1.4-1] server must validate connect packet and close connection without connack if it does not conform")
338 buf = repr(self.
fh)+
", ProtocolName="+str(self.
ProtocolName)+
", ProtocolVersion=" +\
340 ", WillFlag="+repr(self.
WillFlag)+
", KeepAliveTimer=" +\
344 buf +=
", WillQoS=" + repr(self.
WillQoS) +\
351 buf +=
", password="+str(self.
password)
355 rc = Packets.__eq__(self, packet)
and \
359 self.
WillFlag == packet.WillFlag
and \
364 rc = self.
WillQoS == packet.WillQoS
and \
373 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, ReturnCode=0):
377 self.fh.Retain = Retain
385 buffer = self.fh.pack(
len(buffer)) + buffer
389 assert len(buffer) >= 4
391 self.fh.unpack(buffer)
392 assert self.fh.remainingLength == 2,
"Connack packet is wrong length %d" % self.fh.remainingLength
393 assert ord(buffer[2])
in [0, 1],
"Connect Acknowledge Flags" 395 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1]" 396 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1]" 397 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1]" 400 return repr(self.
fh)+
", Session present="+str((self.
flags & 0x01) == 1)+
", ReturnCode="+repr(self.
returnCode)+
")" 403 return Packets.__eq__(self, packet)
and \
409 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False):
413 self.fh.Retain = Retain
418 assert len(buffer) >= 2
420 self.fh.unpack(buffer)
421 assert self.fh.remainingLength == 0,
"Disconnect packet is wrong length %d" % self.fh.remainingLength
422 logger.info(
"[MQTT-3.14.1-1] disconnect reserved bits must be 0")
423 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1]" 424 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1]" 425 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1]" 428 return repr(self.
fh)+
")" 433 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0, TopicName="", Payload=b""):
437 self.fh.Retain = Retain
451 buffer = self.fh.pack(
len(buffer)) + buffer
455 assert len(buffer) >= 2
457 fhlen = self.fh.unpack(buffer)
458 assert self.fh.QoS
in [0, 1, 2],
"QoS in Publish must be 0, 1, or 2" 459 packlen = fhlen + self.fh.remainingLength
460 assert len(buffer) >= packlen
464 except UnicodeDecodeError:
465 logger.info(
"[MQTT-3.3.2-1] topic name in publish must be utf-8")
470 logger.info(
"[MQTT-2.3.1-1] packet indentifier must be in publish if QoS is 1 or 2")
472 assert self.
messageIdentifier > 0,
"[MQTT-2.3.1-1] packet indentifier must be > 0" 474 logger.info(
"[MQTT-2.3.1-5] no packet indentifier in publish if QoS is 0")
476 self.
data = buffer[curlen:fhlen + self.fh.remainingLength]
478 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-4]" 479 return fhlen + self.fh.remainingLength
485 rc +=
", TopicName="+repr(self.
topicName)+
", Payload="+repr(self.
data)+
")" 489 rc = Packets.__eq__(self, packet)
and \
491 self.
data == packet.data
492 if rc
and self.fh.QoS != 0:
499 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0):
503 self.fh.Retain = Retain
511 buffer = self.fh.pack(
len(buffer)) + buffer
515 assert len(buffer) >= 2
517 fhlen = self.fh.unpack(buffer)
518 assert self.fh.remainingLength == 2,
"Puback packet is wrong length %d" % self.fh.remainingLength
519 assert len(buffer) >= fhlen + self.fh.remainingLength
521 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1] Puback reserved bits must be 0" 522 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1] Puback reserved bits must be 0" 523 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1] Puback reserved bits must be 0" 530 return Packets.__eq__(self, packet)
and \
536 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0):
540 self.fh.Retain = Retain
548 buffer = self.fh.pack(
len(buffer)) + buffer
552 assert len(buffer) >= 2
554 fhlen = self.fh.unpack(buffer)
555 assert self.fh.remainingLength == 2,
"Pubrec packet is wrong length %d" % self.fh.remainingLength
556 assert len(buffer) >= fhlen + self.fh.remainingLength
558 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1] Pubrec reserved bits must be 0" 559 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1] Pubrec reserved bits must be 0" 560 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1] Pubrec reserved bits must be 0" 567 return Packets.__eq__(self, packet)
and \
573 def __init__(self, buffer=None, DUP=False, QoS=1, Retain=False, MsgId=0):
577 self.fh.Retain = Retain
585 buffer = self.fh.pack(
len(buffer)) + buffer
589 assert len(buffer) >= 2
591 fhlen = self.fh.unpack(buffer)
592 assert self.fh.remainingLength == 2,
"Pubrel packet is wrong length %d" % self.fh.remainingLength
593 assert len(buffer) >= fhlen + self.fh.remainingLength
595 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1] DUP should be False in PUBREL" 596 assert self.fh.QoS == 1,
"[MQTT-2.1.2-1] QoS should be 1 in PUBREL" 597 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1] RETAIN should be False in PUBREL" 598 logger.info(
"[MQTT-3.6.1-1] bits in fixed header for pubrel are ok")
605 return Packets.__eq__(self, packet)
and \
611 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0):
615 self.fh.Retain = Retain
623 buffer = self.fh.pack(
len(buffer)) + buffer
627 assert len(buffer) >= 2
629 fhlen = self.fh.unpack(buffer)
630 assert len(buffer) >= fhlen + self.fh.remainingLength
631 assert self.fh.remainingLength == 2,
"Pubcomp packet is wrong length %d" % self.fh.remainingLength
633 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1] DUP should be False in Pubcomp" 634 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1] QoS should be 0 in Pubcomp" 635 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1] Retain should be false in Pubcomp" 642 return Packets.__eq__(self, packet)
and \
648 def __init__(self, buffer=None, DUP=False, QoS=1, Retain=False, MsgId=0, Data=[]):
652 self.fh.Retain = Retain
664 buffer = self.fh.pack(
len(buffer)) + buffer
668 assert len(buffer) >= 2
670 fhlen = self.fh.unpack(buffer)
671 assert len(buffer) >= fhlen + self.fh.remainingLength
672 logger.info(
"[MQTT-2.3.1-1] packet indentifier must be in subscribe")
674 assert self.
messageIdentifier > 0,
"[MQTT-2.3.1-1] packet indentifier must be > 0" 675 leftlen = self.fh.remainingLength - 2
678 topic =
readUTF(buffer[-leftlen:], leftlen)
679 leftlen -=
len(topic) + 2
680 qos = ord(buffer[-leftlen])
681 assert qos
in [0, 1, 2],
"[MQTT-3-8.3-2] reserved bits must be zero" 683 self.data.append((topic, qos))
684 assert len(self.
data) > 0,
"[MQTT-3.8.3-1] at least one topic, qos pair must be in subscribe" 686 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1] DUP must be false in subscribe" 687 assert self.fh.QoS == 1,
"[MQTT-2.1.2-1] QoS must be 1 in subscribe" 688 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1] RETAIN must be false in subscribe" 689 return fhlen + self.fh.remainingLength
693 ", Data="+repr(self.
data)+
")" 696 return Packets.__eq__(self, packet)
and \
698 self.
data == packet.data
703 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0, Data=[]):
707 self.fh.Retain = Retain
719 buffer = self.fh.pack(
len(buffer)) + buffer
723 assert len(buffer) >= 2
725 fhlen = self.fh.unpack(buffer)
726 assert len(buffer) >= fhlen + self.fh.remainingLength
728 leftlen = self.fh.remainingLength - 2
731 qos = buffer[-leftlen]
732 assert ord(qos)
in [0, 1, 2, 0x80],
"[MQTT-3.9.3-2] return code in QoS must be 0, 1, 2 or 0x80, was "+ord(qos)
734 self.data.append(qos)
736 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1] DUP should be false in suback" 737 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1] QoS should be 0 in suback" 738 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1] Retain should be false in suback" 739 return fhlen + self.fh.remainingLength
743 ", Data="+repr(self.
data)+
")" 746 return Packets.__eq__(self, packet)
and \
748 self.
data == packet.data
753 def __init__(self, buffer=None, DUP=False, QoS=1, Retain=False, MsgId=0, Data=[]):
757 self.fh.Retain = Retain
769 buffer = self.fh.pack(
len(buffer)) + buffer
773 assert len(buffer) >= 2
775 fhlen = self.fh.unpack(buffer)
776 assert len(buffer) >= fhlen + self.fh.remainingLength
777 logger.info(
"[MQTT-2.3.1-1] packet indentifier must be in unsubscribe")
779 assert self.
messageIdentifier > 0,
"[MQTT-2.3.1-1] packet indentifier must be > 0" 780 leftlen = self.fh.remainingLength - 2
783 topic =
readUTF(buffer[-leftlen:], leftlen)
784 leftlen -=
len(topic) + 2
785 self.data.append(topic)
787 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1]" 788 assert self.fh.QoS == 1,
"[MQTT-2.1.2-1]" 789 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1]" 790 logger.info(
"[MQTT-3-10.1-1] fixed header bits are 0,0,1,0")
791 return fhlen + self.fh.remainingLength
795 ", Data="+repr(self.
data)+
")" 798 return Packets.__eq__(self, packet)
and \
800 self.
data == packet.data
805 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0):
809 self.fh.Retain = Retain
817 buffer = self.fh.pack(
len(buffer)) + buffer
821 assert len(buffer) >= 2
823 fhlen = self.fh.unpack(buffer)
824 assert len(buffer) >= fhlen + self.fh.remainingLength
826 assert self.
messageIdentifier > 0,
"[MQTT-2.3.1-1] packet indentifier must be > 0" 828 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1]" 829 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1]" 830 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1]" 831 return fhlen + self.fh.remainingLength
837 return Packets.__eq__(self, packet)
and \
843 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False):
847 self.fh.Retain = Retain
852 assert len(buffer) >= 2
854 fhlen = self.fh.unpack(buffer)
855 assert self.fh.remainingLength == 0
856 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1]" 857 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1]" 858 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1]" 862 return repr(self.
fh)+
")" 867 def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False):
871 self.fh.Retain = Retain
876 assert len(buffer) >= 2
878 fhlen = self.fh.unpack(buffer)
879 assert self.fh.remainingLength == 0
880 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1]" 881 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1]" 882 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1]" 886 return repr(self.
fh)+
")" 888 classes = [
None, Connects, Connacks, Publishes, Pubacks, Pubrecs,
889 Pubrels, Pubcomps, Subscribes, Subacks, Unsubscribes,
890 Unsubacks, Pingreqs, Pingresps, Disconnects]
895 packet.unpack(buffer)
900 if __name__ ==
"__main__":
902 tests = [0, 56, 127, 128, 8888, 16383, 16384, 65535, 2097151, 2097152,
903 20555666, 268435454, 268435455]
906 assert x == fh.decode(fh.encode(x))[0]
907 except AssertionError:
908 print(
"Test failed for x =", x, fh.decode(fh.encode(x)))
910 fh.decode(fh.encode(268435456))
912 except AssertionError:
915 for packet
in classes[1:]:
916 before = str(packet())
919 assert before == after
921 print(
"before:", before,
"\nafter:", after)
def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, ReturnCode=0)
def __init__(self, buffer=None, DUP=False, QoS=1, Retain=False, MsgId=0, Data=[])
def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0)
def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False)
def __init__(self, buffer=None, DUP=False, QoS=1, Retain=False, MsgId=0, Data=[])
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=1, Retain=False, MsgId=0)
def __init__(self, buffer=None)
def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False)
def readUTF(buffer, maxlen)
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, Data=[])
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, MsgId=0)
def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False)
def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0)