MQTTV5.py
Go to the documentation of this file.
1 """
2 *******************************************************************
3  Copyright (c) 2013, 2018 IBM Corp.
4 
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.
8 
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.
13 
14  Contributors:
15  Ian Craggs - initial implementation and/or documentation
16  Ian Craggs - take MQTT 3.1.1 and create MQTT 5.0 version
17 *******************************************************************
18 """
19 
20 """
21 
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.
24 
25 """
26 
27 import logging, struct
28 
29 logger = logging.getLogger('MQTTV5')
30 
31 # Low-level protocol interface
32 
33 class MQTTException(Exception):
34  pass
35 
37  pass
38 
40  pass
41 
42 MAX_PACKET_SIZE = 2**28-1
43 MAX_PACKETID = 2**16-1
44 
46 
47  indexes = range(1, 16)
48 
49  # Packet types
50  CONNECT, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL, \
51  PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, \
52  PINGREQ, PINGRESP, DISCONNECT, AUTH = indexes
53 
54  # Dummy packet type for properties use - will delay only applies to will
55  WILLMESSAGE = 99
56 
57 
58 class Packets(object):
59 
60  Names = [ "reserved", \
61  "Connect", "Connack", "Publish", "Puback", "Pubrec", "Pubrel", \
62  "Pubcomp", "Subscribe", "Suback", "Unsubscribe", "Unsuback", \
63  "Pingreq", "Pingresp", "Disconnect", "Auth"]
64 
65  classNames = [name+'es' if name == "Publish" else
66  name+'s' if name != "reserved" else name for name in Names]
67 
68  def pack(self):
69  buffer = self.fh.pack(0)
70  return buffer
71 
72  def __str__(self):
73  return str(self.fh)
74 
75  def __eq__(self, packet):
76  return self.fh == packet.fh if packet else False
77 
78  def __setattr__(self, name, value):
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)
82 
83 
84 def PacketType(byte):
85  """
86  Retrieve the message type from the first byte of the fixed header.
87  """
88  if byte != None:
89  rc = byte[0] >> 4
90  else:
91  rc = None
92  return rc
93 
95  """
96  The reason code used in MQTT V5.0
97 
98  """
99 
100  def __getName__(self, packetType, identifier):
101  """
102  used when displaying the reason code
103  """
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
108  return namelist[0]
109 
110  def getId(self, name):
111  """
112  used when setting the reason code for a packetType
113  check that only valid codes for the packet are set
114  """
115  identifier = None
116  for code in self.names.keys():
117  if name in self.names[code].keys():
118  if self.packetType in self.names[code][name]:
119  identifier = code
120  break
121  assert identifier != None, name
122  return identifier
123 
124  def set(self, name):
125  self.value = self.getId(name)
126 
127  def unpack(self, buffer):
128  name = self.__getName__(self.packetType, buffer[0])
129  self.value = self.getId(name)
130  return 1
131 
132  def getName(self):
133  return self.__getName__(self.packetType, self.value)
134 
135  def __str__(self):
136  return self.getName()
137 
138  def pack(self):
139  return bytes([self.value])
140 
141  def __init__(self, packetType, aName="Success", identifier=-1):
142  self.packetType = packetType
143  self.names = {
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] },
218  }
219  if identifier == -1:
220  self.set(aName)
221  else:
222  self.value = identifier
223  self.getName() # check it's good
224 
225 
226 class VBIs: # Variable Byte Integer
227 
228  @staticmethod
229  def encode(x):
230  """
231  Convert an integer 0 <= x <= 268435455 into multi-byte format.
232  Returns the buffer convered from the integer.
233  """
234  assert 0 <= x <= 268435455
235  buffer = b''
236  while 1:
237  digit = x % 128
238  x //= 128
239  if x > 0:
240  digit |= 0x80
241  buffer += bytes([digit])
242  if x == 0:
243  break
244  return buffer
245 
246  @staticmethod
247  def decode(buffer):
248  """
249  Get the value of a multi-byte integer from a buffer
250  Return the value, and the number of bytes used.
251 
252  [MQTT-1.5.5-1] the encoded value MUST use the minimum number of bytes necessary to represent the value
253  """
254  multiplier = 1
255  value = 0
256  bytes = 0
257  while 1:
258  bytes += 1
259  digit = buffer[0]
260  buffer = buffer[1:]
261  value += (digit & 127) * multiplier
262  if digit & 128 == 0:
263  break
264  multiplier *= 128
265  return (value, bytes)
266 
267 def getPacket(aSocket):
268  "receive the next packet"
269  buf = aSocket.recv(1) # get the first byte fixed header
270  if buf == b"":
271  return None
272  if str(aSocket).find("[closed]") != -1:
273  closed = True
274  else:
275  closed = False
276  if closed:
277  return None
278  # now get the remaining length
279  multiplier = 1
280  remlength = 0
281  while 1:
282  next = aSocket.recv(1)
283  while len(next) == 0:
284  next = aSocket.recv(1)
285  buf += next
286  digit = buf[-1]
287  remlength += (digit & 127) * multiplier
288  if digit & 128 == 0:
289  break
290  multiplier *= 128
291  # receive the remaining length if there is any
292  rest = bytes([])
293  if remlength > 0:
294  while len(rest) < remlength:
295  rest += aSocket.recv(remlength-len(rest))
296  assert len(rest) == remlength
297  return buf + rest
298 
299 
301 
302  def __init__(self, aPacketType):
303  self.PacketType = aPacketType
304  self.DUP = False
305  self.QoS = 0
306  self.RETAIN = False
308 
309  def __eq__(self, fh):
310  return self.PacketType == fh.PacketType and \
311  self.DUP == fh.DUP and \
312  self.QoS == fh.QoS and \
313  self.RETAIN == fh.RETAIN # and \
314  # self.remainingLength == fh.remainingLength
315 
316  def __setattr__(self, name, value):
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)
321 
322  def __str__(self):
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)
326 
327  def pack(self, length):
328  "pack data into string buffer ready for transmission down socket"
329  buffer = bytes([(self.PacketType << 4) | (self.DUP << 3) |\
330  (self.QoS << 1) | self.RETAIN])
331  self.remainingLength = length
332  buffer += VBIs.encode(length)
333  return buffer
334 
335  def unpack(self, buffer, maximumPacketSize):
336  "unpack data from string buffer into separate fields"
337  b0 = buffer[0]
338  self.PacketType = b0 >> 4
339  self.DUP = ((b0 >> 3) & 0x01) == 1
340  self.QoS = (b0 >> 1) & 0x03
341  self.RETAIN = (b0 & 0x01) == 1
342  (self.remainingLength, bytes) = VBIs.decode(buffer[1:])
343  if self.remainingLength + bytes + 1 > maximumPacketSize:
344  raise ProtocolError("Packet too large")
345  return bytes + 1 # length of fixed header
346 
347 
348 def writeInt16(length):
349  return bytes([length // 256, length % 256])
350 
351 def readInt16(buf):
352  return buf[0]*256 + buf[1]
353 
354 def writeInt32(length):
355  buffer = [length // 16777216]
356  length %= 16777216
357  buffer += [length // 65536]
358  length %= 65536
359  buffer += [length // 256, length % 256]
360  return bytes(buffer)
361 
362 def readInt32(buf):
363  return buf[0]*16777216 + buf[1]*65536 + buf[2]*256 + buf[3]
364 
365 def writeUTF(data):
366  # data could be a string, or bytes. If string, encode into bytes with utf-8
367  return writeInt16(len(data)) + (data if type(data) == type(b"") else bytes(data, "utf-8"))
368 
369 def readUTF(buffer, maxlen):
370  if maxlen >= 2:
371  length = readInt16(buffer)
372  else:
373  raise MalformedPacket("Not enough data to read string length")
374  maxlen -= 2
375  if length > maxlen:
376  raise MalformedPacket("Length delimited string too long")
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") # look for null in the UTF string
380  if zz != -1:
381  raise MalformedPacket("[MQTT-1.5.4-2] Null found in UTF data "+buf)
382  for c in range (0xD800, 0xDFFF):
383  zz = buf.find(chr(c)) # look for D800-DFFF in the UTF string
384  if zz != -1:
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")
388  return buf, length+2
389 
390 def writeBytes(buffer):
391  return writeInt16(len(buffer)) + buffer
392 
393 def readBytes(buffer):
394  length = readInt16(buffer)
395  return buffer[2:2+length], length+2
396 
397 
399 
400  def __init__(self, packetType):
401  self.packetType = packetType
402  self.types = ["Byte", "Two Byte Integer", "Four Byte Integer", "Variable Byte Integer",
403  "Binary Data", "UTF-8 Encoded String", "UTF-8 String Pair"]
404 
405  self.names = {
406  "Payload Format Indicator" : 1,
407  "Message Expiry Interval" : 2,
408  "Content Type" : 3,
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,
425  "Topic Alias" : 35,
426  "Maximum QoS" : 36,
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
433  }
434 
435  self.properties = {
436  # id: type, packets
437  1 : (self.types.index("Byte"), [PacketTypes.PUBLISH, PacketTypes.WILLMESSAGE]), # payload format indicator
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]),
482  }
483 
484  def getIdentFromName(self, compressedName):
485  # return the identifier corresponding to the property name
486  result = -1
487  for name in self.names.keys():
488  if compressedName == name.replace(' ', ''):
489  result = self.names[name]
490  break
491  return result
492 
493  def __setattr__(self, name, value):
494  name = name.replace(' ', '')
495  privateVars = ["packetType", "types", "names", "properties"]
496  if name in privateVars:
497  object.__setattr__(self, name, value)
498  else:
499  # the name could have spaces in, or not. Remove spaces before assignment
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()))
502  # check that this attribute applies to the packet type
503  if self.packetType not in self.properties[self.getIdentFromName(name)][1]:
504  raise MQTTException("Attribute %s does not apply to packet type %s"
505  % (name, Packets.Names[self.packetType]) )
506  object.__setattr__(self, name, value)
507 
508  def __str__(self):
509  buffer = "["
510  first = True
511  for name in self.names.keys():
512  compressedName = name.replace(' ', '')
513  if hasattr(self, compressedName):
514  if not first:
515  buffer += ", "
516  buffer += compressedName +" : "+str(getattr(self, compressedName))
517  first = False
518  buffer += "]"
519  return buffer
520 
521  def isEmpty(self):
522  rc = True
523  for name in self.names.keys():
524  compressedName = name.replace(' ', '')
525  if hasattr(self, compressedName):
526  rc = False
527  break
528  return rc
529 
530  def clear(self):
531  for name in self.names.keys():
532  compressedName = name.replace(' ', '')
533  if hasattr(self, compressedName):
534  delattr(self, compressedName)
535 
536  def writeProperty(self, identifier, type, value):
537  buffer = b""
538  buffer += VBIs.encode(identifier) # identifier
539  if type == self.types.index("Byte"): # value
540  buffer += bytes([value])
541  elif type == self.types.index("Two Byte Integer"):
542  buffer += writeInt16(value)
543  elif type == self.types.index("Four Byte Integer"):
544  buffer += writeInt32(value)
545  elif type == self.types.index("Variable Byte Integer"):
546  buffer += VBIs.encode(value)
547  elif type == self.types.index("Binary Data"):
548  buffer += writeBytes(value)
549  elif type == self.types.index("UTF-8 Encoded String"):
550  buffer += writeUTF(value)
551  elif type == self.types.index("UTF-8 String Pair"):
552  buffer += writeUTF(value[0]) + writeUTF(value[1])
553  return buffer
554 
555  def pack(self):
556  # serialize properties into buffer for sending over network
557  buffer = b""
558  for name in self.names.keys():
559  compressedName = name.replace(' ', '')
560  isList = False
561  if compressedName.endswith('List'):
562  isList = True
563  if hasattr(self, compressedName):
564  identifier = self.getIdentFromName(compressedName)
565  attr_type = self.properties[identifier][0]
566  if isList:
567  for prop in getattr(self, compressedName):
568  buffer += self.writeProperty(identifier, attr_type, prop)
569  else:
570  buffer += self.writeProperty(identifier, attr_type,
571  getattr(self, compressedName))
572  return VBIs.encode(len(buffer)) + buffer
573 
574  def readProperty(self, buffer, type, propslen):
575  if type == self.types.index("Byte"):
576  value = buffer[0]
577  valuelen = 1
578  elif type == self.types.index("Two Byte Integer"):
579  value = readInt16(buffer)
580  valuelen = 2
581  elif type == self.types.index("Four Byte Integer"):
582  value = readInt32(buffer)
583  valuelen = 4
584  elif type == self.types.index("Variable Byte Integer"):
585  value, valuelen = VBIs.decode(buffer)
586  elif type == self.types.index("Binary Data"):
587  value, valuelen = readBytes(buffer)
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:] # strip the bytes used by the value
593  value1, valuelen1 = readUTF(buffer, propslen - valuelen)
594  value = (value, value1)
595  valuelen += valuelen1
596  return value, valuelen
597 
598  def getNameFromIdent(self, identifier):
599  rc = None
600  for name in self.names:
601  if self.names[name] == identifier:
602  rc = name
603  return rc
604 
605  def unpack(self, buffer):
606  self.clear()
607  # deserialize properties into attributes from buffer received from network
608  propslen, VBIlen = VBIs.decode(buffer)
609  buffer = buffer[VBIlen:] # strip the bytes used by the VBI
610  propslenleft = propslen
611  while propslenleft > 0: # properties length is 0 if there are none
612  identifier, VBIlen = VBIs.decode(buffer) # property identifier
613  buffer = buffer[VBIlen:] # strip the bytes used by the VBI
614  propslenleft -= VBIlen
615  attr_type = self.properties[identifier][0]
616  value, valuelen = self.readProperty(buffer, attr_type, propslenleft)
617  buffer = buffer[valuelen:] # strip the bytes used by the value
618  propslenleft -= valuelen
619  propname = self.getNameFromIdent(identifier)
620  compressedName = propname.replace(' ', '')
621  if propname.endswith('List'):
622  if not hasattr(self, compressedName):
623  setattr(self, propname, [value])
624  else:
625  setattr(self, propname, getattr(self, compressedName) + [value])
626  else:
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
631 
632 
634 
635  def __init__(self, buffer = None):
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"])
641 
642  self.fh = FixedHeaders(PacketTypes.CONNECT)
643 
644  # variable header
645  self.ProtocolName = "MQTT"
647  self.CleanStart = True
648  self.WillFlag = False
649  self.WillQoS = 0
650  self.WillRETAIN = 0
651  self.KeepAliveTimer = 30
652  self.usernameFlag = False
653  self.passwordFlag = False
654 
655  self.properties = Properties(PacketTypes.CONNECT)
656  self.willProperties = Properties(PacketTypes.WILLMESSAGE)
657 
658  # Payload
659  self.ClientIdentifier = "" # UTF-8
660  self.WillTopic = None # UTF-8
661  self.WillMessage = None # binary
662  self.username = None # UTF-8
663  self.password = None # binary
664 
665  #self.properties = Properties()
666  if buffer != None:
667  self.unpack(buffer)
668 
669  def pack(self):
670  connectFlags = bytes([(self.CleanStart << 1) | (self.WillFlag << 2) | \
671  (self.WillQoS << 3) | (self.WillRETAIN << 5) | \
672  (self.usernameFlag << 6) | (self.passwordFlag << 7)])
673  buffer = writeUTF(self.ProtocolName) + bytes([self.ProtocolVersion]) + \
674  connectFlags + writeInt16(self.KeepAliveTimer)
675  buffer += self.properties.pack()
676  buffer += writeUTF(self.ClientIdentifier)
677  if self.WillFlag:
678  assert self.willProperties.packetType == PacketTypes.WILLMESSAGE
679  buffer += self.willProperties.pack()
680  buffer += writeUTF(self.WillTopic)
681  buffer += writeBytes(self.WillMessage)
682  if self.usernameFlag:
683  buffer += writeUTF(self.username)
684  if self.passwordFlag:
685  buffer += writeBytes(self.password)
686  buffer = self.fh.pack(len(buffer)) + buffer
687  return buffer
688 
689  def unpack(self, buffer, maximumPacketSize):
690  assert len(buffer) >= 2
691  assert PacketType(buffer) == PacketTypes.CONNECT
692 
693  try:
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)
697  curlen = fhlen # points to after header + remaining length
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]"
701 
702  # to allow the server to send back a CONNACK with unsupported protocol version,
703  # the following two assertions will need to be disabled
704  self.ProtocolName, valuelen = readUTF(buffer[curlen:], packlen - curlen)
705  curlen += valuelen
706  assert self.ProtocolName == "MQTT", "Wrong protocol name %s" % self.ProtocolName
707 
708  self.ProtocolVersion = buffer[curlen]
709  curlen += 1
710  assert self.ProtocolVersion == 5, "Wrong protocol version %s" % self.ProtocolVersion
711 
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
717  self.WillRETAIN = (connectFlags >> 5) & 0x01
718  self.passwordFlag = ((connectFlags >> 6) & 0x01) == 1
719  self.usernameFlag = ((connectFlags >> 7) & 0x01) == 1
720  curlen += 1
721 
722  if self.WillFlag:
723  assert self.WillQoS in [0, 1, 2], "[MQTT-3.1.2-12] will qos must not be 3"
724  else:
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"
727 
728  self.KeepAliveTimer = readInt16(buffer[curlen:])
729  curlen += 2
730 
731  curlen += self.properties.unpack(buffer[curlen:])[1]
732 
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")
735  self.ClientIdentifier, valuelen = readUTF(buffer[curlen:], packlen - curlen)
736  curlen += valuelen
737 
738  if self.WillFlag:
739  curlen += self.willProperties.unpack(buffer[curlen:])[1]
740  self.WillTopic, valuelen = readUTF(buffer[curlen:], packlen - curlen)
741  curlen += valuelen
742  self.WillMessage, valuelen = readBytes(buffer[curlen:])
743  curlen += valuelen
744  logger.info("[[MQTT-3.1.2-9] will topic and will message fields must be present")
745  else:
746  self.WillTopic = self.WillMessage = None
747 
748  if self.usernameFlag:
749  assert len(buffer) > curlen+2, "Buffer too short to read username length"
750  self.username, valuelen = readUTF(buffer[curlen:], packlen - curlen)
751  curlen += valuelen
752  logger.info("[MQTT-3.1.2-19] username must be in payload if user name flag is 1")
753  else:
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"
756 
757  if self.passwordFlag:
758  assert len(buffer) > curlen+2, "Buffer too short to read password length"
759  self.password, valuelen = readBytes(buffer[curlen:])
760  curlen += valuelen
761  logger.info("[MQTT-3.1.2-21] password must be in payload if password flag is 0")
762  else:
763  logger.info("[MQTT-3.1.2-20] password must not be in payload if password flag is 0")
764 
765  if self.WillFlag and self.usernameFlag and self.passwordFlag:
766  logger.info("[MQTT-3.1.3-1] clientid, will topic, will message, username and password all present")
767 
768  assert curlen == packlen, "Packet is wrong length curlen %d != packlen %d" % (curlen, packlen)
769  except:
770  logger.exception("[MQTT-3.1.4-1] server must validate connect packet and close connection without connack if it does not conform")
771  raise
772 
773  def __str__(self):
774  buf = str(self.fh)+", ProtocolName="+str(self.ProtocolName)+", ProtocolVersion=" +\
775  str(self.ProtocolVersion)+", CleanStart="+str(self.CleanStart) +\
776  ", WillFlag="+str(self.WillFlag)+", KeepAliveTimer=" +\
777  str(self.KeepAliveTimer)+", ClientId="+str(self.ClientIdentifier) +\
778  ", usernameFlag="+str(self.usernameFlag)+", passwordFlag="+str(self.passwordFlag)
779  if self.WillFlag:
780  buf += ", WillQoS=" + str(self.WillQoS) +\
781  ", WillRETAIN=" + str(self.WillRETAIN) +\
782  ", WillTopic='"+ self.WillTopic +\
783  "', WillMessage='"+str(self.WillMessage)+"'"
784  if self.username:
785  buf += ", username="+self.username
786  if self.password:
787  buf += ", password="+str(self.password)
788  buf += ", properties="+str(self.properties)
789  return buf+")"
790 
791  def __eq__(self, packet):
792  rc = Packets.__eq__(self, packet) and \
793  self.ProtocolName == packet.ProtocolName and \
794  self.ProtocolVersion == packet.ProtocolVersion and \
795  self.CleanStart == packet.CleanStart and \
796  self.WillFlag == packet.WillFlag and \
797  self.KeepAliveTimer == packet.KeepAliveTimer and \
798  self.ClientIdentifier == packet.ClientIdentifier and \
799  self.WillFlag == packet.WillFlag
800  if rc and self.WillFlag:
801  rc = self.WillQoS == packet.WillQoS and \
802  self.WillRETAIN == packet.WillRETAIN and \
803  self.WillTopic == packet.WillTopic and \
804  self.WillMessage == packet.WillMessage
805  if rc:
806  rc = self.properties == packet.properties
807  return rc
808 
809 
811 
812  def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, ReasonCode="Success"):
813  object.__setattr__(self, "names",
814  ["fh", "sessionPresent", "reasonCode", "properties"])
815  self.fh = FixedHeaders(PacketTypes.CONNACK)
816  self.fh.DUP = DUP
817  self.fh.QoS = QoS
818  self.fh.RETAIN = RETAIN
819  self.sessionPresent = False
820  self.reasonCode = ReasonCodes(PacketTypes.CONNACK, ReasonCode)
821  self.properties = Properties(PacketTypes.CONNACK)
822  if buffer != None:
823  self.unpack(buffer)
824 
825  def pack(self):
826  flags = 0x01 if self.sessionPresent else 0x00
827  buffer = bytes([flags])
828  buffer += self.reasonCode.pack()
829  buffer += self.properties.pack()
830  buffer = self.fh.pack(len(buffer)) + buffer
831  return buffer
832 
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"
838  self.sessionPresent = (buffer[curlen] == 0x01)
839  curlen += 1
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]"
845 
846  def __str__(self):
847  return str(self.fh)+", Session present="+str((self.sessionPresent & 0x01) == 1)+\
848  ", ReturnCode="+str(self.reasonCode)+\
849  ", properties="+str(self.properties)+")"
850 
851  def __eq__(self, packet):
852  return Packets.__eq__(self, packet) and \
853  self.reasonCode == packet.reasonCode
854 
855 
857 
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"])
862  self.fh = FixedHeaders(PacketTypes.DISCONNECT)
863  self.fh.DUP = DUP
864  self.fh.QoS = QoS
865  self.fh.RETAIN = RETAIN
866  # variable header
867  self.reasonCode = ReasonCodes(PacketTypes.DISCONNECT, identifier=reasonCode)
868  self.properties = Properties(PacketTypes.DISCONNECT)
869  if buffer != None:
870  self.unpack(buffer)
871 
872  def pack(self):
873  buffer = b""
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
879  return buffer
880 
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"
891  curlen = 0
892  if self.fh.remainingLength > 0:
893  self.reasonCode.unpack(buffer[curlen:])
894  curlen += 1
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
900 
901  def __str__(self):
902  return str(self.fh)+", ReasonCode: "+str(self.reasonCode)+", Properties: "+str(self.properties)
903 
904  def __eq__(self, packet):
905  return Packets.__eq__(self, packet) and \
906  self.reasonCode == packet.reasonCode and \
907  self.properties == packet.properties
908 
909 
911 
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"])
916  self.fh = FixedHeaders(PacketTypes.PUBLISH)
917  self.fh.DUP = DUP
918  self.fh.QoS = QoS
919  self.fh.RETAIN = RETAIN
920  # variable header
921  self.topicName = TopicName
922  self.packetIdentifier = MsgId
923  self.properties = Properties(PacketTypes.PUBLISH)
924  # payload
925  self.data = Payload
926  if buffer != None:
927  self.unpack(buffer)
928 
929  def pack(self):
930  buffer = writeUTF(self.topicName)
931  if self.fh.QoS != 0:
932  buffer += writeInt16(self.packetIdentifier)
933  buffer += self.properties.pack()
934  buffer += self.data
935  buffer = self.fh.pack(len(buffer)) + buffer
936  return buffer
937 
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
945  curlen = fhlen
946  try:
947  self.topicName, valuelen = readUTF(buffer[fhlen:], packlen - curlen)
948  except UnicodeDecodeError:
949  logger.info("[MQTT-3.3.2-1] topic name in publish must be utf-8")
950  raise
951  curlen += valuelen
952  if self.fh.QoS != 0:
953  self.packetIdentifier = readInt16(buffer[curlen:])
954  logger.info("[MQTT-2.3.1-1] packet indentifier must be in publish if QoS is 1 or 2")
955  curlen += 2
956  assert self.packetIdentifier > 0, "[MQTT-2.3.1-1] packet indentifier must be > 0"
957  else:
958  logger.info("[MQTT-2.3.1-5] no packet indentifier in publish if QoS is 0")
959  self.packetIdentifier = 0
960  curlen += self.properties.unpack(buffer[curlen:])[1]
961  self.data = buffer[curlen:fhlen + self.fh.remainingLength]
962  if self.fh.QoS == 0:
963  assert self.fh.DUP == False, "[MQTT-2.1.2-4]"
964  return fhlen + self.fh.remainingLength
965 
966  def __str__(self):
967  rc = str(self.fh)
968  if self.fh.QoS != 0:
969  rc += ", PacketId="+str(self.packetIdentifier)
970  rc += ", Properties: "+str(self.properties)
971  rc += ", TopicName="+str(self.topicName)+", Payload="+str(self.data)+")"
972  return rc
973 
974  def __eq__(self, packet):
975  rc = Packets.__eq__(self, packet) and \
976  self.topicName == packet.topicName and \
977  self.data == packet.data
978  if rc and self.fh.QoS != 0:
979  rc = self.packetIdentifier == packet.packetIdentifier
980  return rc
981 
982 
983 class Acks(Packets):
984 
985  def __init__(self, ackType, buffer, DUP, QoS, RETAIN, packetId):
986  object.__setattr__(self, "names",
987  ["fh", "DUP", "QoS", "RETAIN", "packetIdentifier",
988  "reasonCode", "properties"])
989  self.fh = FixedHeaders(ackType)
990  self.fh.DUP = DUP
991  self.fh.QoS = QoS
992  self.fh.RETAIN = RETAIN
993  # variable header
994  self.packetIdentifier = packetId
995  self.reasonCode = ReasonCodes(ackType)
996  self.properties = Properties(ackType)
997  object.__setattr__(self, "ackType", ackType)
998  object.__setattr__(self, "ackName", Packets.Names[self.ackType])
999  if buffer != None:
1000  self.unpack(buffer)
1001 
1002  def pack(self):
1003  buffer = writeInt16(self.packetIdentifier)
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
1009  return buffer
1010 
1011  def unpack(self, buffer, maximumPacketSize):
1012  self.properties.clear()
1013  self.reasonCode.set("Success")
1014  assert len(buffer) >= 2
1015  assert PacketType(buffer) == self.ackType
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
1020  self.packetIdentifier = readInt16(buffer[fhlen:])
1021  curlen = fhlen + 2
1022  assert self.fh.DUP == False, "[MQTT-2.1.2-1] %s reserved bits must be 0" %\
1023  self.ackName
1024  if self.ackType == PacketTypes.PUBREL:
1025  assert self.fh.QoS == 1, "[MQTT-3.6.1-1] %s reserved bits must be 0010" %\
1026  self.ackName
1027  else:
1028  assert self.fh.QoS == 0, "[MQTT-2.1.2-1] %s reserved bits must be 0" %\
1029  self.ackName
1030  assert self.fh.RETAIN == False, "[MQTT-2.1.2-1] %s reserved bits must be 0" %\
1031  self.ackName
1032  if self.fh.remainingLength > 2:
1033  self.reasonCode.unpack(buffer[curlen:])
1034  curlen += 1
1035  if self.fh.remainingLength > 3:
1036  self.properties.unpack(buffer[curlen:])
1037  return fhlen + self.fh.remainingLength
1038 
1039  def __str__(self):
1040  return str(self.fh)+", PacketId="+str(self.packetIdentifier)+")"
1041 
1042  def __eq__(self, packet):
1043  return Packets.__eq__(self, packet) and \
1044  self.packetIdentifier == packet.packetIdentifier
1045 
1046 
1047 class Pubacks(Acks):
1048 
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)
1051 
1052 class Pubrecs(Acks):
1053 
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)
1056 
1057 class Pubrels(Acks):
1058 
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)
1061 
1063 
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)
1066 
1068 
1069  def __init__(self, QoS=0, noLocal=False, retainAsPublished=False, retainHandling=0):
1070  object.__setattr__(self, "names",
1071  ["QoS", "noLocal", "retainAsPublished", "retainHandling"])
1072  self.QoS = QoS # bits 0,1
1073  self.noLocal = noLocal # bit 2
1074  self.retainAsPublished = retainAsPublished # bit 3
1075  self.retainHandling = retainHandling # bits 4 and 5: 0, 1 or 2
1076 
1077  def __setattr__(self, name, value):
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)
1081 
1082  def pack(self):
1083  assert self.QoS in [0, 1, 2]
1084  assert self.retainHandling in [0, 1, 2]
1085  noLocal = 1 if self.noLocal else 0
1086  retainAsPublished = 1 if self.retainAsPublished else 0
1087  buffer = bytes([(self.retainHandling << 4) | (retainAsPublished << 3) |\
1088  (noLocal << 2) | self.QoS])
1089  return buffer
1090 
1091  def unpack(self, buffer):
1092  b0 = buffer[0]
1093  self.retainHandling = ((b0 >> 4) & 0x03)
1094  self.retainAsPublished = True if ((b0 >> 3) & 0x01) == 1 else False
1095  self.noLocal = True if ((b0 >> 2) & 0x01) == 1 else False
1096  self.QoS = (b0 & 0x03)
1097  assert self.retainHandling in [0, 1, 2]
1098  assert self.QoS in [0, 1, 2]
1099  return 1
1100 
1101  def __str__(self):
1102  return "{QoS="+str(self.QoS)+", noLocal="+str(self.noLocal)+\
1103  ", retainAsPublished="+str(self.retainAsPublished)+\
1104  ", retainHandling="+str(self.retainHandling)+"}"
1105 
1106 
1108 
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"])
1113  self.fh = FixedHeaders(PacketTypes.SUBSCRIBE)
1114  self.fh.DUP = DUP
1115  self.fh.QoS = QoS
1116  self.fh.RETAIN = RETAIN
1117  # variable header
1118  self.packetIdentifier = MsgId
1119  self.properties = Properties(PacketTypes.SUBSCRIBE)
1120  # payload - list of topic, subscribe option pairs
1121  self.data = Data[:]
1122  if buffer != None:
1123  self.unpack(buffer)
1124 
1125  def pack(self):
1126  buffer = writeInt16(self.packetIdentifier)
1127  buffer += self.properties.pack()
1128  for d in self.data:
1129  buffer += writeUTF(d[0]) + d[1].pack()
1130  buffer = self.fh.pack(len(buffer)) + buffer
1131  return buffer
1132 
1133  def unpack(self, buffer, maximumPacketSize):
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")
1140  self.packetIdentifier = readInt16(buffer[fhlen:])
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]
1144  self.data = []
1145  while leftlen > 0:
1146  topic, topiclen = readUTF(buffer[-leftlen:], leftlen)
1147  leftlen -= topiclen
1148  options = SubscribeOptions()
1149  options.unpack(buffer[-leftlen:])
1150  leftlen -= 1
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"
1153  assert leftlen == 0
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
1158 
1159  def __str__(self):
1160  return str(self.fh)+", PacketId="+str(self.packetIdentifier)+\
1161  ", Properties: "+str(self.properties)+\
1162  ", Data="+str( [(x, str(y)) for (x, y) in self.data] ) +")"
1163 
1164  def __eq__(self, packet):
1165  return Packets.__eq__(self, packet) and \
1166  self.packetIdentifier == packet.packetIdentifier and \
1167  self.data == packet.data
1168 
1169 
1171 
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)
1178  self.fh.DUP = DUP
1179  self.fh.QoS = QoS
1180  self.fh.RETAIN = RETAIN
1181  # variable header
1182  self.packetIdentifier = PacketId
1184  # payload - list of reason codes corresponding to topics in subscribe
1185  self.reasonCodes = reasonCodes[:]
1186  if buffer != None:
1187  self.unpack(buffer)
1188 
1189  def pack(self):
1190  buffer = writeInt16(self.packetIdentifier)
1191  buffer += self.properties.pack()
1192  for reasonCode in self.reasonCodes:
1193  buffer += reasonCode.pack()
1194  buffer = self.fh.pack(len(buffer)) + buffer
1195  assert len(buffer) >= 3 # must have property field, even if empty
1196  return buffer
1197 
1198  def unpack(self, buffer, maximumPacketSize):
1199  assert len(buffer) >= 3
1200  assert PacketType(buffer) == self.packetType
1201  fhlen = self.fh.unpack(buffer, maximumPacketSize)
1202  assert len(buffer) >= fhlen + self.fh.remainingLength
1203  self.packetIdentifier = readInt16(buffer[fhlen:])
1204  leftlen = self.fh.remainingLength - 2
1205  leftlen -= self.properties.unpack(buffer[-leftlen:])[1]
1206  self.reasonCodes = []
1207  while leftlen > 0:
1208  if self.packetType == PacketTypes.SUBACK:
1209  reasonCode = ReasonCodes(self.packetType, "Granted QoS 0")
1210  else:
1211  reasonCode = ReasonCodes(self.packetType, "Success")
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"
1214  leftlen -= 1
1215  self.reasonCodes.append(reasonCode)
1216  assert leftlen == 0
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
1221 
1222  def __str__(self):
1223  return str(self.fh)+", PacketId="+str(self.packetIdentifier)+\
1224  ", Properties: "+str(self.properties)+\
1225  ", reason codes="+str([str(rc) for rc in self.reasonCodes])+")"
1226 
1227  def __eq__(self, packet):
1228  return Packets.__eq__(self, packet) and \
1229  self.packetIdentifier == packet.packetIdentifier and \
1230  self.data == packet.data
1231 
1232 
1234 
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)
1237 
1238 
1240 
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"])
1244  self.fh = FixedHeaders(PacketTypes.UNSUBSCRIBE)
1245  self.fh.DUP = DUP
1246  self.fh.QoS = QoS
1247  self.fh.RETAIN = RETAIN
1248  # variable header
1249  self.packetIdentifier = PacketId
1250  self.properties = Properties(PacketTypes.UNSUBSCRIBE)
1251  # payload - list of topics
1252  self.topicFilters = TopicFilters[:]
1253  if buffer != None:
1254  self.unpack(buffer)
1255 
1256  def pack(self):
1257  buffer = writeInt16(self.packetIdentifier)
1258  buffer += self.properties.pack()
1259  for topicFilter in self.topicFilters:
1260  buffer += writeUTF(topicFilter)
1261  buffer = self.fh.pack(len(buffer)) + buffer
1262  return buffer
1263 
1264  def unpack(self, buffer, maximumPacketSize):
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")
1270  self.packetIdentifier = readInt16(buffer[fhlen:])
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]
1274  self.topicFilters = []
1275  while leftlen > 0:
1276  topic, topiclen = readUTF(buffer[-leftlen:], leftlen)
1277  leftlen -= topiclen
1278  self.topicFilters.append(topic)
1279  assert leftlen == 0
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
1285 
1286  def __str__(self):
1287  return str(self.fh)+", PacketId="+str(self.packetIdentifier)+\
1288  ", Properties: "+str(self.properties)+\
1289  ", Data="+str(self.topicFilters)+")"
1290 
1291  def __eq__(self, packet):
1292  return Packets.__eq__(self, packet) and \
1293  self.packetIdentifier == packet.packetIdentifier and \
1294  self.topicFilters == packet.topicFilters
1295 
1296 
1298 
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)
1302 
1303 
1305 
1306  def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False):
1307  object.__setattr__(self, "names", ["fh", "DUP", "QoS", "RETAIN"])
1308  self.fh = FixedHeaders(PacketTypes.PINGREQ)
1309  self.fh.DUP = DUP
1310  self.fh.QoS = QoS
1311  self.fh.RETAIN = RETAIN
1312  if buffer != None:
1313  self.unpack(buffer)
1314 
1315  def unpack(self, buffer, maximumPacketSize):
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]"
1323  return fhlen
1324 
1325  def __str__(self):
1326  return str(self.fh)+")"
1327 
1328 
1330 
1331  def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False):
1332  object.__setattr__(self, "names", ["fh", "DUP", "QoS", "RETAIN"])
1333  self.fh = FixedHeaders(PacketTypes.PINGRESP)
1334  self.fh.DUP = DUP
1335  self.fh.QoS = QoS
1336  self.fh.RETAIN = RETAIN
1337  if buffer != None:
1338  self.unpack(buffer)
1339 
1340  def unpack(self, buffer, maximumPacketSize):
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]"
1348  return fhlen
1349 
1350  def __str__(self):
1351  return str(self.fh)+")"
1352 
1353 
1354 class Disconnects(Packets):
1355 
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"])
1360  self.fh = FixedHeaders(PacketTypes.DISCONNECT)
1361  self.fh.DUP = DUP
1362  self.fh.QoS = QoS
1363  self.fh.RETAIN = RETAIN
1364  # variable header
1365  self.reasonCode = ReasonCodes(PacketTypes.DISCONNECT, aName=reasonCode)
1366  self.properties = Properties(PacketTypes.DISCONNECT)
1367  if buffer != None:
1368  self.unpack(buffer)
1369 
1370  def pack(self):
1371  buffer = b""
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
1377  return buffer
1378 
1379  def unpack(self, buffer, maximumPacketSize):
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"
1389  curlen = fhlen
1390  if self.fh.remainingLength > 0:
1391  self.reasonCode.unpack(buffer[curlen:])
1392  curlen += 1
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
1398 
1399  def __str__(self):
1400  return str(self.fh)+", ReasonCode: "+str(self.reasonCode)+", Properties: "+str(self.properties)
1401 
1402  def __eq__(self, packet):
1403  return Packets.__eq__(self, packet) and \
1404  self.reasonCode == packet.reasonCode and \
1405  self.properties == packet.properties
1406 
1407 
1409 
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"])
1414  self.fh = FixedHeaders(PacketTypes.AUTH)
1415  self.fh.DUP = DUP
1416  self.fh.QoS = QoS
1417  self.fh.RETAIN = RETAIN
1418  # variable header
1419  self.reasonCode = ReasonCodes(PacketTypes.AUTH, reasonCode)
1420  self.properties = Properties(PacketTypes.AUTH)
1421  if buffer != None:
1422  self.unpack(buffer)
1423 
1424  def pack(self):
1425  buffer = self.reasonCode.pack()
1426  buffer += self.properties.pack()
1427  buffer = self.fh.pack(len(buffer)) + buffer
1428  return buffer
1429 
1430  def unpack(self, buffer, maximumPacketSize):
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"
1438  curlen = fhlen
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
1444 
1445  def __str__(self):
1446  return str(self.fh)+", ReasonCode: "+str(self.reasonCode)+", Properties: "+str(self.properties)
1447 
1448  def __eq__(self, packet):
1449  return Packets.__eq__(self, packet) and \
1450  self.reasonCode == packet.reasonCode and \
1451  self.properties == packet.properties
1452 
1453 
1454 classes = [Connects, Connacks, Publishes, Pubacks, Pubrecs,
1455  Pubrels, Pubcomps, Subscribes, Subacks, Unsubscribes,
1456  Unsubacks, Pingreqs, Pingresps, Disconnects, Auths]
1457 
1458 def unpackPacket(buffer, maximumPacketSize=MAX_PACKET_SIZE):
1459  if PacketType(buffer) != None:
1460  packet = classes[PacketType(buffer)-1]()
1461  packet.unpack(buffer, maximumPacketSize=maximumPacketSize)
1462  else:
1463  packet = None
1464  return packet
def __init__(self, packetType)
Definition: MQTTV5.py:400
def __str__(self)
Definition: MQTTV5.py:1445
def __init__(self, ackType, buffer, DUP, QoS, RETAIN, packetId)
Definition: MQTTV5.py:985
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, reasonCode="Normal disconnection")
Definition: MQTTV5.py:859
def __str__(self)
Definition: MQTTV5.py:1350
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, PacketId=1)
Definition: MQTTV5.py:1064
def __init__(self, packetType, aName="Success", identifier=-1)
Definition: MQTTV5.py:141
def __str__(self)
Definition: MQTTV5.py:773
def writeInt16(length)
Definition: MQTTV5.py:348
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, PacketId=1)
Definition: MQTTV5.py:1054
def unpack(self, buffer, maximumPacketSize)
Definition: MQTTV5.py:1133
def __init__(self, QoS=0, noLocal=False, retainAsPublished=False, retainHandling=0)
Definition: MQTTV5.py:1069
basic_object< reference > object
Definition: forward.hpp:717
def __str__(self)
Definition: MQTTV5.py:1222
def unpack(self, buffer, maximumPacketSize)
Definition: MQTTV5.py:938
def readUTF(buffer, maxlen)
Definition: MQTTV5.py:369
def unpack(self, buffer, maximumPacketSize)
Definition: MQTTV5.py:1011
def readBytes(buffer)
Definition: MQTTV5.py:393
def writeUTF(data)
Definition: MQTTV5.py:365
def writeProperty(self, identifier, type, value)
Definition: MQTTV5.py:536
def __eq__(self, packet)
Definition: MQTTV5.py:75
def readInt16(buf)
Definition: MQTTV5.py:351
def unpack(self, buffer)
Definition: MQTTV5.py:127
def __init__(self, buffer=None, DUP=False, QoS=1, RETAIN=False, PacketId=1, TopicFilters=[])
Definition: MQTTV5.py:1241
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, ReasonCode="Success")
Definition: MQTTV5.py:812
def pack(self)
Definition: MQTTV5.py:825
def __str__(self)
Definition: MQTTV5.py:135
def unpack(self, buffer, maximumPacketSize)
Definition: MQTTV5.py:833
def encode(x)
Definition: MQTTV5.py:229
def pack(self, length)
Definition: MQTTV5.py:327
def __init__(self, buffer=None)
Definition: MQTTV5.py:635
def unpack(self, buffer, maximumPacketSize)
Definition: MQTTV5.py:1264
def unpack(self, buffer, maximumPacketSize)
Definition: MQTTV5.py:335
def unpack(self, buffer, maximumPacketSize)
Definition: MQTTV5.py:1430
def readInt32(buf)
Definition: MQTTV5.py:362
def unpack(self, buffer, maximumPacketSize)
Definition: MQTTV5.py:689
def writeBytes(buffer)
Definition: MQTTV5.py:390
def pack(self)
Definition: MQTTV5.py:1256
def PacketType(byte)
Definition: MQTTV5.py:84
def isEmpty(self)
Definition: MQTTV5.py:521
def unpack(self, buffer)
Definition: MQTTV5.py:1091
def clear(self)
Definition: MQTTV5.py:530
def __str__(self)
Definition: MQTTV5.py:901
def __str__(self)
Definition: MQTTV5.py:322
def getNameFromIdent(self, identifier)
Definition: MQTTV5.py:598
def getId(self, name)
Definition: MQTTV5.py:110
def pack(self)
Definition: MQTTV5.py:929
def __str__(self)
Definition: MQTTV5.py:1039
def pack(self)
Definition: MQTTV5.py:1002
def unpack(self, buffer, maximumPacketSize)
Definition: MQTTV5.py:1340
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, PacketId=1)
Definition: MQTTV5.py:1049
def __eq__(self, packet)
Definition: MQTTV5.py:1164
FMT_CONSTEXPR bool find(Ptr first, Ptr last, T value, Ptr &out)
Definition: format.h:2881
def __eq__(self, packet)
Definition: MQTTV5.py:1227
def pack(self)
Definition: MQTTV5.py:68
def __setattr__(self, name, value)
Definition: MQTTV5.py:316
def __str__(self)
Definition: MQTTV5.py:1159
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False)
Definition: MQTTV5.py:1306
def unpack(self, buffer)
Definition: MQTTV5.py:605
def getName(self)
Definition: MQTTV5.py:132
def unpack(self, buffer, maximumPacketSize)
Definition: MQTTV5.py:881
def __eq__(self, packet)
Definition: MQTTV5.py:974
def pack(self)
Definition: MQTTV5.py:1125
def writeInt32(length)
Definition: MQTTV5.py:354
def pack(self)
Definition: MQTTV5.py:555
def __setattr__(self, name, value)
Definition: MQTTV5.py:78
def getIdentFromName(self, compressedName)
Definition: MQTTV5.py:484
def __eq__(self, packet)
Definition: MQTTV5.py:1042
def __eq__(self, fh)
Definition: MQTTV5.py:309
def pack(self)
Definition: MQTTV5.py:872
def __setattr__(self, name, value)
Definition: MQTTV5.py:1077
def __str__(self)
Definition: MQTTV5.py:1325
def __str__(self)
Definition: MQTTV5.py:1286
def __setattr__(self, name, value)
Definition: MQTTV5.py:493
def unpack(self, buffer, maximumPacketSize)
Definition: MQTTV5.py:1315
packetIdentifier
Definition: MQTTV5.py:994
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, PacketId=1, reasonCodes=[])
Definition: MQTTV5.py:1235
def __init__(self, aPacketType)
Definition: MQTTV5.py:302
def readProperty(self, buffer, type, propslen)
Definition: MQTTV5.py:574
def __str__(self)
Definition: MQTTV5.py:846
def __str__(self)
Definition: MQTTV5.py:508
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False)
Definition: MQTTV5.py:1331
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, MsgId=1, TopicName="", Payload=b"")
Definition: MQTTV5.py:912
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, PacketId=1, reasonCodes=[])
Definition: MQTTV5.py:1299
def __getName__(self, packetType, identifier)
Definition: MQTTV5.py:100
def unpackPacket(buffer, maximumPacketSize=MAX_PACKET_SIZE)
Definition: MQTTV5.py:1458
def pack(self)
Definition: MQTTV5.py:669
def __init__(self, buffer=None, DUP=False, QoS=1, RETAIN=False, PacketId=1)
Definition: MQTTV5.py:1059
def __eq__(self, packet)
Definition: MQTTV5.py:1448
def decode(buffer)
Definition: MQTTV5.py:247
def __eq__(self, packet)
Definition: MQTTV5.py:851
def __init__(self, buffer=None, DUP=False, QoS=0, RETAIN=False, reasonCode="Success")
Definition: MQTTV5.py:1411
def unpack(self, buffer, maximumPacketSize)
Definition: MQTTV5.py:1198
def __init__(self, buffer=None, DUP=False, QoS=1, RETAIN=False, MsgId=1, Data=[])
Definition: MQTTV5.py:1109
def __str__(self)
Definition: MQTTV5.py:72
def pack(self)
Definition: MQTTV5.py:1424
def set(self, name)
Definition: MQTTV5.py:124
def __init__(self, packetType, buffer, DUP, QoS, RETAIN, PacketId, reasonCodes)
Definition: MQTTV5.py:1172
def __eq__(self, packet)
Definition: MQTTV5.py:791
def __eq__(self, packet)
Definition: MQTTV5.py:1291
def __eq__(self, packet)
Definition: MQTTV5.py:904
def pack(self)
Definition: MQTTV5.py:1189
def pack(self)
Definition: MQTTV5.py:138
def getPacket(aSocket)
Definition: MQTTV5.py:267
Definition: format.h:3618
def __str__(self)
Definition: MQTTV5.py:966
int len
Definition: utf-8.c:46


plotjuggler
Author(s): Davide Faconti
autogenerated on Sun Dec 6 2020 03:48:09