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 Ian Craggs - take MQTT 3.1.1 and create MQTT 5.0 version 17 ******************************************************************* 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. 27 import logging, struct
29 logger = logging.getLogger(
'MQTTV5')
42 MAX_PACKET_SIZE = 2**28-1
43 MAX_PACKETID = 2**16-1
47 indexes = range(1, 16)
50 CONNECT, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL, \
51 PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, \
52 PINGREQ, PINGRESP, DISCONNECT, AUTH = indexes
60 Names = [
"reserved", \
61 "Connect",
"Connack",
"Publish",
"Puback",
"Pubrec",
"Pubrel", \
62 "Pubcomp",
"Subscribe",
"Suback",
"Unsubscribe",
"Unsuback", \
63 "Pingreq",
"Pingresp",
"Disconnect",
"Auth"]
65 classNames = [name+
'es' if name ==
"Publish" else 66 name+
's' if name !=
"reserved" else name
for name
in Names]
69 buffer = self.fh.pack(0)
76 return self.
fh == packet.fh
if packet
else False 79 if name
not in self.names:
80 raise MQTTException(name +
" Attribute name must be one of "+str(self.names))
81 object.__setattr__(self, name, value)
86 Retrieve the message type from the first byte of the fixed header. 96 The reason code used in MQTT V5.0 102 used when displaying the reason code 104 assert identifier
in self.names.keys(), identifier
105 names = self.
names[identifier]
106 namelist = [name
for name
in names.keys()
if packetType
in names[name]]
107 assert len(namelist) == 1
112 used when setting the reason code for a packetType 113 check that only valid codes for the packet are set 116 for code
in self.names.keys():
117 if name
in self.
names[code].keys():
121 assert identifier !=
None, name
141 def __init__(self, packetType, aName="Success", identifier=-1):
144 0 : {
"Success" : [PacketTypes.CONNACK, PacketTypes.PUBACK,
145 PacketTypes.PUBREC, PacketTypes.PUBREL, PacketTypes.PUBCOMP,
146 PacketTypes.UNSUBACK, PacketTypes.AUTH],
147 "Normal disconnection" : [PacketTypes.DISCONNECT],
148 "Granted QoS 0" : [PacketTypes.SUBACK] },
149 1 : {
"Granted QoS 1" : [PacketTypes.SUBACK] },
150 2 : {
"Granted QoS 2" : [PacketTypes.SUBACK] },
151 4 : {
"Disconnect with will message" : [PacketTypes.DISCONNECT] },
152 16 : {
"No matching subscribers" :
153 [PacketTypes.PUBACK, PacketTypes.PUBREC] },
154 17 : {
"No subscription found" : [PacketTypes.UNSUBACK] },
155 24 : {
"Continue authentication" : [PacketTypes.AUTH] },
156 25 : {
"Re-authenticate" : [PacketTypes.AUTH] },
157 128 : {
"Unspecified error" : [PacketTypes.CONNACK, PacketTypes.PUBACK,
158 PacketTypes.PUBREC, PacketTypes.SUBACK, PacketTypes.UNSUBACK,
159 PacketTypes.DISCONNECT], },
160 129 : {
"Malformed packet" :
161 [PacketTypes.CONNACK, PacketTypes.DISCONNECT] },
162 130 : {
"Protocol error" :
163 [PacketTypes.CONNACK, PacketTypes.DISCONNECT] },
164 131 : {
"Implementation specific error": [PacketTypes.CONNACK,
165 PacketTypes.PUBACK, PacketTypes.PUBREC, PacketTypes.SUBACK,
166 PacketTypes.UNSUBACK, PacketTypes.DISCONNECT], },
167 132 : {
"Unsupported protocol version" : [PacketTypes.CONNACK] },
168 133 : {
"Client identifier not valid" : [PacketTypes.CONNACK] },
169 134 : {
"Bad user name or password" : [PacketTypes.CONNACK] },
170 135 : {
"Not authorized" : [PacketTypes.CONNACK, PacketTypes.PUBACK,
171 PacketTypes.PUBREC, PacketTypes.SUBACK, PacketTypes.UNSUBACK,
172 PacketTypes.DISCONNECT], },
173 136 : {
"Server unavailable" : [PacketTypes.CONNACK] },
174 137 : {
"Server busy" : [PacketTypes.CONNACK, PacketTypes.DISCONNECT] },
175 138 : {
"Banned" : [PacketTypes.CONNACK] },
176 139 : {
"Server shutting down" : [PacketTypes.DISCONNECT] },
177 140 : {
"Bad authentication method" :
178 [PacketTypes.CONNACK, PacketTypes.DISCONNECT] },
179 141 : {
"Keep alive timeout" : [PacketTypes.DISCONNECT] },
180 142 : {
"Session taken over" : [PacketTypes.DISCONNECT] },
181 143 : {
"Topic filter invalid" :
182 [PacketTypes.SUBACK, PacketTypes.UNSUBACK, PacketTypes.DISCONNECT]},
183 144 : {
"Topic name invalid" :
184 [PacketTypes.CONNACK, PacketTypes.PUBACK,
185 PacketTypes.PUBREC, PacketTypes.DISCONNECT]},
186 145 : {
"Packet identifier in use" :
187 [PacketTypes.PUBACK, PacketTypes.PUBREC,
188 PacketTypes.SUBACK, PacketTypes.UNSUBACK]},
189 146 : {
"Packet identifier not found" :
190 [PacketTypes.PUBREL, PacketTypes.PUBCOMP] },
191 147 : {
"Receive maximum exceeded": [PacketTypes.DISCONNECT] },
192 148 : {
"Topic alias invalid": [PacketTypes.DISCONNECT] },
193 149 : {
"Packet too large": [PacketTypes.CONNACK, PacketTypes.DISCONNECT] },
194 150 : {
"Message rate too high": [PacketTypes.DISCONNECT] },
195 151 : {
"Quota exceeded": [PacketTypes.CONNACK, PacketTypes.PUBACK,
196 PacketTypes.PUBREC, PacketTypes.SUBACK, PacketTypes.DISCONNECT], },
197 152 : {
"Administrative action" : [PacketTypes.DISCONNECT] },
198 153 : {
"Payload format invalid" :
199 [PacketTypes.PUBACK, PacketTypes.PUBREC, PacketTypes.DISCONNECT]},
200 154 : {
"Retain not supported" :
201 [PacketTypes.CONNACK, PacketTypes.DISCONNECT] },
202 155 : {
"QoS not supported" :
203 [PacketTypes.CONNACK, PacketTypes.DISCONNECT] },
204 156 : {
"Use another server" :
205 [PacketTypes.CONNACK, PacketTypes.DISCONNECT] },
206 157 : {
"Server moved" :
207 [PacketTypes.CONNACK, PacketTypes.DISCONNECT] },
208 158 : {
"Shared subscription not supported" :
209 [PacketTypes.SUBACK, PacketTypes.DISCONNECT] },
210 159 : {
"Connection rate exceeded" :
211 [PacketTypes.CONNACK, PacketTypes.DISCONNECT] },
212 160 : {
"Maximum connect time" :
213 [PacketTypes.DISCONNECT] },
214 161 : {
"Subscription identifiers not supported" :
215 [PacketTypes.SUBACK, PacketTypes.DISCONNECT] },
216 162 : {
"Wildcard subscription not supported" :
217 [PacketTypes.SUBACK, PacketTypes.DISCONNECT] },
222 self.
value = identifier
231 Convert an integer 0 <= x <= 268435455 into multi-byte format. 232 Returns the buffer convered from the integer. 234 assert 0 <= x <= 268435455
241 buffer +=
bytes([digit])
249 Get the value of a multi-byte integer from a buffer 250 Return the value, and the number of bytes used. 252 [MQTT-1.5.5-1] the encoded value MUST use the minimum number of bytes necessary to represent the value 261 value += (digit & 127) * multiplier
265 return (value, bytes)
268 "receive the next packet" 269 buf = aSocket.recv(1)
272 if str(aSocket).
find(
"[closed]") != -1:
282 next = aSocket.recv(1)
283 while len(next) == 0:
284 next = aSocket.recv(1)
287 remlength += (digit & 127) * multiplier
294 while len(rest) < remlength:
295 rest += aSocket.recv(remlength-
len(rest))
296 assert len(rest) == remlength
311 self.
DUP == fh.DUP
and \
312 self.
QoS == fh.QoS
and \
317 names = [
"PacketType",
"DUP",
"QoS",
"RETAIN",
"remainingLength"]
318 if name
not in names:
319 raise MQTTException(name +
" Attribute name must be one of "+str(names))
320 object.__setattr__(self, name, value)
323 "return printable representation of our data" 324 return Packets.classNames[self.
PacketType]+
'(fh.DUP='+str(self.
DUP)+ \
325 ", fh.QoS="+str(self.
QoS)+
", fh.RETAIN="+str(self.
RETAIN)
328 "pack data into string buffer ready for transmission down socket" 332 buffer += VBIs.encode(length)
335 def unpack(self, buffer, maximumPacketSize):
336 "unpack data from string buffer into separate fields" 339 self.
DUP = ((b0 >> 3) & 0x01) == 1
340 self.
QoS = (b0 >> 1) & 0x03
341 self.
RETAIN = (b0 & 0x01) == 1
349 return bytes([length // 256, length % 256])
352 return buf[0]*256 + buf[1]
355 buffer = [length // 16777216]
357 buffer += [length // 65536]
359 buffer += [length // 256, length % 256]
363 return buf[0]*16777216 + buf[1]*65536 + buf[2]*256 + buf[3]
367 return writeInt16(
len(data)) + (data
if type(data) == type(b
"")
else bytes(data,
"utf-8"))
377 buf = buffer[2:2+length].
decode(
"utf-8")
378 logger.info(
"[MQTT-4.7.3-2] topic names and filters must not include null")
379 zz = buf.find(
"\x00")
382 for c
in range (0xD800, 0xDFFF):
383 zz = buf.find(chr(c))
385 raise MalformedPacket(
"[MQTT-1.5.4-1] D800-DFFF found in UTF data "+buf)
386 if buf.find(
"\uFEFF") != -1:
387 logger.info(
"[MQTT-1.5.4-3] U+FEFF in UTF string")
395 return buffer[2:2+length], length+2
402 self.
types = [
"Byte",
"Two Byte Integer",
"Four Byte Integer",
"Variable Byte Integer",
403 "Binary Data",
"UTF-8 Encoded String",
"UTF-8 String Pair"]
406 "Payload Format Indicator" : 1,
407 "Message Expiry Interval" : 2,
409 "Response Topic" : 8,
410 "Correlation Data" : 9,
411 "Subscription Identifier" : 11,
412 "Session Expiry Interval" : 17,
413 "Assigned Client Identifier" : 18,
414 "Server Keep Alive" : 19,
415 "Authentication Method" : 21,
416 "Authentication Data" : 22,
417 "Request Problem Information" : 23,
418 "Will Delay Interval" : 24,
419 "Request Response Information" : 25,
420 "Response Information" : 26,
421 "Server Reference" : 28,
422 "Reason String" : 31,
423 "Receive Maximum" : 33,
424 "Topic Alias Maximum" : 34,
427 "Retain Available" : 37,
428 "User Property List" : 38,
429 "Maximum Packet Size" : 39,
430 "Wildcard Subscription Available" : 40,
431 "Subscription Identifier Available" : 41,
432 "Shared Subscription Available" : 42
437 1 : (self.types.index(
"Byte"), [PacketTypes.PUBLISH, PacketTypes.WILLMESSAGE]),
438 2 : (self.types.index(
"Four Byte Integer"), [PacketTypes.PUBLISH, PacketTypes.WILLMESSAGE]),
439 3 : (self.types.index(
"UTF-8 Encoded String"), [PacketTypes.PUBLISH, PacketTypes.WILLMESSAGE]),
440 8 : (self.types.index(
"UTF-8 Encoded String"), [PacketTypes.PUBLISH, PacketTypes.WILLMESSAGE]),
441 9 : (self.types.index(
"Binary Data"), [PacketTypes.PUBLISH, PacketTypes.WILLMESSAGE]),
442 11 : (self.types.index(
"Variable Byte Integer"),
443 [PacketTypes.PUBLISH, PacketTypes.SUBSCRIBE]),
444 17 : (self.types.index(
"Four Byte Integer"),
445 [PacketTypes.CONNECT, PacketTypes.CONNACK, PacketTypes.DISCONNECT]),
446 18 : (self.types.index(
"UTF-8 Encoded String"), [PacketTypes.CONNACK]),
447 19 : (self.types.index(
"Two Byte Integer"), [PacketTypes.CONNACK]),
448 21 : (self.types.index(
"UTF-8 Encoded String"),
449 [PacketTypes.CONNECT, PacketTypes.CONNACK, PacketTypes.AUTH]),
450 22 : (self.types.index(
"Binary Data"),
451 [PacketTypes.CONNECT, PacketTypes.CONNACK, PacketTypes.AUTH]),
452 23 : (self.types.index(
"Byte"),
453 [PacketTypes.CONNECT]),
454 24 : (self.types.index(
"Four Byte Integer"), [PacketTypes.WILLMESSAGE]),
455 25 : (self.types.index(
"Byte"), [PacketTypes.CONNECT]),
456 26 : (self.types.index(
"UTF-8 Encoded String"), [PacketTypes.CONNACK]),
457 28 : (self.types.index(
"UTF-8 Encoded String"),
458 [PacketTypes.CONNACK, PacketTypes.DISCONNECT]),
459 31 : (self.types.index(
"UTF-8 Encoded String"),
460 [PacketTypes.CONNACK, PacketTypes.PUBACK, PacketTypes.PUBREC,
461 PacketTypes.PUBREL, PacketTypes.PUBCOMP, PacketTypes.SUBACK,
462 PacketTypes.UNSUBACK, PacketTypes.DISCONNECT, PacketTypes.AUTH]),
463 33 : (self.types.index(
"Two Byte Integer"),
464 [PacketTypes.CONNECT, PacketTypes.CONNACK]),
465 34 : (self.types.index(
"Two Byte Integer"),
466 [PacketTypes.CONNECT, PacketTypes.CONNACK]),
467 35 : (self.types.index(
"Two Byte Integer"), [PacketTypes.PUBLISH]),
468 36 : (self.types.index(
"Byte"), [PacketTypes.CONNACK]),
469 37 : (self.types.index(
"Byte"), [PacketTypes.CONNACK]),
470 38 : (self.types.index(
"UTF-8 String Pair"),
471 [PacketTypes.CONNECT, PacketTypes.CONNACK,
472 PacketTypes.PUBLISH, PacketTypes.PUBACK,
473 PacketTypes.PUBREC, PacketTypes.PUBREL, PacketTypes.PUBCOMP,
474 PacketTypes.SUBSCRIBE, PacketTypes.SUBACK,
475 PacketTypes.UNSUBSCRIBE, PacketTypes.UNSUBACK,
476 PacketTypes.DISCONNECT, PacketTypes.AUTH, PacketTypes.WILLMESSAGE]),
477 39 : (self.types.index(
"Four Byte Integer"),
478 [PacketTypes.CONNECT, PacketTypes.CONNACK]),
479 40 : (self.types.index(
"Byte"), [PacketTypes.CONNACK]),
480 41 : (self.types.index(
"Byte"), [PacketTypes.CONNACK]),
481 42 : (self.types.index(
"Byte"), [PacketTypes.CONNACK]),
487 for name
in self.names.keys():
488 if compressedName == name.replace(
' ',
''):
489 result = self.
names[name]
494 name = name.replace(
' ',
'')
495 privateVars = [
"packetType",
"types",
"names",
"properties"]
496 if name
in privateVars:
497 object.__setattr__(self, name, value)
500 if name
not in [name.replace(
' ',
'')
for name
in self.names.keys()]:
501 raise MQTTException(
"Attribute name must be one of "+str(self.names.keys()))
504 raise MQTTException(
"Attribute %s does not apply to packet type %s" 506 object.__setattr__(self, name, value)
511 for name
in self.names.keys():
512 compressedName = name.replace(
' ',
'')
513 if hasattr(self, compressedName):
516 buffer += compressedName +
" : "+str(getattr(self, compressedName))
523 for name
in self.names.keys():
524 compressedName = name.replace(
' ',
'')
525 if hasattr(self, compressedName):
531 for name
in self.names.keys():
532 compressedName = name.replace(
' ',
'')
533 if hasattr(self, compressedName):
534 delattr(self, compressedName)
538 buffer += VBIs.encode(identifier)
539 if type == self.types.index(
"Byte"):
540 buffer +=
bytes([value])
541 elif type == self.types.index(
"Two Byte Integer"):
543 elif type == self.types.index(
"Four Byte Integer"):
545 elif type == self.types.index(
"Variable Byte Integer"):
546 buffer += VBIs.encode(value)
547 elif type == self.types.index(
"Binary Data"):
549 elif type == self.types.index(
"UTF-8 Encoded String"):
551 elif type == self.types.index(
"UTF-8 String Pair"):
558 for name
in self.names.keys():
559 compressedName = name.replace(
' ',
'')
561 if compressedName.endswith(
'List'):
563 if hasattr(self, compressedName):
567 for prop
in getattr(self, compressedName):
571 getattr(self, compressedName))
572 return VBIs.encode(
len(buffer)) + buffer
575 if type == self.types.index(
"Byte"):
578 elif type == self.types.index(
"Two Byte Integer"):
581 elif type == self.types.index(
"Four Byte Integer"):
584 elif type == self.types.index(
"Variable Byte Integer"):
585 value, valuelen = VBIs.decode(buffer)
586 elif type == self.types.index(
"Binary Data"):
588 elif type == self.types.index(
"UTF-8 Encoded String"):
589 value, valuelen =
readUTF(buffer, propslen)
590 elif type == self.types.index(
"UTF-8 String Pair"):
591 value, valuelen =
readUTF(buffer, propslen)
592 buffer = buffer[valuelen:]
593 value1, valuelen1 =
readUTF(buffer, propslen - valuelen)
594 value = (value, value1)
595 valuelen += valuelen1
596 return value, valuelen
600 for name
in self.
names:
601 if self.
names[name] == identifier:
608 propslen, VBIlen = VBIs.decode(buffer)
609 buffer = buffer[VBIlen:]
610 propslenleft = propslen
611 while propslenleft > 0:
612 identifier, VBIlen = VBIs.decode(buffer)
613 buffer = buffer[VBIlen:]
614 propslenleft -= VBIlen
616 value, valuelen = self.
readProperty(buffer, attr_type, propslenleft)
617 buffer = buffer[valuelen:]
618 propslenleft -= valuelen
620 compressedName = propname.replace(
' ',
'')
621 if propname.endswith(
'List'):
622 if not hasattr(self, compressedName):
623 setattr(self, propname, [value])
625 setattr(self, propname, getattr(self, compressedName) + [value])
627 if hasattr(self, compressedName):
628 raise MQTTException(
"Property '%s' must not exist more than once" % property)
629 setattr(self, propname, value)
630 return self, propslen + VBIlen
636 object.__setattr__(self,
"names",
637 [
"fh",
"properties",
"willProperties",
"ProtocolName",
"ProtocolVersion",
638 "ClientIdentifier",
"CleanStart",
"KeepAliveTimer",
639 "WillFlag",
"WillQoS",
"WillRETAIN",
"WillTopic",
"WillMessage",
640 "usernameFlag",
"passwordFlag",
"username",
"password"])
675 buffer += self.properties.pack()
678 assert self.willProperties.packetType == PacketTypes.WILLMESSAGE
679 buffer += self.willProperties.pack()
686 buffer = self.fh.pack(
len(buffer)) + buffer
689 def unpack(self, buffer, maximumPacketSize):
690 assert len(buffer) >= 2
691 assert PacketType(buffer) == PacketTypes.CONNECT
694 fhlen = self.fh.unpack(buffer, maximumPacketSize)
695 packlen = fhlen + self.fh.remainingLength
696 assert len(buffer) >= packlen,
"buffer length %d packet length %d" % (
len(buffer), packlen)
698 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1]" 699 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1] QoS was not 0, was %d" % self.fh.QoS
700 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1]" 712 connectFlags = buffer[curlen]
713 assert (connectFlags & 0x01) == 0,
"[MQTT-3.1.2-3] reserved connect flag must be 0" 714 self.
CleanStart = ((connectFlags >> 1) & 0x01) == 1
715 self.
WillFlag = ((connectFlags >> 2) & 0x01) == 1
716 self.
WillQoS = (connectFlags >> 3) & 0x03
723 assert self.
WillQoS in [0, 1, 2],
"[MQTT-3.1.2-12] will qos must not be 3" 725 assert self.
WillQoS == 0,
"[MQTT-3.1.2-11] will qos must be 0, if will flag is false" 726 assert self.
WillRETAIN ==
False,
"[MQTT-3.1.2-13] will retain must be false, if will flag is false" 731 curlen += self.properties.unpack(buffer[curlen:])[1]
733 logger.info(
"[MQTT-3.1.3-3] Clientid must be present, and first field")
734 logger.info(
"[MQTT-3.1.3-4] Clientid must be Unicode, and between 0 and 65535 bytes long")
739 curlen += self.willProperties.unpack(buffer[curlen:])[1]
744 logger.info(
"[[MQTT-3.1.2-9] will topic and will message fields must be present")
749 assert len(buffer) > curlen+2,
"Buffer too short to read username length" 752 logger.info(
"[MQTT-3.1.2-19] username must be in payload if user name flag is 1")
754 logger.info(
"[MQTT-3.1.2-18] username must not be in payload if user name flag is 0")
755 assert self.
passwordFlag ==
False,
"[MQTT-3.1.2-22] password flag must be 0 if username flag is 0" 758 assert len(buffer) > curlen+2,
"Buffer too short to read password length" 761 logger.info(
"[MQTT-3.1.2-21] password must be in payload if password flag is 0")
763 logger.info(
"[MQTT-3.1.2-20] password must not be in payload if password flag is 0")
766 logger.info(
"[MQTT-3.1.3-1] clientid, will topic, will message, username and password all present")
768 assert curlen == packlen,
"Packet is wrong length curlen %d != packlen %d" % (curlen, packlen)
770 logger.exception(
"[MQTT-3.1.4-1] server must validate connect packet and close connection without connack if it does not conform")
774 buf = str(self.
fh)+
", ProtocolName="+str(self.
ProtocolName)+
", ProtocolVersion=" +\
776 ", WillFlag="+str(self.
WillFlag)+
", KeepAliveTimer=" +\
780 buf +=
", WillQoS=" + str(self.
WillQoS) +\
787 buf +=
", password="+str(self.
password)
792 rc = Packets.__eq__(self, packet)
and \
796 self.
WillFlag == packet.WillFlag
and \
801 rc = self.
WillQoS == packet.WillQoS
and \
812 def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, ReasonCode="Success"):
813 object.__setattr__(self,
"names",
814 [
"fh",
"sessionPresent",
"reasonCode",
"properties"])
818 self.fh.RETAIN = RETAIN
827 buffer =
bytes([flags])
828 buffer += self.reasonCode.pack()
829 buffer += self.properties.pack()
830 buffer = self.fh.pack(
len(buffer)) + buffer
833 def unpack(self, buffer, maximumPacketSize):
834 assert len(buffer) >= 4
835 assert PacketType(buffer) == PacketTypes.CONNACK
836 curlen = self.fh.unpack(buffer, maximumPacketSize)
837 assert buffer[curlen]
in [0, 1],
"Connect Acknowledge Flags" 840 curlen += self.reasonCode.unpack(buffer[curlen:])
841 curlen += self.properties.unpack(buffer[curlen:])[1]
842 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1]" 843 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1]" 844 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1]" 847 return str(self.
fh)+
", Session present="+str((self.
sessionPresent & 0x01) == 1)+\
852 return Packets.__eq__(self, packet)
and \
858 def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False,
859 reasonCode=
"Normal disconnection"):
860 object.__setattr__(self,
"names",
861 [
"fh",
"DUP",
"QoS",
"RETAIN",
"reasonCode",
"properties"])
865 self.fh.RETAIN = RETAIN
874 if self.reasonCode.getName() !=
"Normal disconnection" or not self.properties.isEmpty():
875 buffer += self.reasonCode.pack()
876 if not self.properties.isEmpty():
877 buffer += self.properties.pack()
878 buffer = self.fh.pack(
len(buffer)) + buffer
881 def unpack(self, buffer, maximumPacketSize):
882 self.properties.clear()
883 self.reasonCode.set(
"Normal disconnection")
884 assert len(buffer) >= 2
885 assert PacketType(buffer) == PacketTypes.DISCONNECT
886 fhlen = self.fh.unpack(buffer, maximumPacketSize)
887 assert len(buffer) >= fhlen + self.fh.remainingLength
888 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1] DISCONNECT reserved bits must be 0" 889 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1] DISCONNECT reserved bits must be 0" 890 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1] DISCONNECT reserved bits must be 0" 892 if self.fh.remainingLength > 0:
893 self.reasonCode.unpack(buffer[curlen:])
895 if self.fh.remainingLength > 1:
896 curlen += self.properties.unpack(buffer[curlen:])[1]
897 assert curlen == self.fh.remainingLength, \
898 "DISCONNECT packet is wrong length %d" % self.fh.remainingLength
899 return fhlen + self.fh.remainingLength
905 return Packets.__eq__(self, packet)
and \
912 def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, MsgId=1, TopicName="", Payload=b""):
913 object.__setattr__(self,
"names",
914 [
"fh",
"DUP",
"QoS",
"RETAIN",
"topicName",
"packetIdentifier",
915 "properties",
"data",
"qos2state",
"receivedTime"])
919 self.fh.RETAIN = RETAIN
933 buffer += self.properties.pack()
935 buffer = self.fh.pack(
len(buffer)) + buffer
938 def unpack(self, buffer, maximumPacketSize):
939 assert len(buffer) >= 2
940 assert PacketType(buffer) == PacketTypes.PUBLISH
941 fhlen = self.fh.unpack(buffer, maximumPacketSize)
942 assert self.fh.QoS
in [0, 1, 2],
"QoS in Publish must be 0, 1, or 2" 943 packlen = fhlen + self.fh.remainingLength
944 assert len(buffer) >= packlen
948 except UnicodeDecodeError:
949 logger.info(
"[MQTT-3.3.2-1] topic name in publish must be utf-8")
954 logger.info(
"[MQTT-2.3.1-1] packet indentifier must be in publish if QoS is 1 or 2")
956 assert self.
packetIdentifier > 0,
"[MQTT-2.3.1-1] packet indentifier must be > 0" 958 logger.info(
"[MQTT-2.3.1-5] no packet indentifier in publish if QoS is 0")
960 curlen += self.properties.unpack(buffer[curlen:])[1]
961 self.
data = buffer[curlen:fhlen + self.fh.remainingLength]
963 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-4]" 964 return fhlen + self.fh.remainingLength
971 rc +=
", TopicName="+str(self.
topicName)+
", Payload="+str(self.
data)+
")" 975 rc = Packets.__eq__(self, packet)
and \
977 self.
data == packet.data
978 if rc
and self.fh.QoS != 0:
985 def __init__(self, ackType, buffer, DUP, QoS, RETAIN, packetId):
986 object.__setattr__(self,
"names",
987 [
"fh",
"DUP",
"QoS",
"RETAIN",
"packetIdentifier",
988 "reasonCode",
"properties"])
992 self.fh.RETAIN = RETAIN
997 object.__setattr__(self,
"ackType", ackType)
998 object.__setattr__(self,
"ackName", Packets.Names[self.
ackType])
1004 if self.reasonCode.getName() !=
"Success" or not self.properties.isEmpty():
1005 buffer += self.reasonCode.pack()
1006 if not self.properties.isEmpty():
1007 buffer += self.properties.pack()
1008 buffer = self.fh.pack(
len(buffer)) + buffer
1012 self.properties.clear()
1013 self.reasonCode.set(
"Success")
1014 assert len(buffer) >= 2
1016 fhlen = self.fh.unpack(buffer, maximumPacketSize)
1017 assert self.fh.remainingLength
in [2, 3, 4], \
1018 "%s packet is wrong length %d" % (self.ackName, self.fh.remainingLength)
1019 assert len(buffer) >= fhlen + self.fh.remainingLength
1022 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1] %s reserved bits must be 0" %\
1025 assert self.fh.QoS == 1,
"[MQTT-3.6.1-1] %s reserved bits must be 0010" %\
1028 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1] %s reserved bits must be 0" %\
1030 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1] %s reserved bits must be 0" %\
1032 if self.fh.remainingLength > 2:
1033 self.reasonCode.unpack(buffer[curlen:])
1035 if self.fh.remainingLength > 3:
1036 self.properties.unpack(buffer[curlen:])
1037 return fhlen + self.fh.remainingLength
1043 return Packets.__eq__(self, packet)
and \
1049 def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, PacketId=1):
1050 Acks.__init__(self, PacketTypes.PUBACK, buffer, DUP, QoS, RETAIN, PacketId)
1054 def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, PacketId=1):
1055 Acks.__init__(self, PacketTypes.PUBREC, buffer, DUP, QoS, RETAIN, PacketId)
1059 def __init__(self, buffer=None, DUP=False, QoS=1, RETAIN=False, PacketId=1):
1060 Acks.__init__(self, PacketTypes.PUBREL, buffer, DUP, QoS, RETAIN, PacketId)
1064 def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, PacketId=1):
1065 Acks.__init__(self, PacketTypes.PUBCOMP, buffer, DUP, QoS, RETAIN, PacketId)
1069 def __init__(self, QoS=0, noLocal=False, retainAsPublished=False, retainHandling=0):
1070 object.__setattr__(self,
"names",
1071 [
"QoS",
"noLocal",
"retainAsPublished",
"retainHandling"])
1078 if name
not in self.names:
1079 raise MQTTException(name +
" Attribute name must be one of "+str(self.names))
1080 object.__setattr__(self, name, value)
1083 assert self.
QoS in [0, 1, 2]
1085 noLocal = 1
if self.
noLocal else 0
1088 (noLocal << 2) | self.
QoS])
1095 self.
noLocal =
True if ((b0 >> 2) & 0x01) == 1
else False 1096 self.
QoS = (b0 & 0x03)
1098 assert self.
QoS in [0, 1, 2]
1102 return "{QoS="+str(self.
QoS)+
", noLocal="+str(self.
noLocal)+\
1109 def __init__(self, buffer=None, DUP=False, QoS=1, RETAIN=False, MsgId=1, Data=[]):
1110 object.__setattr__(self,
"names",
1111 [
"fh",
"DUP",
"QoS",
"RETAIN",
"packetIdentifier",
1112 "properties",
"data"])
1116 self.fh.RETAIN = RETAIN
1127 buffer += self.properties.pack()
1130 buffer = self.fh.pack(
len(buffer)) + buffer
1134 self.properties.clear()
1135 assert len(buffer) >= 2
1136 assert PacketType(buffer) == PacketTypes.SUBSCRIBE
1137 fhlen = self.fh.unpack(buffer, maximumPacketSize)
1138 assert len(buffer) >= fhlen + self.fh.remainingLength
1139 logger.info(
"[MQTT-2.3.1-1] packet indentifier must be in subscribe")
1141 assert self.
packetIdentifier > 0,
"[MQTT-2.3.1-1] packet indentifier must be > 0" 1142 leftlen = self.fh.remainingLength - 2
1143 leftlen -= self.properties.unpack(buffer[-leftlen:])[1]
1146 topic, topiclen =
readUTF(buffer[-leftlen:], leftlen)
1149 options.unpack(buffer[-leftlen:])
1151 self.data.append((topic, options))
1152 assert len(self.
data) > 0,
"[MQTT-3.8.3-1] at least one topic, qos pair must be in subscribe" 1154 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1] DUP must be false in subscribe" 1155 assert self.fh.QoS == 1,
"[MQTT-2.1.2-1] QoS must be 1 in subscribe" 1156 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1] RETAIN must be false in subscribe" 1157 return fhlen + self.fh.remainingLength
1162 ", Data="+str( [(x, str(y))
for (x, y)
in self.
data] ) +
")" 1165 return Packets.__eq__(self, packet)
and \
1167 self.
data == packet.data
1172 def __init__(self, packetType, buffer, DUP, QoS, RETAIN, PacketId, reasonCodes):
1173 object.__setattr__(self,
"names",
1174 [
"fh",
"DUP",
"QoS",
"RETAIN",
"packetIdentifier",
1175 "reasonCodes",
"properties"])
1176 object.__setattr__(self,
"packetType", packetType)
1180 self.fh.RETAIN = RETAIN
1191 buffer += self.properties.pack()
1193 buffer += reasonCode.pack()
1194 buffer = self.fh.pack(
len(buffer)) + buffer
1195 assert len(buffer) >= 3
1199 assert len(buffer) >= 3
1201 fhlen = self.fh.unpack(buffer, maximumPacketSize)
1202 assert len(buffer) >= fhlen + self.fh.remainingLength
1204 leftlen = self.fh.remainingLength - 2
1205 leftlen -= self.properties.unpack(buffer[-leftlen:])[1]
1212 reasonCode.unpack(buffer[-leftlen:])
1213 assert reasonCode.value
in [0, 1, 2, 0x80],
"[MQTT-3.9.3-2] return code in QoS must be 0, 1, 2 or 0x80" 1215 self.reasonCodes.append(reasonCode)
1217 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1] DUP should be false in suback" 1218 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1] QoS should be 0 in suback" 1219 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1] Retain should be false in suback" 1220 return fhlen + self.fh.remainingLength
1225 ", reason codes="+str([str(rc)
for rc
in self.
reasonCodes])+
")" 1228 return Packets.__eq__(self, packet)
and \
1235 def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, PacketId=1, reasonCodes=[]):
1236 UnsubSubacks.__init__(self, PacketTypes.SUBACK, buffer, DUP, QoS, RETAIN, PacketId, reasonCodes)
1241 def __init__(self, buffer=None, DUP=False, QoS=1, RETAIN=False, PacketId=1, TopicFilters=[]):
1242 object.__setattr__(self,
"names",
1243 [
"fh",
"DUP",
"QoS",
"RETAIN",
"packetIdentifier",
"properties",
"topicFilters"])
1247 self.fh.RETAIN = RETAIN
1258 buffer += self.properties.pack()
1261 buffer = self.fh.pack(
len(buffer)) + buffer
1265 assert len(buffer) >= 2
1266 assert PacketType(buffer) == PacketTypes.UNSUBSCRIBE
1267 fhlen = self.fh.unpack(buffer, maximumPacketSize)
1268 assert len(buffer) >= fhlen + self.fh.remainingLength
1269 logger.info(
"[MQTT-2.3.1-1] packet indentifier must be in unsubscribe")
1271 assert self.
packetIdentifier > 0,
"[MQTT-2.3.1-1] packet indentifier must be > 0" 1272 leftlen = self.fh.remainingLength - 2
1273 leftlen -= self.properties.unpack(buffer[-leftlen:])[1]
1276 topic, topiclen =
readUTF(buffer[-leftlen:], leftlen)
1278 self.topicFilters.append(topic)
1280 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1]" 1281 assert self.fh.QoS == 1,
"[MQTT-2.1.2-1]" 1282 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1]" 1283 logger.info(
"[MQTT-3-10.1-1] fixed header bits are 0,0,1,0")
1284 return fhlen + self.fh.remainingLength
1292 return Packets.__eq__(self, packet)
and \
1299 def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, PacketId=1, reasonCodes=[]):
1300 UnsubSubacks.__init__(self, PacketTypes.UNSUBACK, buffer, DUP, QoS, RETAIN,
1301 PacketId, reasonCodes)
1306 def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False):
1307 object.__setattr__(self,
"names", [
"fh",
"DUP",
"QoS",
"RETAIN"])
1311 self.fh.RETAIN = RETAIN
1316 assert len(buffer) >= 2
1317 assert PacketType(buffer) == PacketTypes.PINGREQ
1318 fhlen = self.fh.unpack(buffer, maximumPacketSize)
1319 assert self.fh.remainingLength == 0
1320 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1]" 1321 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1]" 1322 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1]" 1326 return str(self.
fh)+
")" 1331 def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False):
1332 object.__setattr__(self,
"names", [
"fh",
"DUP",
"QoS",
"RETAIN"])
1336 self.fh.RETAIN = RETAIN
1341 assert len(buffer) >= 2
1342 assert PacketType(buffer) == PacketTypes.PINGRESP
1343 fhlen = self.fh.unpack(buffer, maximumPacketSize)
1344 assert self.fh.remainingLength == 0
1345 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1]" 1346 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1]" 1347 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1]" 1351 return str(self.
fh)+
")" 1356 def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False,
1357 reasonCode=
"Normal disconnection"):
1358 object.__setattr__(self,
"names",
1359 [
"fh",
"DUP",
"QoS",
"RETAIN",
"reasonCode",
"properties"])
1363 self.fh.RETAIN = RETAIN
1372 if self.reasonCode.getName() !=
"Normal disconnection" or not self.properties.isEmpty():
1373 buffer += self.reasonCode.pack()
1374 if not self.properties.isEmpty():
1375 buffer += self.properties.pack()
1376 buffer = self.fh.pack(
len(buffer)) + buffer
1380 self.properties.clear()
1381 self.reasonCode.set(
"Normal disconnection")
1382 assert len(buffer) >= 2
1383 assert PacketType(buffer) == PacketTypes.DISCONNECT
1384 fhlen = self.fh.unpack(buffer, maximumPacketSize)
1385 assert len(buffer) >= fhlen + self.fh.remainingLength
1386 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1] DISCONNECT reserved bits must be 0" 1387 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1] DISCONNECT reserved bits must be 0" 1388 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1] DISCONNECT reserved bits must be 0" 1390 if self.fh.remainingLength > 0:
1391 self.reasonCode.unpack(buffer[curlen:])
1393 if self.fh.remainingLength > 1:
1394 curlen += self.properties.unpack(buffer[curlen:])[1]
1395 assert curlen == fhlen + self.fh.remainingLength, \
1396 "DISCONNECT packet is wrong length %d" % self.fh.remainingLength
1397 return fhlen + self.fh.remainingLength
1403 return Packets.__eq__(self, packet)
and \
1410 def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False,
1411 reasonCode=
"Success"):
1412 object.__setattr__(self,
"names",
1413 [
"fh",
"DUP",
"QoS",
"RETAIN",
"reasonCode",
"properties"])
1417 self.fh.RETAIN = RETAIN
1425 buffer = self.reasonCode.pack()
1426 buffer += self.properties.pack()
1427 buffer = self.fh.pack(
len(buffer)) + buffer
1431 assert len(buffer) >= 2
1432 assert PacketType(buffer) == PacketTypes.AUTH
1433 fhlen = self.fh.unpack(buffer, maximumPacketSize)
1434 assert len(buffer) >= fhlen + self.fh.remainingLength
1435 assert self.fh.DUP ==
False,
"[MQTT-2.1.2-1] AUTH reserved bits must be 0" 1436 assert self.fh.QoS == 0,
"[MQTT-2.1.2-1] AUTH reserved bits must be 0" 1437 assert self.fh.RETAIN ==
False,
"[MQTT-2.1.2-1] AUTH reserved bits must be 0" 1439 curlen += self.reasonCode.unpack(buffer[curlen:])
1440 curlen += self.properties.unpack(buffer[curlen:])[1]
1441 assert curlen == fhlen + self.fh.remainingLength, \
1442 "AUTH packet is wrong length %d %d" % (self.fh.remainingLength, curlen)
1443 return fhlen + self.fh.remainingLength
1449 return Packets.__eq__(self, packet)
and \
1454 classes = [Connects, Connacks, Publishes, Pubacks, Pubrecs,
1455 Pubrels, Pubcomps, Subscribes, Subacks, Unsubscribes,
1456 Unsubacks, Pingreqs, Pingresps, Disconnects, Auths]
1461 packet.unpack(buffer, maximumPacketSize=maximumPacketSize)
def __init__(self, packetType)
def __init__(self, ackType, buffer, DUP, QoS, RETAIN, packetId)
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, reasonCode="Normal disconnection")
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, PacketId=1)
def __init__(self, packetType, aName="Success", identifier=-1)
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, PacketId=1)
def unpack(self, buffer, maximumPacketSize)
def __init__(self, QoS=0, noLocal=False, retainAsPublished=False, retainHandling=0)
basic_object< reference > object
def unpack(self, buffer, maximumPacketSize)
def readUTF(buffer, maxlen)
def unpack(self, buffer, maximumPacketSize)
def writeProperty(self, identifier, type, value)
def __init__(self, buffer=None, DUP=False, QoS=1, RETAIN=False, PacketId=1, TopicFilters=[])
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, ReasonCode="Success")
def unpack(self, buffer, maximumPacketSize)
def __init__(self, buffer=None)
def unpack(self, buffer, maximumPacketSize)
def unpack(self, buffer, maximumPacketSize)
def unpack(self, buffer, maximumPacketSize)
def getNameFromIdent(self, identifier)
def unpack(self, buffer, maximumPacketSize)
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, PacketId=1)
FMT_CONSTEXPR bool find(Ptr first, Ptr last, T value, Ptr &out)
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False)
def unpack(self, buffer, maximumPacketSize)
def __setattr__(self, name, value)
def getIdentFromName(self, compressedName)
def __setattr__(self, name, value)
def __setattr__(self, name, value)
def unpack(self, buffer, maximumPacketSize)
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, PacketId=1, reasonCodes=[])
def readProperty(self, buffer, type, propslen)
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False)
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, MsgId=1, TopicName="", Payload=b"")
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, PacketId=1, reasonCodes=[])
def __getName__(self, packetType, identifier)
def unpackPacket(buffer, maximumPacketSize=MAX_PACKET_SIZE)
def __init__(self, buffer=None, DUP=False, QoS=1, RETAIN=False, PacketId=1)
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, reasonCode="Success")
def unpack(self, buffer, maximumPacketSize)
def __init__(self, buffer=None, DUP=False, QoS=1, RETAIN=False, MsgId=1, Data=[])
def __init__(self, packetType, buffer, DUP, QoS, RETAIN, PacketId, reasonCodes)