Library for MQTT
mbed-mqtt-master/paho_mqtt_embedded_c/test/MQTTV3112.py@0:ba7e439238ab, 2022-06-20 (annotated)
- Committer:
- pavleradojkovic
- Date:
- Mon Jun 20 16:24:43 2022 +0000
- Revision:
- 0:ba7e439238ab
Inital commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
pavleradojkovic | 0:ba7e439238ab | 1 | """ |
pavleradojkovic | 0:ba7e439238ab | 2 | ******************************************************************* |
pavleradojkovic | 0:ba7e439238ab | 3 | Copyright (c) 2013, 2014 IBM Corp. |
pavleradojkovic | 0:ba7e439238ab | 4 | |
pavleradojkovic | 0:ba7e439238ab | 5 | All rights reserved. This program and the accompanying materials |
pavleradojkovic | 0:ba7e439238ab | 6 | are made available under the terms of the Eclipse Public License v1.0 |
pavleradojkovic | 0:ba7e439238ab | 7 | and Eclipse Distribution License v1.0 which accompany this distribution. |
pavleradojkovic | 0:ba7e439238ab | 8 | |
pavleradojkovic | 0:ba7e439238ab | 9 | The Eclipse Public License is available at |
pavleradojkovic | 0:ba7e439238ab | 10 | http://www.eclipse.org/legal/epl-v10.html |
pavleradojkovic | 0:ba7e439238ab | 11 | and the Eclipse Distribution License is available at |
pavleradojkovic | 0:ba7e439238ab | 12 | http://www.eclipse.org/org/documents/edl-v10.php. |
pavleradojkovic | 0:ba7e439238ab | 13 | |
pavleradojkovic | 0:ba7e439238ab | 14 | Contributors: |
pavleradojkovic | 0:ba7e439238ab | 15 | Ian Craggs - initial implementation and/or documentation |
pavleradojkovic | 0:ba7e439238ab | 16 | ******************************************************************* |
pavleradojkovic | 0:ba7e439238ab | 17 | """ |
pavleradojkovic | 0:ba7e439238ab | 18 | from __future__ import print_function |
pavleradojkovic | 0:ba7e439238ab | 19 | |
pavleradojkovic | 0:ba7e439238ab | 20 | """ |
pavleradojkovic | 0:ba7e439238ab | 21 | |
pavleradojkovic | 0:ba7e439238ab | 22 | Assertions are used to validate incoming data, but are omitted from outgoing packets. This is |
pavleradojkovic | 0:ba7e439238ab | 23 | so that the tests that use this package can send invalid data for error testing. |
pavleradojkovic | 0:ba7e439238ab | 24 | |
pavleradojkovic | 0:ba7e439238ab | 25 | """ |
pavleradojkovic | 0:ba7e439238ab | 26 | |
pavleradojkovic | 0:ba7e439238ab | 27 | |
pavleradojkovic | 0:ba7e439238ab | 28 | import logging |
pavleradojkovic | 0:ba7e439238ab | 29 | |
pavleradojkovic | 0:ba7e439238ab | 30 | logger = logging.getLogger("mqttsas") |
pavleradojkovic | 0:ba7e439238ab | 31 | |
pavleradojkovic | 0:ba7e439238ab | 32 | # Low-level protocol interface |
pavleradojkovic | 0:ba7e439238ab | 33 | |
pavleradojkovic | 0:ba7e439238ab | 34 | class MQTTException(Exception): |
pavleradojkovic | 0:ba7e439238ab | 35 | pass |
pavleradojkovic | 0:ba7e439238ab | 36 | |
pavleradojkovic | 0:ba7e439238ab | 37 | |
pavleradojkovic | 0:ba7e439238ab | 38 | # Message types |
pavleradojkovic | 0:ba7e439238ab | 39 | CONNECT, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL, \ |
pavleradojkovic | 0:ba7e439238ab | 40 | PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, \ |
pavleradojkovic | 0:ba7e439238ab | 41 | PINGREQ, PINGRESP, DISCONNECT = range(1, 15) |
pavleradojkovic | 0:ba7e439238ab | 42 | |
pavleradojkovic | 0:ba7e439238ab | 43 | packetNames = [ "reserved", \ |
pavleradojkovic | 0:ba7e439238ab | 44 | "Connect", "Connack", "Publish", "Puback", "Pubrec", "Pubrel", \ |
pavleradojkovic | 0:ba7e439238ab | 45 | "Pubcomp", "Subscribe", "Suback", "Unsubscribe", "Unsuback", \ |
pavleradojkovic | 0:ba7e439238ab | 46 | "Pingreq", "Pingresp", "Disconnect"] |
pavleradojkovic | 0:ba7e439238ab | 47 | |
pavleradojkovic | 0:ba7e439238ab | 48 | classNames = [ "reserved", \ |
pavleradojkovic | 0:ba7e439238ab | 49 | "Connects", "Connacks", "Publishes", "Pubacks", "Pubrecs", "Pubrels", \ |
pavleradojkovic | 0:ba7e439238ab | 50 | "Pubcomps", "Subscribes", "Subacks", "Unsubscribes", "Unsubacks", \ |
pavleradojkovic | 0:ba7e439238ab | 51 | "Pingreqs", "Pingresps", "Disconnects"] |
pavleradojkovic | 0:ba7e439238ab | 52 | |
pavleradojkovic | 0:ba7e439238ab | 53 | |
pavleradojkovic | 0:ba7e439238ab | 54 | def MessageType(byte): |
pavleradojkovic | 0:ba7e439238ab | 55 | if byte != None: |
pavleradojkovic | 0:ba7e439238ab | 56 | rc = ord(byte[0]) >> 4 |
pavleradojkovic | 0:ba7e439238ab | 57 | else: |
pavleradojkovic | 0:ba7e439238ab | 58 | rc = None |
pavleradojkovic | 0:ba7e439238ab | 59 | return rc |
pavleradojkovic | 0:ba7e439238ab | 60 | |
pavleradojkovic | 0:ba7e439238ab | 61 | |
pavleradojkovic | 0:ba7e439238ab | 62 | def getPacket(aSocket): |
pavleradojkovic | 0:ba7e439238ab | 63 | "receive the next packet" |
pavleradojkovic | 0:ba7e439238ab | 64 | buf = aSocket.recv(1) # get the first byte fixed header |
pavleradojkovic | 0:ba7e439238ab | 65 | if buf == b"": |
pavleradojkovic | 0:ba7e439238ab | 66 | return None |
pavleradojkovic | 0:ba7e439238ab | 67 | if str(aSocket).find("[closed]") != -1: |
pavleradojkovic | 0:ba7e439238ab | 68 | closed = True |
pavleradojkovic | 0:ba7e439238ab | 69 | else: |
pavleradojkovic | 0:ba7e439238ab | 70 | closed = False |
pavleradojkovic | 0:ba7e439238ab | 71 | if closed: |
pavleradojkovic | 0:ba7e439238ab | 72 | return None |
pavleradojkovic | 0:ba7e439238ab | 73 | # now get the remaining length |
pavleradojkovic | 0:ba7e439238ab | 74 | multiplier = 1 |
pavleradojkovic | 0:ba7e439238ab | 75 | remlength = 0 |
pavleradojkovic | 0:ba7e439238ab | 76 | while 1: |
pavleradojkovic | 0:ba7e439238ab | 77 | next = aSocket.recv(1) |
pavleradojkovic | 0:ba7e439238ab | 78 | while len(next) == 0: |
pavleradojkovic | 0:ba7e439238ab | 79 | next = aSocket.recv(1) |
pavleradojkovic | 0:ba7e439238ab | 80 | buf += next |
pavleradojkovic | 0:ba7e439238ab | 81 | digit = ord(buf[-1]) |
pavleradojkovic | 0:ba7e439238ab | 82 | remlength += (digit & 127) * multiplier |
pavleradojkovic | 0:ba7e439238ab | 83 | if digit & 128 == 0: |
pavleradojkovic | 0:ba7e439238ab | 84 | break |
pavleradojkovic | 0:ba7e439238ab | 85 | multiplier *= 128 |
pavleradojkovic | 0:ba7e439238ab | 86 | # receive the remaining length if there is any |
pavleradojkovic | 0:ba7e439238ab | 87 | rest = '' |
pavleradojkovic | 0:ba7e439238ab | 88 | if remlength > 0: |
pavleradojkovic | 0:ba7e439238ab | 89 | while len(rest) < remlength: |
pavleradojkovic | 0:ba7e439238ab | 90 | rest += aSocket.recv(remlength-len(rest)) |
pavleradojkovic | 0:ba7e439238ab | 91 | assert len(rest) == remlength |
pavleradojkovic | 0:ba7e439238ab | 92 | return buf + rest |
pavleradojkovic | 0:ba7e439238ab | 93 | |
pavleradojkovic | 0:ba7e439238ab | 94 | |
pavleradojkovic | 0:ba7e439238ab | 95 | class FixedHeaders: |
pavleradojkovic | 0:ba7e439238ab | 96 | |
pavleradojkovic | 0:ba7e439238ab | 97 | def __init__(self, aMessageType): |
pavleradojkovic | 0:ba7e439238ab | 98 | self.MessageType = aMessageType |
pavleradojkovic | 0:ba7e439238ab | 99 | self.DUP = False |
pavleradojkovic | 0:ba7e439238ab | 100 | self.QoS = 0 |
pavleradojkovic | 0:ba7e439238ab | 101 | self.RETAIN = False |
pavleradojkovic | 0:ba7e439238ab | 102 | self.remainingLength = 0 |
pavleradojkovic | 0:ba7e439238ab | 103 | |
pavleradojkovic | 0:ba7e439238ab | 104 | def __eq__(self, fh): |
pavleradojkovic | 0:ba7e439238ab | 105 | return self.MessageType == fh.MessageType and \ |
pavleradojkovic | 0:ba7e439238ab | 106 | self.DUP == fh.DUP and \ |
pavleradojkovic | 0:ba7e439238ab | 107 | self.QoS == fh.QoS and \ |
pavleradojkovic | 0:ba7e439238ab | 108 | self.RETAIN == fh.RETAIN # and \ |
pavleradojkovic | 0:ba7e439238ab | 109 | # self.remainingLength == fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 110 | |
pavleradojkovic | 0:ba7e439238ab | 111 | def __repr__(self): |
pavleradojkovic | 0:ba7e439238ab | 112 | "return printable representation of our data" |
pavleradojkovic | 0:ba7e439238ab | 113 | return classNames[self.MessageType]+'(DUP='+repr(self.DUP)+ \ |
pavleradojkovic | 0:ba7e439238ab | 114 | ", QoS="+repr(self.QoS)+", Retain="+repr(self.RETAIN) |
pavleradojkovic | 0:ba7e439238ab | 115 | |
pavleradojkovic | 0:ba7e439238ab | 116 | def pack(self, length): |
pavleradojkovic | 0:ba7e439238ab | 117 | "pack data into string buffer ready for transmission down socket" |
pavleradojkovic | 0:ba7e439238ab | 118 | buffer = bytes([(self.MessageType << 4) | (self.DUP << 3) |\ |
pavleradojkovic | 0:ba7e439238ab | 119 | (self.QoS << 1) | self.RETAIN]) |
pavleradojkovic | 0:ba7e439238ab | 120 | self.remainingLength = length |
pavleradojkovic | 0:ba7e439238ab | 121 | buffer += self.encode(length) |
pavleradojkovic | 0:ba7e439238ab | 122 | return buffer |
pavleradojkovic | 0:ba7e439238ab | 123 | |
pavleradojkovic | 0:ba7e439238ab | 124 | def encode(self, x): |
pavleradojkovic | 0:ba7e439238ab | 125 | assert 0 <= x <= 268435455 |
pavleradojkovic | 0:ba7e439238ab | 126 | buffer = b'' |
pavleradojkovic | 0:ba7e439238ab | 127 | while 1: |
pavleradojkovic | 0:ba7e439238ab | 128 | digit = x % 128 |
pavleradojkovic | 0:ba7e439238ab | 129 | x //= 128 |
pavleradojkovic | 0:ba7e439238ab | 130 | if x > 0: |
pavleradojkovic | 0:ba7e439238ab | 131 | digit |= 0x80 |
pavleradojkovic | 0:ba7e439238ab | 132 | buffer += bytes([digit]) |
pavleradojkovic | 0:ba7e439238ab | 133 | if x == 0: |
pavleradojkovic | 0:ba7e439238ab | 134 | break |
pavleradojkovic | 0:ba7e439238ab | 135 | return buffer |
pavleradojkovic | 0:ba7e439238ab | 136 | |
pavleradojkovic | 0:ba7e439238ab | 137 | def unpack(self, buffer): |
pavleradojkovic | 0:ba7e439238ab | 138 | "unpack data from string buffer into separate fields" |
pavleradojkovic | 0:ba7e439238ab | 139 | b0 = ord(buffer[0]) |
pavleradojkovic | 0:ba7e439238ab | 140 | self.MessageType = b0 >> 4 |
pavleradojkovic | 0:ba7e439238ab | 141 | self.DUP = ((b0 >> 3) & 0x01) == 1 |
pavleradojkovic | 0:ba7e439238ab | 142 | self.QoS = (b0 >> 1) & 0x03 |
pavleradojkovic | 0:ba7e439238ab | 143 | self.RETAIN = (b0 & 0x01) == 1 |
pavleradojkovic | 0:ba7e439238ab | 144 | (self.remainingLength, bytes) = self.decode(buffer[1:]) |
pavleradojkovic | 0:ba7e439238ab | 145 | return bytes + 1 # length of fixed header |
pavleradojkovic | 0:ba7e439238ab | 146 | |
pavleradojkovic | 0:ba7e439238ab | 147 | def decode(self, buffer): |
pavleradojkovic | 0:ba7e439238ab | 148 | multiplier = 1 |
pavleradojkovic | 0:ba7e439238ab | 149 | value = 0 |
pavleradojkovic | 0:ba7e439238ab | 150 | bytes = 0 |
pavleradojkovic | 0:ba7e439238ab | 151 | while 1: |
pavleradojkovic | 0:ba7e439238ab | 152 | bytes += 1 |
pavleradojkovic | 0:ba7e439238ab | 153 | digit = ord(buffer[0]) |
pavleradojkovic | 0:ba7e439238ab | 154 | buffer = buffer[1:] |
pavleradojkovic | 0:ba7e439238ab | 155 | value += (digit & 127) * multiplier |
pavleradojkovic | 0:ba7e439238ab | 156 | if digit & 128 == 0: |
pavleradojkovic | 0:ba7e439238ab | 157 | break |
pavleradojkovic | 0:ba7e439238ab | 158 | multiplier *= 128 |
pavleradojkovic | 0:ba7e439238ab | 159 | return (value, bytes) |
pavleradojkovic | 0:ba7e439238ab | 160 | |
pavleradojkovic | 0:ba7e439238ab | 161 | |
pavleradojkovic | 0:ba7e439238ab | 162 | def writeInt16(length): |
pavleradojkovic | 0:ba7e439238ab | 163 | return bytes([length // 256, length % 256]) |
pavleradojkovic | 0:ba7e439238ab | 164 | |
pavleradojkovic | 0:ba7e439238ab | 165 | def readInt16(buf): |
pavleradojkovic | 0:ba7e439238ab | 166 | return ord(buf[0])*256 + ord(buf[1]) |
pavleradojkovic | 0:ba7e439238ab | 167 | |
pavleradojkovic | 0:ba7e439238ab | 168 | def writeUTF(data): |
pavleradojkovic | 0:ba7e439238ab | 169 | # data could be a string, or bytes. If string, encode into bytes with utf-8 |
pavleradojkovic | 0:ba7e439238ab | 170 | return writeInt16(len(data)) + (data if type(data) == type(b"") else bytes(data, "utf-8")) |
pavleradojkovic | 0:ba7e439238ab | 171 | |
pavleradojkovic | 0:ba7e439238ab | 172 | def readUTF(buffer, maxlen): |
pavleradojkovic | 0:ba7e439238ab | 173 | if maxlen >= 2: |
pavleradojkovic | 0:ba7e439238ab | 174 | length = readInt16(buffer) |
pavleradojkovic | 0:ba7e439238ab | 175 | else: |
pavleradojkovic | 0:ba7e439238ab | 176 | raise MQTTException("Not enough data to read string length") |
pavleradojkovic | 0:ba7e439238ab | 177 | maxlen -= 2 |
pavleradojkovic | 0:ba7e439238ab | 178 | if length > maxlen: |
pavleradojkovic | 0:ba7e439238ab | 179 | raise MQTTException("Length delimited string too long") |
pavleradojkovic | 0:ba7e439238ab | 180 | buf = buffer[2:2+length].decode("utf-8") |
pavleradojkovic | 0:ba7e439238ab | 181 | logger.info("[MQTT-4.7.3-2] topic names and filters not include null") |
pavleradojkovic | 0:ba7e439238ab | 182 | zz = buf.find("\x00") # look for null in the UTF string |
pavleradojkovic | 0:ba7e439238ab | 183 | if zz != -1: |
pavleradojkovic | 0:ba7e439238ab | 184 | raise MQTTException("[MQTT-1.5.3-2] Null found in UTF data "+buf) |
pavleradojkovic | 0:ba7e439238ab | 185 | """for c in range (0xD800, 0xDFFF): |
pavleradojkovic | 0:ba7e439238ab | 186 | zz = buf.find(chr(c)) # look for D800-DFFF in the UTF string |
pavleradojkovic | 0:ba7e439238ab | 187 | if zz != -1: |
pavleradojkovic | 0:ba7e439238ab | 188 | raise MQTTException("[MQTT-1.5.3-1] D800-DFFF found in UTF data "+buf) |
pavleradojkovic | 0:ba7e439238ab | 189 | """ |
pavleradojkovic | 0:ba7e439238ab | 190 | if buf.find("\uFEFF") != -1: |
pavleradojkovic | 0:ba7e439238ab | 191 | logger.info("[MQTT-1.5.3-3] U+FEFF in UTF string") |
pavleradojkovic | 0:ba7e439238ab | 192 | return buf |
pavleradojkovic | 0:ba7e439238ab | 193 | |
pavleradojkovic | 0:ba7e439238ab | 194 | def writeBytes(buffer): |
pavleradojkovic | 0:ba7e439238ab | 195 | return writeInt16(len(buffer)) + buffer |
pavleradojkovic | 0:ba7e439238ab | 196 | |
pavleradojkovic | 0:ba7e439238ab | 197 | def readBytes(buffer): |
pavleradojkovic | 0:ba7e439238ab | 198 | length = readInt16(buffer) |
pavleradojkovic | 0:ba7e439238ab | 199 | return buffer[2:2+length] |
pavleradojkovic | 0:ba7e439238ab | 200 | |
pavleradojkovic | 0:ba7e439238ab | 201 | |
pavleradojkovic | 0:ba7e439238ab | 202 | class Packets: |
pavleradojkovic | 0:ba7e439238ab | 203 | |
pavleradojkovic | 0:ba7e439238ab | 204 | def pack(self): |
pavleradojkovic | 0:ba7e439238ab | 205 | buffer = self.fh.pack(0) |
pavleradojkovic | 0:ba7e439238ab | 206 | return buffer |
pavleradojkovic | 0:ba7e439238ab | 207 | |
pavleradojkovic | 0:ba7e439238ab | 208 | def __repr__(self): |
pavleradojkovic | 0:ba7e439238ab | 209 | return repr(self.fh) |
pavleradojkovic | 0:ba7e439238ab | 210 | |
pavleradojkovic | 0:ba7e439238ab | 211 | def __eq__(self, packet): |
pavleradojkovic | 0:ba7e439238ab | 212 | return self.fh == packet.fh if packet else False |
pavleradojkovic | 0:ba7e439238ab | 213 | |
pavleradojkovic | 0:ba7e439238ab | 214 | |
pavleradojkovic | 0:ba7e439238ab | 215 | class Connects(Packets): |
pavleradojkovic | 0:ba7e439238ab | 216 | |
pavleradojkovic | 0:ba7e439238ab | 217 | def __init__(self, buffer = None): |
pavleradojkovic | 0:ba7e439238ab | 218 | self.fh = FixedHeaders(CONNECT) |
pavleradojkovic | 0:ba7e439238ab | 219 | |
pavleradojkovic | 0:ba7e439238ab | 220 | # variable header |
pavleradojkovic | 0:ba7e439238ab | 221 | self.ProtocolName = "MQTT" |
pavleradojkovic | 0:ba7e439238ab | 222 | self.ProtocolVersion = 4 |
pavleradojkovic | 0:ba7e439238ab | 223 | self.CleanSession = True |
pavleradojkovic | 0:ba7e439238ab | 224 | self.WillFlag = False |
pavleradojkovic | 0:ba7e439238ab | 225 | self.WillQoS = 0 |
pavleradojkovic | 0:ba7e439238ab | 226 | self.WillRETAIN = 0 |
pavleradojkovic | 0:ba7e439238ab | 227 | self.KeepAliveTimer = 30 |
pavleradojkovic | 0:ba7e439238ab | 228 | self.usernameFlag = False |
pavleradojkovic | 0:ba7e439238ab | 229 | self.passwordFlag = False |
pavleradojkovic | 0:ba7e439238ab | 230 | |
pavleradojkovic | 0:ba7e439238ab | 231 | # Payload |
pavleradojkovic | 0:ba7e439238ab | 232 | self.ClientIdentifier = "" # UTF-8 |
pavleradojkovic | 0:ba7e439238ab | 233 | self.WillTopic = None # UTF-8 |
pavleradojkovic | 0:ba7e439238ab | 234 | self.WillMessage = None # binary |
pavleradojkovic | 0:ba7e439238ab | 235 | self.username = None # UTF-8 |
pavleradojkovic | 0:ba7e439238ab | 236 | self.password = None # binary |
pavleradojkovic | 0:ba7e439238ab | 237 | |
pavleradojkovic | 0:ba7e439238ab | 238 | if buffer != None: |
pavleradojkovic | 0:ba7e439238ab | 239 | self.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 240 | |
pavleradojkovic | 0:ba7e439238ab | 241 | def pack(self): |
pavleradojkovic | 0:ba7e439238ab | 242 | connectFlags = bytes([(self.CleanSession << 1) | (self.WillFlag << 2) | \ |
pavleradojkovic | 0:ba7e439238ab | 243 | (self.WillQoS << 3) | (self.WillRETAIN << 5) | \ |
pavleradojkovic | 0:ba7e439238ab | 244 | (self.usernameFlag << 6) | (self.passwordFlag << 7)]) |
pavleradojkovic | 0:ba7e439238ab | 245 | buffer = writeUTF(self.ProtocolName) + bytes([self.ProtocolVersion]) + \ |
pavleradojkovic | 0:ba7e439238ab | 246 | connectFlags + writeInt16(self.KeepAliveTimer) |
pavleradojkovic | 0:ba7e439238ab | 247 | buffer += writeUTF(self.ClientIdentifier) |
pavleradojkovic | 0:ba7e439238ab | 248 | if self.WillFlag: |
pavleradojkovic | 0:ba7e439238ab | 249 | buffer += writeUTF(self.WillTopic) |
pavleradojkovic | 0:ba7e439238ab | 250 | buffer += writeBytes(self.WillMessage) |
pavleradojkovic | 0:ba7e439238ab | 251 | if self.usernameFlag: |
pavleradojkovic | 0:ba7e439238ab | 252 | buffer += writeUTF(self.username) |
pavleradojkovic | 0:ba7e439238ab | 253 | if self.passwordFlag: |
pavleradojkovic | 0:ba7e439238ab | 254 | buffer += writeBytes(self.password) |
pavleradojkovic | 0:ba7e439238ab | 255 | buffer = self.fh.pack(len(buffer)) + buffer |
pavleradojkovic | 0:ba7e439238ab | 256 | return buffer |
pavleradojkovic | 0:ba7e439238ab | 257 | |
pavleradojkovic | 0:ba7e439238ab | 258 | def unpack(self, buffer): |
pavleradojkovic | 0:ba7e439238ab | 259 | assert len(buffer) >= 2 |
pavleradojkovic | 0:ba7e439238ab | 260 | assert MessageType(buffer) == CONNECT |
pavleradojkovic | 0:ba7e439238ab | 261 | |
pavleradojkovic | 0:ba7e439238ab | 262 | try: |
pavleradojkovic | 0:ba7e439238ab | 263 | fhlen = self.fh.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 264 | packlen = fhlen + self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 265 | assert len(buffer) >= packlen, "buffer length %d packet length %d" % (len(buffer), packlen) |
pavleradojkovic | 0:ba7e439238ab | 266 | curlen = fhlen # points to after header + remaining length |
pavleradojkovic | 0:ba7e439238ab | 267 | assert self.fh.DUP == False, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 268 | assert self.fh.QoS == 0, "[MQTT-2.1.2-1] QoS was not 0, was %d" % self.fh.QoS |
pavleradojkovic | 0:ba7e439238ab | 269 | assert self.fh.RETAIN == False, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 270 | |
pavleradojkovic | 0:ba7e439238ab | 271 | self.ProtocolName = readUTF(buffer[curlen:], packlen - curlen) |
pavleradojkovic | 0:ba7e439238ab | 272 | curlen += len(self.ProtocolName) + 2 |
pavleradojkovic | 0:ba7e439238ab | 273 | assert self.ProtocolName == "MQTT", "Wrong protocol name %s" % self.ProtocolName |
pavleradojkovic | 0:ba7e439238ab | 274 | |
pavleradojkovic | 0:ba7e439238ab | 275 | self.ProtocolVersion = ord(buffer[curlen]) |
pavleradojkovic | 0:ba7e439238ab | 276 | curlen += 1 |
pavleradojkovic | 0:ba7e439238ab | 277 | |
pavleradojkovic | 0:ba7e439238ab | 278 | connectFlags = ord(buffer[curlen]) |
pavleradojkovic | 0:ba7e439238ab | 279 | assert (connectFlags & 0x01) == 0, "[MQTT-3.1.2-3] reserved connect flag must be 0" |
pavleradojkovic | 0:ba7e439238ab | 280 | self.CleanSession = ((connectFlags >> 1) & 0x01) == 1 |
pavleradojkovic | 0:ba7e439238ab | 281 | self.WillFlag = ((connectFlags >> 2) & 0x01) == 1 |
pavleradojkovic | 0:ba7e439238ab | 282 | self.WillQoS = (connectFlags >> 3) & 0x03 |
pavleradojkovic | 0:ba7e439238ab | 283 | self.WillRETAIN = (connectFlags >> 5) & 0x01 |
pavleradojkovic | 0:ba7e439238ab | 284 | self.passwordFlag = ((connectFlags >> 6) & 0x01) == 1 |
pavleradojkovic | 0:ba7e439238ab | 285 | self.usernameFlag = ((connectFlags >> 7) & 0x01) == 1 |
pavleradojkovic | 0:ba7e439238ab | 286 | curlen +=1 |
pavleradojkovic | 0:ba7e439238ab | 287 | |
pavleradojkovic | 0:ba7e439238ab | 288 | if self.WillFlag: |
pavleradojkovic | 0:ba7e439238ab | 289 | assert self.WillQoS in [0, 1, 2], "[MQTT-3.1.2-14] will qos must not be 3" |
pavleradojkovic | 0:ba7e439238ab | 290 | else: |
pavleradojkovic | 0:ba7e439238ab | 291 | assert self.WillQoS == 0, "[MQTT-3.1.2-13] will qos must be 0, if will flag is false" |
pavleradojkovic | 0:ba7e439238ab | 292 | assert self.WillRETAIN == False, "[MQTT-3.1.2-14] will retain must be false, if will flag is false" |
pavleradojkovic | 0:ba7e439238ab | 293 | |
pavleradojkovic | 0:ba7e439238ab | 294 | self.KeepAliveTimer = readInt16(buffer[curlen:]) |
pavleradojkovic | 0:ba7e439238ab | 295 | curlen += 2 |
pavleradojkovic | 0:ba7e439238ab | 296 | logger.info("[MQTT-3.1.3-3] Clientid must be present, and first field") |
pavleradojkovic | 0:ba7e439238ab | 297 | logger.info("[MQTT-3.1.3-4] Clientid must be Unicode, and between 0 and 65535 bytes long") |
pavleradojkovic | 0:ba7e439238ab | 298 | self.ClientIdentifier = readUTF(buffer[curlen:], packlen - curlen) |
pavleradojkovic | 0:ba7e439238ab | 299 | curlen += len(self.ClientIdentifier) + 2 |
pavleradojkovic | 0:ba7e439238ab | 300 | |
pavleradojkovic | 0:ba7e439238ab | 301 | if self.WillFlag: |
pavleradojkovic | 0:ba7e439238ab | 302 | self.WillTopic = readUTF(buffer[curlen:], packlen - curlen) |
pavleradojkovic | 0:ba7e439238ab | 303 | curlen += len(self.WillTopic) + 2 |
pavleradojkovic | 0:ba7e439238ab | 304 | self.WillMessage = readBytes(buffer[curlen:]) |
pavleradojkovic | 0:ba7e439238ab | 305 | curlen += len(self.WillMessage) + 2 |
pavleradojkovic | 0:ba7e439238ab | 306 | logger.info("[[MQTT-3.1.2-9] will topic and will message fields must be present") |
pavleradojkovic | 0:ba7e439238ab | 307 | else: |
pavleradojkovic | 0:ba7e439238ab | 308 | self.WillTopic = self.WillMessage = None |
pavleradojkovic | 0:ba7e439238ab | 309 | |
pavleradojkovic | 0:ba7e439238ab | 310 | if self.usernameFlag: |
pavleradojkovic | 0:ba7e439238ab | 311 | assert len(buffer) > curlen+2, "Buffer too short to read username length" |
pavleradojkovic | 0:ba7e439238ab | 312 | self.username = readUTF(buffer[curlen:], packlen - curlen) |
pavleradojkovic | 0:ba7e439238ab | 313 | curlen += len(self.username) + 2 |
pavleradojkovic | 0:ba7e439238ab | 314 | logger.info("[MQTT-3.1.2-19] username must be in payload if user name flag is 1") |
pavleradojkovic | 0:ba7e439238ab | 315 | else: |
pavleradojkovic | 0:ba7e439238ab | 316 | logger.info("[MQTT-3.1.2-18] username must not be in payload if user name flag is 0") |
pavleradojkovic | 0:ba7e439238ab | 317 | assert self.passwordFlag == False, "[MQTT-3.1.2-22] password flag must be 0 if username flag is 0" |
pavleradojkovic | 0:ba7e439238ab | 318 | |
pavleradojkovic | 0:ba7e439238ab | 319 | if self.passwordFlag: |
pavleradojkovic | 0:ba7e439238ab | 320 | assert len(buffer) > curlen+2, "Buffer too short to read password length" |
pavleradojkovic | 0:ba7e439238ab | 321 | self.password = readBytes(buffer[curlen:]) |
pavleradojkovic | 0:ba7e439238ab | 322 | curlen += len(self.password) + 2 |
pavleradojkovic | 0:ba7e439238ab | 323 | logger.info("[MQTT-3.1.2-21] password must be in payload if password flag is 0") |
pavleradojkovic | 0:ba7e439238ab | 324 | else: |
pavleradojkovic | 0:ba7e439238ab | 325 | logger.info("[MQTT-3.1.2-20] password must not be in payload if password flag is 0") |
pavleradojkovic | 0:ba7e439238ab | 326 | |
pavleradojkovic | 0:ba7e439238ab | 327 | if self.WillFlag and self.usernameFlag and self.passwordFlag: |
pavleradojkovic | 0:ba7e439238ab | 328 | logger.info("[MQTT-3.1.3-1] clientid, will topic, will message, username and password all present") |
pavleradojkovic | 0:ba7e439238ab | 329 | |
pavleradojkovic | 0:ba7e439238ab | 330 | assert curlen == packlen, "Packet is wrong length curlen %d != packlen %d" |
pavleradojkovic | 0:ba7e439238ab | 331 | except: |
pavleradojkovic | 0:ba7e439238ab | 332 | logger.exception("[MQTT-3.1.4-1] server must validate connect packet and close connection without connack if it does not conform") |
pavleradojkovic | 0:ba7e439238ab | 333 | raise |
pavleradojkovic | 0:ba7e439238ab | 334 | |
pavleradojkovic | 0:ba7e439238ab | 335 | |
pavleradojkovic | 0:ba7e439238ab | 336 | |
pavleradojkovic | 0:ba7e439238ab | 337 | def __repr__(self): |
pavleradojkovic | 0:ba7e439238ab | 338 | buf = repr(self.fh)+", ProtocolName="+str(self.ProtocolName)+", ProtocolVersion=" +\ |
pavleradojkovic | 0:ba7e439238ab | 339 | repr(self.ProtocolVersion)+", CleanSession="+repr(self.CleanSession) +\ |
pavleradojkovic | 0:ba7e439238ab | 340 | ", WillFlag="+repr(self.WillFlag)+", KeepAliveTimer=" +\ |
pavleradojkovic | 0:ba7e439238ab | 341 | repr(self.KeepAliveTimer)+", ClientId="+str(self.ClientIdentifier) +\ |
pavleradojkovic | 0:ba7e439238ab | 342 | ", usernameFlag="+repr(self.usernameFlag)+", passwordFlag="+repr(self.passwordFlag) |
pavleradojkovic | 0:ba7e439238ab | 343 | if self.WillFlag: |
pavleradojkovic | 0:ba7e439238ab | 344 | buf += ", WillQoS=" + repr(self.WillQoS) +\ |
pavleradojkovic | 0:ba7e439238ab | 345 | ", WillRETAIN=" + repr(self.WillRETAIN) +\ |
pavleradojkovic | 0:ba7e439238ab | 346 | ", WillTopic='"+ self.WillTopic +\ |
pavleradojkovic | 0:ba7e439238ab | 347 | "', WillMessage='"+str(self.WillMessage)+"'" |
pavleradojkovic | 0:ba7e439238ab | 348 | if self.username: |
pavleradojkovic | 0:ba7e439238ab | 349 | buf += ", username="+self.username |
pavleradojkovic | 0:ba7e439238ab | 350 | if self.password: |
pavleradojkovic | 0:ba7e439238ab | 351 | buf += ", password="+str(self.password) |
pavleradojkovic | 0:ba7e439238ab | 352 | return buf+")" |
pavleradojkovic | 0:ba7e439238ab | 353 | |
pavleradojkovic | 0:ba7e439238ab | 354 | def __eq__(self, packet): |
pavleradojkovic | 0:ba7e439238ab | 355 | rc = Packets.__eq__(self, packet) and \ |
pavleradojkovic | 0:ba7e439238ab | 356 | self.ProtocolName == packet.ProtocolName and \ |
pavleradojkovic | 0:ba7e439238ab | 357 | self.ProtocolVersion == packet.ProtocolVersion and \ |
pavleradojkovic | 0:ba7e439238ab | 358 | self.CleanSession == packet.CleanSession and \ |
pavleradojkovic | 0:ba7e439238ab | 359 | self.WillFlag == packet.WillFlag and \ |
pavleradojkovic | 0:ba7e439238ab | 360 | self.KeepAliveTimer == packet.KeepAliveTimer and \ |
pavleradojkovic | 0:ba7e439238ab | 361 | self.ClientIdentifier == packet.ClientIdentifier and \ |
pavleradojkovic | 0:ba7e439238ab | 362 | self.WillFlag == packet.WillFlag |
pavleradojkovic | 0:ba7e439238ab | 363 | if rc and self.WillFlag: |
pavleradojkovic | 0:ba7e439238ab | 364 | rc = self.WillQoS == packet.WillQoS and \ |
pavleradojkovic | 0:ba7e439238ab | 365 | self.WillRETAIN == packet.WillRETAIN and \ |
pavleradojkovic | 0:ba7e439238ab | 366 | self.WillTopic == packet.WillTopic and \ |
pavleradojkovic | 0:ba7e439238ab | 367 | self.WillMessage == packet.WillMessage |
pavleradojkovic | 0:ba7e439238ab | 368 | return rc |
pavleradojkovic | 0:ba7e439238ab | 369 | |
pavleradojkovic | 0:ba7e439238ab | 370 | |
pavleradojkovic | 0:ba7e439238ab | 371 | class Connacks(Packets): |
pavleradojkovic | 0:ba7e439238ab | 372 | |
pavleradojkovic | 0:ba7e439238ab | 373 | def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, ReturnCode=0): |
pavleradojkovic | 0:ba7e439238ab | 374 | self.fh = FixedHeaders(CONNACK) |
pavleradojkovic | 0:ba7e439238ab | 375 | self.fh.DUP = DUP |
pavleradojkovic | 0:ba7e439238ab | 376 | self.fh.QoS = QoS |
pavleradojkovic | 0:ba7e439238ab | 377 | self.fh.Retain = Retain |
pavleradojkovic | 0:ba7e439238ab | 378 | self.flags = 0 |
pavleradojkovic | 0:ba7e439238ab | 379 | self.returnCode = ReturnCode |
pavleradojkovic | 0:ba7e439238ab | 380 | if buffer != None: |
pavleradojkovic | 0:ba7e439238ab | 381 | self.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 382 | |
pavleradojkovic | 0:ba7e439238ab | 383 | def pack(self): |
pavleradojkovic | 0:ba7e439238ab | 384 | buffer = bytes([self.flags, self.returnCode]) |
pavleradojkovic | 0:ba7e439238ab | 385 | buffer = self.fh.pack(len(buffer)) + buffer |
pavleradojkovic | 0:ba7e439238ab | 386 | return buffer |
pavleradojkovic | 0:ba7e439238ab | 387 | |
pavleradojkovic | 0:ba7e439238ab | 388 | def unpack(self, buffer): |
pavleradojkovic | 0:ba7e439238ab | 389 | assert len(buffer) >= 4 |
pavleradojkovic | 0:ba7e439238ab | 390 | assert MessageType(buffer) == CONNACK |
pavleradojkovic | 0:ba7e439238ab | 391 | self.fh.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 392 | assert self.fh.remainingLength == 2, "Connack packet is wrong length %d" % self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 393 | assert ord(buffer[2]) in [0, 1], "Connect Acknowledge Flags" |
pavleradojkovic | 0:ba7e439238ab | 394 | self.returnCode = ord(buffer[3]) |
pavleradojkovic | 0:ba7e439238ab | 395 | assert self.fh.DUP == False, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 396 | assert self.fh.QoS == 0, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 397 | assert self.fh.RETAIN == False, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 398 | |
pavleradojkovic | 0:ba7e439238ab | 399 | def __repr__(self): |
pavleradojkovic | 0:ba7e439238ab | 400 | return repr(self.fh)+", Session present="+str((self.flags & 0x01) == 1)+", ReturnCode="+repr(self.returnCode)+")" |
pavleradojkovic | 0:ba7e439238ab | 401 | |
pavleradojkovic | 0:ba7e439238ab | 402 | def __eq__(self, packet): |
pavleradojkovic | 0:ba7e439238ab | 403 | return Packets.__eq__(self, packet) and \ |
pavleradojkovic | 0:ba7e439238ab | 404 | self.returnCode == packet.returnCode |
pavleradojkovic | 0:ba7e439238ab | 405 | |
pavleradojkovic | 0:ba7e439238ab | 406 | |
pavleradojkovic | 0:ba7e439238ab | 407 | class Disconnects(Packets): |
pavleradojkovic | 0:ba7e439238ab | 408 | |
pavleradojkovic | 0:ba7e439238ab | 409 | def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False): |
pavleradojkovic | 0:ba7e439238ab | 410 | self.fh = FixedHeaders(DISCONNECT) |
pavleradojkovic | 0:ba7e439238ab | 411 | self.fh.DUP = DUP |
pavleradojkovic | 0:ba7e439238ab | 412 | self.fh.QoS = QoS |
pavleradojkovic | 0:ba7e439238ab | 413 | self.fh.Retain = Retain |
pavleradojkovic | 0:ba7e439238ab | 414 | if buffer != None: |
pavleradojkovic | 0:ba7e439238ab | 415 | self.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 416 | |
pavleradojkovic | 0:ba7e439238ab | 417 | def unpack(self, buffer): |
pavleradojkovic | 0:ba7e439238ab | 418 | assert len(buffer) >= 2 |
pavleradojkovic | 0:ba7e439238ab | 419 | assert MessageType(buffer) == DISCONNECT |
pavleradojkovic | 0:ba7e439238ab | 420 | self.fh.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 421 | assert self.fh.remainingLength == 0, "Disconnect packet is wrong length %d" % self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 422 | logger.info("[MQTT-3.14.1-1] disconnect reserved bits must be 0") |
pavleradojkovic | 0:ba7e439238ab | 423 | assert self.fh.DUP == False, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 424 | assert self.fh.QoS == 0, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 425 | assert self.fh.RETAIN == False, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 426 | |
pavleradojkovic | 0:ba7e439238ab | 427 | def __repr__(self): |
pavleradojkovic | 0:ba7e439238ab | 428 | return repr(self.fh)+")" |
pavleradojkovic | 0:ba7e439238ab | 429 | |
pavleradojkovic | 0:ba7e439238ab | 430 | |
pavleradojkovic | 0:ba7e439238ab | 431 | class Publishes(Packets): |
pavleradojkovic | 0:ba7e439238ab | 432 | |
pavleradojkovic | 0:ba7e439238ab | 433 | def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0, TopicName="", Payload=b""): |
pavleradojkovic | 0:ba7e439238ab | 434 | self.fh = FixedHeaders(PUBLISH) |
pavleradojkovic | 0:ba7e439238ab | 435 | self.fh.DUP = DUP |
pavleradojkovic | 0:ba7e439238ab | 436 | self.fh.QoS = QoS |
pavleradojkovic | 0:ba7e439238ab | 437 | self.fh.Retain = Retain |
pavleradojkovic | 0:ba7e439238ab | 438 | # variable header |
pavleradojkovic | 0:ba7e439238ab | 439 | self.topicName = TopicName |
pavleradojkovic | 0:ba7e439238ab | 440 | self.messageIdentifier = MsgId |
pavleradojkovic | 0:ba7e439238ab | 441 | # payload |
pavleradojkovic | 0:ba7e439238ab | 442 | self.data = Payload |
pavleradojkovic | 0:ba7e439238ab | 443 | if buffer != None: |
pavleradojkovic | 0:ba7e439238ab | 444 | self.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 445 | |
pavleradojkovic | 0:ba7e439238ab | 446 | def pack(self): |
pavleradojkovic | 0:ba7e439238ab | 447 | buffer = writeUTF(self.topicName) |
pavleradojkovic | 0:ba7e439238ab | 448 | if self.fh.QoS != 0: |
pavleradojkovic | 0:ba7e439238ab | 449 | buffer += writeInt16(self.messageIdentifier) |
pavleradojkovic | 0:ba7e439238ab | 450 | buffer += self.data |
pavleradojkovic | 0:ba7e439238ab | 451 | buffer = self.fh.pack(len(buffer)) + buffer |
pavleradojkovic | 0:ba7e439238ab | 452 | return buffer |
pavleradojkovic | 0:ba7e439238ab | 453 | |
pavleradojkovic | 0:ba7e439238ab | 454 | def unpack(self, buffer): |
pavleradojkovic | 0:ba7e439238ab | 455 | assert len(buffer) >= 2 |
pavleradojkovic | 0:ba7e439238ab | 456 | assert MessageType(buffer) == PUBLISH |
pavleradojkovic | 0:ba7e439238ab | 457 | fhlen = self.fh.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 458 | assert self.fh.QoS in [0, 1, 2], "QoS in Publish must be 0, 1, or 2" |
pavleradojkovic | 0:ba7e439238ab | 459 | packlen = fhlen + self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 460 | assert len(buffer) >= packlen |
pavleradojkovic | 0:ba7e439238ab | 461 | curlen = fhlen |
pavleradojkovic | 0:ba7e439238ab | 462 | try: |
pavleradojkovic | 0:ba7e439238ab | 463 | self.topicName = readUTF(buffer[fhlen:], packlen - curlen) |
pavleradojkovic | 0:ba7e439238ab | 464 | except UnicodeDecodeError: |
pavleradojkovic | 0:ba7e439238ab | 465 | logger.info("[MQTT-3.3.2-1] topic name in publish must be utf-8") |
pavleradojkovic | 0:ba7e439238ab | 466 | raise |
pavleradojkovic | 0:ba7e439238ab | 467 | curlen += len(self.topicName) + 2 |
pavleradojkovic | 0:ba7e439238ab | 468 | if self.fh.QoS != 0: |
pavleradojkovic | 0:ba7e439238ab | 469 | self.messageIdentifier = readInt16(buffer[curlen:]) |
pavleradojkovic | 0:ba7e439238ab | 470 | logger.info("[MQTT-2.3.1-1] packet indentifier must be in publish if QoS is 1 or 2") |
pavleradojkovic | 0:ba7e439238ab | 471 | curlen += 2 |
pavleradojkovic | 0:ba7e439238ab | 472 | assert self.messageIdentifier > 0, "[MQTT-2.3.1-1] packet indentifier must be > 0" |
pavleradojkovic | 0:ba7e439238ab | 473 | else: |
pavleradojkovic | 0:ba7e439238ab | 474 | logger.info("[MQTT-2.3.1-5] no packet indentifier in publish if QoS is 0") |
pavleradojkovic | 0:ba7e439238ab | 475 | self.messageIdentifier = 0 |
pavleradojkovic | 0:ba7e439238ab | 476 | self.data = buffer[curlen:fhlen + self.fh.remainingLength] |
pavleradojkovic | 0:ba7e439238ab | 477 | if self.fh.QoS == 0: |
pavleradojkovic | 0:ba7e439238ab | 478 | assert self.fh.DUP == False, "[MQTT-2.1.2-4]" |
pavleradojkovic | 0:ba7e439238ab | 479 | return fhlen + self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 480 | |
pavleradojkovic | 0:ba7e439238ab | 481 | def __repr__(self): |
pavleradojkovic | 0:ba7e439238ab | 482 | rc = repr(self.fh) |
pavleradojkovic | 0:ba7e439238ab | 483 | if self.fh.QoS != 0: |
pavleradojkovic | 0:ba7e439238ab | 484 | rc += ", MsgId="+repr(self.messageIdentifier) |
pavleradojkovic | 0:ba7e439238ab | 485 | rc += ", TopicName="+repr(self.topicName)+", Payload="+repr(self.data)+")" |
pavleradojkovic | 0:ba7e439238ab | 486 | return rc |
pavleradojkovic | 0:ba7e439238ab | 487 | |
pavleradojkovic | 0:ba7e439238ab | 488 | def __eq__(self, packet): |
pavleradojkovic | 0:ba7e439238ab | 489 | rc = Packets.__eq__(self, packet) and \ |
pavleradojkovic | 0:ba7e439238ab | 490 | self.topicName == packet.topicName and \ |
pavleradojkovic | 0:ba7e439238ab | 491 | self.data == packet.data |
pavleradojkovic | 0:ba7e439238ab | 492 | if rc and self.fh.QoS != 0: |
pavleradojkovic | 0:ba7e439238ab | 493 | rc = self.messageIdentifier == packet.messageIdentifier |
pavleradojkovic | 0:ba7e439238ab | 494 | return rc |
pavleradojkovic | 0:ba7e439238ab | 495 | |
pavleradojkovic | 0:ba7e439238ab | 496 | |
pavleradojkovic | 0:ba7e439238ab | 497 | class Pubacks(Packets): |
pavleradojkovic | 0:ba7e439238ab | 498 | |
pavleradojkovic | 0:ba7e439238ab | 499 | def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0): |
pavleradojkovic | 0:ba7e439238ab | 500 | self.fh = FixedHeaders(PUBACK) |
pavleradojkovic | 0:ba7e439238ab | 501 | self.fh.DUP = DUP |
pavleradojkovic | 0:ba7e439238ab | 502 | self.fh.QoS = QoS |
pavleradojkovic | 0:ba7e439238ab | 503 | self.fh.Retain = Retain |
pavleradojkovic | 0:ba7e439238ab | 504 | # variable header |
pavleradojkovic | 0:ba7e439238ab | 505 | self.messageIdentifier = MsgId |
pavleradojkovic | 0:ba7e439238ab | 506 | if buffer != None: |
pavleradojkovic | 0:ba7e439238ab | 507 | self.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 508 | |
pavleradojkovic | 0:ba7e439238ab | 509 | def pack(self): |
pavleradojkovic | 0:ba7e439238ab | 510 | buffer = writeInt16(self.messageIdentifier) |
pavleradojkovic | 0:ba7e439238ab | 511 | buffer = self.fh.pack(len(buffer)) + buffer |
pavleradojkovic | 0:ba7e439238ab | 512 | return buffer |
pavleradojkovic | 0:ba7e439238ab | 513 | |
pavleradojkovic | 0:ba7e439238ab | 514 | def unpack(self, buffer): |
pavleradojkovic | 0:ba7e439238ab | 515 | assert len(buffer) >= 2 |
pavleradojkovic | 0:ba7e439238ab | 516 | assert MessageType(buffer) == PUBACK |
pavleradojkovic | 0:ba7e439238ab | 517 | fhlen = self.fh.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 518 | assert self.fh.remainingLength == 2, "Puback packet is wrong length %d" % self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 519 | assert len(buffer) >= fhlen + self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 520 | self.messageIdentifier = readInt16(buffer[fhlen:]) |
pavleradojkovic | 0:ba7e439238ab | 521 | assert self.fh.DUP == False, "[MQTT-2.1.2-1] Puback reserved bits must be 0" |
pavleradojkovic | 0:ba7e439238ab | 522 | assert self.fh.QoS == 0, "[MQTT-2.1.2-1] Puback reserved bits must be 0" |
pavleradojkovic | 0:ba7e439238ab | 523 | assert self.fh.RETAIN == False, "[MQTT-2.1.2-1] Puback reserved bits must be 0" |
pavleradojkovic | 0:ba7e439238ab | 524 | return fhlen + 2 |
pavleradojkovic | 0:ba7e439238ab | 525 | |
pavleradojkovic | 0:ba7e439238ab | 526 | def __repr__(self): |
pavleradojkovic | 0:ba7e439238ab | 527 | return repr(self.fh)+", MsgId "+repr(self.messageIdentifier) |
pavleradojkovic | 0:ba7e439238ab | 528 | |
pavleradojkovic | 0:ba7e439238ab | 529 | def __eq__(self, packet): |
pavleradojkovic | 0:ba7e439238ab | 530 | return Packets.__eq__(self, packet) and \ |
pavleradojkovic | 0:ba7e439238ab | 531 | self.messageIdentifier == packet.messageIdentifier |
pavleradojkovic | 0:ba7e439238ab | 532 | |
pavleradojkovic | 0:ba7e439238ab | 533 | |
pavleradojkovic | 0:ba7e439238ab | 534 | class Pubrecs(Packets): |
pavleradojkovic | 0:ba7e439238ab | 535 | |
pavleradojkovic | 0:ba7e439238ab | 536 | def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0): |
pavleradojkovic | 0:ba7e439238ab | 537 | self.fh = FixedHeaders(PUBREC) |
pavleradojkovic | 0:ba7e439238ab | 538 | self.fh.DUP = DUP |
pavleradojkovic | 0:ba7e439238ab | 539 | self.fh.QoS = QoS |
pavleradojkovic | 0:ba7e439238ab | 540 | self.fh.Retain = Retain |
pavleradojkovic | 0:ba7e439238ab | 541 | # variable header |
pavleradojkovic | 0:ba7e439238ab | 542 | self.messageIdentifier = MsgId |
pavleradojkovic | 0:ba7e439238ab | 543 | if buffer != None: |
pavleradojkovic | 0:ba7e439238ab | 544 | self.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 545 | |
pavleradojkovic | 0:ba7e439238ab | 546 | def pack(self): |
pavleradojkovic | 0:ba7e439238ab | 547 | buffer = writeInt16(self.messageIdentifier) |
pavleradojkovic | 0:ba7e439238ab | 548 | buffer = self.fh.pack(len(buffer)) + buffer |
pavleradojkovic | 0:ba7e439238ab | 549 | return buffer |
pavleradojkovic | 0:ba7e439238ab | 550 | |
pavleradojkovic | 0:ba7e439238ab | 551 | def unpack(self, buffer): |
pavleradojkovic | 0:ba7e439238ab | 552 | assert len(buffer) >= 2 |
pavleradojkovic | 0:ba7e439238ab | 553 | assert MessageType(buffer) == PUBREC |
pavleradojkovic | 0:ba7e439238ab | 554 | fhlen = self.fh.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 555 | assert self.fh.remainingLength == 2, "Pubrec packet is wrong length %d" % self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 556 | assert len(buffer) >= fhlen + self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 557 | self.messageIdentifier = readInt16(buffer[fhlen:]) |
pavleradojkovic | 0:ba7e439238ab | 558 | assert self.fh.DUP == False, "[MQTT-2.1.2-1] Pubrec reserved bits must be 0" |
pavleradojkovic | 0:ba7e439238ab | 559 | assert self.fh.QoS == 0, "[MQTT-2.1.2-1] Pubrec reserved bits must be 0" |
pavleradojkovic | 0:ba7e439238ab | 560 | assert self.fh.RETAIN == False, "[MQTT-2.1.2-1] Pubrec reserved bits must be 0" |
pavleradojkovic | 0:ba7e439238ab | 561 | return fhlen + 2 |
pavleradojkovic | 0:ba7e439238ab | 562 | |
pavleradojkovic | 0:ba7e439238ab | 563 | def __repr__(self): |
pavleradojkovic | 0:ba7e439238ab | 564 | return repr(self.fh)+", MsgId="+repr(self.messageIdentifier)+")" |
pavleradojkovic | 0:ba7e439238ab | 565 | |
pavleradojkovic | 0:ba7e439238ab | 566 | def __eq__(self, packet): |
pavleradojkovic | 0:ba7e439238ab | 567 | return Packets.__eq__(self, packet) and \ |
pavleradojkovic | 0:ba7e439238ab | 568 | self.messageIdentifier == packet.messageIdentifier |
pavleradojkovic | 0:ba7e439238ab | 569 | |
pavleradojkovic | 0:ba7e439238ab | 570 | |
pavleradojkovic | 0:ba7e439238ab | 571 | class Pubrels(Packets): |
pavleradojkovic | 0:ba7e439238ab | 572 | |
pavleradojkovic | 0:ba7e439238ab | 573 | def __init__(self, buffer=None, DUP=False, QoS=1, Retain=False, MsgId=0): |
pavleradojkovic | 0:ba7e439238ab | 574 | self.fh = FixedHeaders(PUBREL) |
pavleradojkovic | 0:ba7e439238ab | 575 | self.fh.DUP = DUP |
pavleradojkovic | 0:ba7e439238ab | 576 | self.fh.QoS = QoS |
pavleradojkovic | 0:ba7e439238ab | 577 | self.fh.Retain = Retain |
pavleradojkovic | 0:ba7e439238ab | 578 | # variable header |
pavleradojkovic | 0:ba7e439238ab | 579 | self.messageIdentifier = MsgId |
pavleradojkovic | 0:ba7e439238ab | 580 | if buffer != None: |
pavleradojkovic | 0:ba7e439238ab | 581 | self.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 582 | |
pavleradojkovic | 0:ba7e439238ab | 583 | def pack(self): |
pavleradojkovic | 0:ba7e439238ab | 584 | buffer = writeInt16(self.messageIdentifier) |
pavleradojkovic | 0:ba7e439238ab | 585 | buffer = self.fh.pack(len(buffer)) + buffer |
pavleradojkovic | 0:ba7e439238ab | 586 | return buffer |
pavleradojkovic | 0:ba7e439238ab | 587 | |
pavleradojkovic | 0:ba7e439238ab | 588 | def unpack(self, buffer): |
pavleradojkovic | 0:ba7e439238ab | 589 | assert len(buffer) >= 2 |
pavleradojkovic | 0:ba7e439238ab | 590 | assert MessageType(buffer) == PUBREL |
pavleradojkovic | 0:ba7e439238ab | 591 | fhlen = self.fh.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 592 | assert self.fh.remainingLength == 2, "Pubrel packet is wrong length %d" % self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 593 | assert len(buffer) >= fhlen + self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 594 | self.messageIdentifier = readInt16(buffer[fhlen:]) |
pavleradojkovic | 0:ba7e439238ab | 595 | assert self.fh.DUP == False, "[MQTT-2.1.2-1] DUP should be False in PUBREL" |
pavleradojkovic | 0:ba7e439238ab | 596 | assert self.fh.QoS == 1, "[MQTT-2.1.2-1] QoS should be 1 in PUBREL" |
pavleradojkovic | 0:ba7e439238ab | 597 | assert self.fh.RETAIN == False, "[MQTT-2.1.2-1] RETAIN should be False in PUBREL" |
pavleradojkovic | 0:ba7e439238ab | 598 | logger.info("[MQTT-3.6.1-1] bits in fixed header for pubrel are ok") |
pavleradojkovic | 0:ba7e439238ab | 599 | return fhlen + 2 |
pavleradojkovic | 0:ba7e439238ab | 600 | |
pavleradojkovic | 0:ba7e439238ab | 601 | def __repr__(self): |
pavleradojkovic | 0:ba7e439238ab | 602 | return repr(self.fh)+", MsgId="+repr(self.messageIdentifier)+")" |
pavleradojkovic | 0:ba7e439238ab | 603 | |
pavleradojkovic | 0:ba7e439238ab | 604 | def __eq__(self, packet): |
pavleradojkovic | 0:ba7e439238ab | 605 | return Packets.__eq__(self, packet) and \ |
pavleradojkovic | 0:ba7e439238ab | 606 | self.messageIdentifier == packet.messageIdentifier |
pavleradojkovic | 0:ba7e439238ab | 607 | |
pavleradojkovic | 0:ba7e439238ab | 608 | |
pavleradojkovic | 0:ba7e439238ab | 609 | class Pubcomps(Packets): |
pavleradojkovic | 0:ba7e439238ab | 610 | |
pavleradojkovic | 0:ba7e439238ab | 611 | def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0): |
pavleradojkovic | 0:ba7e439238ab | 612 | self.fh = FixedHeaders(PUBCOMP) |
pavleradojkovic | 0:ba7e439238ab | 613 | self.fh.DUP = DUP |
pavleradojkovic | 0:ba7e439238ab | 614 | self.fh.QoS = QoS |
pavleradojkovic | 0:ba7e439238ab | 615 | self.fh.Retain = Retain |
pavleradojkovic | 0:ba7e439238ab | 616 | # variable header |
pavleradojkovic | 0:ba7e439238ab | 617 | self.messageIdentifier = MsgId |
pavleradojkovic | 0:ba7e439238ab | 618 | if buffer != None: |
pavleradojkovic | 0:ba7e439238ab | 619 | self.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 620 | |
pavleradojkovic | 0:ba7e439238ab | 621 | def pack(self): |
pavleradojkovic | 0:ba7e439238ab | 622 | buffer = writeInt16(self.messageIdentifier) |
pavleradojkovic | 0:ba7e439238ab | 623 | buffer = self.fh.pack(len(buffer)) + buffer |
pavleradojkovic | 0:ba7e439238ab | 624 | return buffer |
pavleradojkovic | 0:ba7e439238ab | 625 | |
pavleradojkovic | 0:ba7e439238ab | 626 | def unpack(self, buffer): |
pavleradojkovic | 0:ba7e439238ab | 627 | assert len(buffer) >= 2 |
pavleradojkovic | 0:ba7e439238ab | 628 | assert MessageType(buffer) == PUBCOMP |
pavleradojkovic | 0:ba7e439238ab | 629 | fhlen = self.fh.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 630 | assert len(buffer) >= fhlen + self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 631 | assert self.fh.remainingLength == 2, "Pubcomp packet is wrong length %d" % self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 632 | self.messageIdentifier = readInt16(buffer[fhlen:]) |
pavleradojkovic | 0:ba7e439238ab | 633 | assert self.fh.DUP == False, "[MQTT-2.1.2-1] DUP should be False in Pubcomp" |
pavleradojkovic | 0:ba7e439238ab | 634 | assert self.fh.QoS == 0, "[MQTT-2.1.2-1] QoS should be 0 in Pubcomp" |
pavleradojkovic | 0:ba7e439238ab | 635 | assert self.fh.RETAIN == False, "[MQTT-2.1.2-1] Retain should be false in Pubcomp" |
pavleradojkovic | 0:ba7e439238ab | 636 | return fhlen + 2 |
pavleradojkovic | 0:ba7e439238ab | 637 | |
pavleradojkovic | 0:ba7e439238ab | 638 | def __repr__(self): |
pavleradojkovic | 0:ba7e439238ab | 639 | return repr(self.fh)+", MsgId="+repr(self.messageIdentifier)+")" |
pavleradojkovic | 0:ba7e439238ab | 640 | |
pavleradojkovic | 0:ba7e439238ab | 641 | def __eq__(self, packet): |
pavleradojkovic | 0:ba7e439238ab | 642 | return Packets.__eq__(self, packet) and \ |
pavleradojkovic | 0:ba7e439238ab | 643 | self.messageIdentifier == packet.messageIdentifier |
pavleradojkovic | 0:ba7e439238ab | 644 | |
pavleradojkovic | 0:ba7e439238ab | 645 | |
pavleradojkovic | 0:ba7e439238ab | 646 | class Subscribes(Packets): |
pavleradojkovic | 0:ba7e439238ab | 647 | |
pavleradojkovic | 0:ba7e439238ab | 648 | def __init__(self, buffer=None, DUP=False, QoS=1, Retain=False, MsgId=0, Data=[]): |
pavleradojkovic | 0:ba7e439238ab | 649 | self.fh = FixedHeaders(SUBSCRIBE) |
pavleradojkovic | 0:ba7e439238ab | 650 | self.fh.DUP = DUP |
pavleradojkovic | 0:ba7e439238ab | 651 | self.fh.QoS = QoS |
pavleradojkovic | 0:ba7e439238ab | 652 | self.fh.Retain = Retain |
pavleradojkovic | 0:ba7e439238ab | 653 | # variable header |
pavleradojkovic | 0:ba7e439238ab | 654 | self.messageIdentifier = MsgId |
pavleradojkovic | 0:ba7e439238ab | 655 | # payload - list of topic, qos pairs |
pavleradojkovic | 0:ba7e439238ab | 656 | self.data = Data[:] |
pavleradojkovic | 0:ba7e439238ab | 657 | if buffer != None: |
pavleradojkovic | 0:ba7e439238ab | 658 | self.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 659 | |
pavleradojkovic | 0:ba7e439238ab | 660 | def pack(self): |
pavleradojkovic | 0:ba7e439238ab | 661 | buffer = writeInt16(self.messageIdentifier) |
pavleradojkovic | 0:ba7e439238ab | 662 | for d in self.data: |
pavleradojkovic | 0:ba7e439238ab | 663 | buffer += writeUTF(d[0]) + bytes([d[1]]) |
pavleradojkovic | 0:ba7e439238ab | 664 | buffer = self.fh.pack(len(buffer)) + buffer |
pavleradojkovic | 0:ba7e439238ab | 665 | return buffer |
pavleradojkovic | 0:ba7e439238ab | 666 | |
pavleradojkovic | 0:ba7e439238ab | 667 | def unpack(self, buffer): |
pavleradojkovic | 0:ba7e439238ab | 668 | assert len(buffer) >= 2 |
pavleradojkovic | 0:ba7e439238ab | 669 | assert MessageType(buffer) == SUBSCRIBE |
pavleradojkovic | 0:ba7e439238ab | 670 | fhlen = self.fh.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 671 | assert len(buffer) >= fhlen + self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 672 | logger.info("[MQTT-2.3.1-1] packet indentifier must be in subscribe") |
pavleradojkovic | 0:ba7e439238ab | 673 | self.messageIdentifier = readInt16(buffer[fhlen:]) |
pavleradojkovic | 0:ba7e439238ab | 674 | assert self.messageIdentifier > 0, "[MQTT-2.3.1-1] packet indentifier must be > 0" |
pavleradojkovic | 0:ba7e439238ab | 675 | leftlen = self.fh.remainingLength - 2 |
pavleradojkovic | 0:ba7e439238ab | 676 | self.data = [] |
pavleradojkovic | 0:ba7e439238ab | 677 | while leftlen > 0: |
pavleradojkovic | 0:ba7e439238ab | 678 | topic = readUTF(buffer[-leftlen:], leftlen) |
pavleradojkovic | 0:ba7e439238ab | 679 | leftlen -= len(topic) + 2 |
pavleradojkovic | 0:ba7e439238ab | 680 | qos = ord(buffer[-leftlen]) |
pavleradojkovic | 0:ba7e439238ab | 681 | assert qos in [0, 1, 2], "[MQTT-3-8.3-2] reserved bits must be zero" |
pavleradojkovic | 0:ba7e439238ab | 682 | leftlen -= 1 |
pavleradojkovic | 0:ba7e439238ab | 683 | self.data.append((topic, qos)) |
pavleradojkovic | 0:ba7e439238ab | 684 | assert len(self.data) > 0, "[MQTT-3.8.3-1] at least one topic, qos pair must be in subscribe" |
pavleradojkovic | 0:ba7e439238ab | 685 | assert leftlen == 0 |
pavleradojkovic | 0:ba7e439238ab | 686 | assert self.fh.DUP == False, "[MQTT-2.1.2-1] DUP must be false in subscribe" |
pavleradojkovic | 0:ba7e439238ab | 687 | assert self.fh.QoS == 1, "[MQTT-2.1.2-1] QoS must be 1 in subscribe" |
pavleradojkovic | 0:ba7e439238ab | 688 | assert self.fh.RETAIN == False, "[MQTT-2.1.2-1] RETAIN must be false in subscribe" |
pavleradojkovic | 0:ba7e439238ab | 689 | return fhlen + self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 690 | |
pavleradojkovic | 0:ba7e439238ab | 691 | def __repr__(self): |
pavleradojkovic | 0:ba7e439238ab | 692 | return repr(self.fh)+", MsgId="+repr(self.messageIdentifier)+\ |
pavleradojkovic | 0:ba7e439238ab | 693 | ", Data="+repr(self.data)+")" |
pavleradojkovic | 0:ba7e439238ab | 694 | |
pavleradojkovic | 0:ba7e439238ab | 695 | def __eq__(self, packet): |
pavleradojkovic | 0:ba7e439238ab | 696 | return Packets.__eq__(self, packet) and \ |
pavleradojkovic | 0:ba7e439238ab | 697 | self.messageIdentifier == packet.messageIdentifier and \ |
pavleradojkovic | 0:ba7e439238ab | 698 | self.data == packet.data |
pavleradojkovic | 0:ba7e439238ab | 699 | |
pavleradojkovic | 0:ba7e439238ab | 700 | |
pavleradojkovic | 0:ba7e439238ab | 701 | class Subacks(Packets): |
pavleradojkovic | 0:ba7e439238ab | 702 | |
pavleradojkovic | 0:ba7e439238ab | 703 | def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0, Data=[]): |
pavleradojkovic | 0:ba7e439238ab | 704 | self.fh = FixedHeaders(SUBACK) |
pavleradojkovic | 0:ba7e439238ab | 705 | self.fh.DUP = DUP |
pavleradojkovic | 0:ba7e439238ab | 706 | self.fh.QoS = QoS |
pavleradojkovic | 0:ba7e439238ab | 707 | self.fh.Retain = Retain |
pavleradojkovic | 0:ba7e439238ab | 708 | # variable header |
pavleradojkovic | 0:ba7e439238ab | 709 | self.messageIdentifier = MsgId |
pavleradojkovic | 0:ba7e439238ab | 710 | # payload - list of qos |
pavleradojkovic | 0:ba7e439238ab | 711 | self.data = Data[:] |
pavleradojkovic | 0:ba7e439238ab | 712 | if buffer != None: |
pavleradojkovic | 0:ba7e439238ab | 713 | self.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 714 | |
pavleradojkovic | 0:ba7e439238ab | 715 | def pack(self): |
pavleradojkovic | 0:ba7e439238ab | 716 | buffer = writeInt16(self.messageIdentifier) |
pavleradojkovic | 0:ba7e439238ab | 717 | for d in self.data: |
pavleradojkovic | 0:ba7e439238ab | 718 | buffer += bytes([d]) |
pavleradojkovic | 0:ba7e439238ab | 719 | buffer = self.fh.pack(len(buffer)) + buffer |
pavleradojkovic | 0:ba7e439238ab | 720 | return buffer |
pavleradojkovic | 0:ba7e439238ab | 721 | |
pavleradojkovic | 0:ba7e439238ab | 722 | def unpack(self, buffer): |
pavleradojkovic | 0:ba7e439238ab | 723 | assert len(buffer) >= 2 |
pavleradojkovic | 0:ba7e439238ab | 724 | assert MessageType(buffer) == SUBACK |
pavleradojkovic | 0:ba7e439238ab | 725 | fhlen = self.fh.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 726 | assert len(buffer) >= fhlen + self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 727 | self.messageIdentifier = readInt16(buffer[fhlen:]) |
pavleradojkovic | 0:ba7e439238ab | 728 | leftlen = self.fh.remainingLength - 2 |
pavleradojkovic | 0:ba7e439238ab | 729 | self.data = [] |
pavleradojkovic | 0:ba7e439238ab | 730 | while leftlen > 0: |
pavleradojkovic | 0:ba7e439238ab | 731 | qos = buffer[-leftlen] |
pavleradojkovic | 0:ba7e439238ab | 732 | assert ord(qos) in [0, 1, 2, 0x80], "[MQTT-3.9.3-2] return code in QoS must be 0, 1, 2 or 0x80, was "+ord(qos) |
pavleradojkovic | 0:ba7e439238ab | 733 | leftlen -= 1 |
pavleradojkovic | 0:ba7e439238ab | 734 | self.data.append(qos) |
pavleradojkovic | 0:ba7e439238ab | 735 | assert leftlen == 0 |
pavleradojkovic | 0:ba7e439238ab | 736 | assert self.fh.DUP == False, "[MQTT-2.1.2-1] DUP should be false in suback" |
pavleradojkovic | 0:ba7e439238ab | 737 | assert self.fh.QoS == 0, "[MQTT-2.1.2-1] QoS should be 0 in suback" |
pavleradojkovic | 0:ba7e439238ab | 738 | assert self.fh.RETAIN == False, "[MQTT-2.1.2-1] Retain should be false in suback" |
pavleradojkovic | 0:ba7e439238ab | 739 | return fhlen + self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 740 | |
pavleradojkovic | 0:ba7e439238ab | 741 | def __repr__(self): |
pavleradojkovic | 0:ba7e439238ab | 742 | return repr(self.fh)+", MsgId="+repr(self.messageIdentifier)+\ |
pavleradojkovic | 0:ba7e439238ab | 743 | ", Data="+repr(self.data)+")" |
pavleradojkovic | 0:ba7e439238ab | 744 | |
pavleradojkovic | 0:ba7e439238ab | 745 | def __eq__(self, packet): |
pavleradojkovic | 0:ba7e439238ab | 746 | return Packets.__eq__(self, packet) and \ |
pavleradojkovic | 0:ba7e439238ab | 747 | self.messageIdentifier == packet.messageIdentifier and \ |
pavleradojkovic | 0:ba7e439238ab | 748 | self.data == packet.data |
pavleradojkovic | 0:ba7e439238ab | 749 | |
pavleradojkovic | 0:ba7e439238ab | 750 | |
pavleradojkovic | 0:ba7e439238ab | 751 | class Unsubscribes(Packets): |
pavleradojkovic | 0:ba7e439238ab | 752 | |
pavleradojkovic | 0:ba7e439238ab | 753 | def __init__(self, buffer=None, DUP=False, QoS=1, Retain=False, MsgId=0, Data=[]): |
pavleradojkovic | 0:ba7e439238ab | 754 | self.fh = FixedHeaders(UNSUBSCRIBE) |
pavleradojkovic | 0:ba7e439238ab | 755 | self.fh.DUP = DUP |
pavleradojkovic | 0:ba7e439238ab | 756 | self.fh.QoS = QoS |
pavleradojkovic | 0:ba7e439238ab | 757 | self.fh.Retain = Retain |
pavleradojkovic | 0:ba7e439238ab | 758 | # variable header |
pavleradojkovic | 0:ba7e439238ab | 759 | self.messageIdentifier = MsgId |
pavleradojkovic | 0:ba7e439238ab | 760 | # payload - list of topics |
pavleradojkovic | 0:ba7e439238ab | 761 | self.data = Data[:] |
pavleradojkovic | 0:ba7e439238ab | 762 | if buffer != None: |
pavleradojkovic | 0:ba7e439238ab | 763 | self.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 764 | |
pavleradojkovic | 0:ba7e439238ab | 765 | def pack(self): |
pavleradojkovic | 0:ba7e439238ab | 766 | buffer = writeInt16(self.messageIdentifier) |
pavleradojkovic | 0:ba7e439238ab | 767 | for d in self.data: |
pavleradojkovic | 0:ba7e439238ab | 768 | buffer += writeUTF(d) |
pavleradojkovic | 0:ba7e439238ab | 769 | buffer = self.fh.pack(len(buffer)) + buffer |
pavleradojkovic | 0:ba7e439238ab | 770 | return buffer |
pavleradojkovic | 0:ba7e439238ab | 771 | |
pavleradojkovic | 0:ba7e439238ab | 772 | def unpack(self, buffer): |
pavleradojkovic | 0:ba7e439238ab | 773 | assert len(buffer) >= 2 |
pavleradojkovic | 0:ba7e439238ab | 774 | assert MessageType(buffer) == UNSUBSCRIBE |
pavleradojkovic | 0:ba7e439238ab | 775 | fhlen = self.fh.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 776 | assert len(buffer) >= fhlen + self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 777 | logger.info("[MQTT-2.3.1-1] packet indentifier must be in unsubscribe") |
pavleradojkovic | 0:ba7e439238ab | 778 | self.messageIdentifier = readInt16(buffer[fhlen:]) |
pavleradojkovic | 0:ba7e439238ab | 779 | assert self.messageIdentifier > 0, "[MQTT-2.3.1-1] packet indentifier must be > 0" |
pavleradojkovic | 0:ba7e439238ab | 780 | leftlen = self.fh.remainingLength - 2 |
pavleradojkovic | 0:ba7e439238ab | 781 | self.data = [] |
pavleradojkovic | 0:ba7e439238ab | 782 | while leftlen > 0: |
pavleradojkovic | 0:ba7e439238ab | 783 | topic = readUTF(buffer[-leftlen:], leftlen) |
pavleradojkovic | 0:ba7e439238ab | 784 | leftlen -= len(topic) + 2 |
pavleradojkovic | 0:ba7e439238ab | 785 | self.data.append(topic) |
pavleradojkovic | 0:ba7e439238ab | 786 | assert leftlen == 0 |
pavleradojkovic | 0:ba7e439238ab | 787 | assert self.fh.DUP == False, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 788 | assert self.fh.QoS == 1, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 789 | assert self.fh.RETAIN == False, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 790 | logger.info("[MQTT-3-10.1-1] fixed header bits are 0,0,1,0") |
pavleradojkovic | 0:ba7e439238ab | 791 | return fhlen + self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 792 | |
pavleradojkovic | 0:ba7e439238ab | 793 | def __repr__(self): |
pavleradojkovic | 0:ba7e439238ab | 794 | return repr(self.fh)+", MsgId="+repr(self.messageIdentifier)+\ |
pavleradojkovic | 0:ba7e439238ab | 795 | ", Data="+repr(self.data)+")" |
pavleradojkovic | 0:ba7e439238ab | 796 | |
pavleradojkovic | 0:ba7e439238ab | 797 | def __eq__(self, packet): |
pavleradojkovic | 0:ba7e439238ab | 798 | return Packets.__eq__(self, packet) and \ |
pavleradojkovic | 0:ba7e439238ab | 799 | self.messageIdentifier == packet.messageIdentifier and \ |
pavleradojkovic | 0:ba7e439238ab | 800 | self.data == packet.data |
pavleradojkovic | 0:ba7e439238ab | 801 | |
pavleradojkovic | 0:ba7e439238ab | 802 | |
pavleradojkovic | 0:ba7e439238ab | 803 | class Unsubacks(Packets): |
pavleradojkovic | 0:ba7e439238ab | 804 | |
pavleradojkovic | 0:ba7e439238ab | 805 | def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0): |
pavleradojkovic | 0:ba7e439238ab | 806 | self.fh = FixedHeaders(UNSUBACK) |
pavleradojkovic | 0:ba7e439238ab | 807 | self.fh.DUP = DUP |
pavleradojkovic | 0:ba7e439238ab | 808 | self.fh.QoS = QoS |
pavleradojkovic | 0:ba7e439238ab | 809 | self.fh.Retain = Retain |
pavleradojkovic | 0:ba7e439238ab | 810 | # variable header |
pavleradojkovic | 0:ba7e439238ab | 811 | self.messageIdentifier = MsgId |
pavleradojkovic | 0:ba7e439238ab | 812 | if buffer != None: |
pavleradojkovic | 0:ba7e439238ab | 813 | self.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 814 | |
pavleradojkovic | 0:ba7e439238ab | 815 | def pack(self): |
pavleradojkovic | 0:ba7e439238ab | 816 | buffer = writeInt16(self.messageIdentifier) |
pavleradojkovic | 0:ba7e439238ab | 817 | buffer = self.fh.pack(len(buffer)) + buffer |
pavleradojkovic | 0:ba7e439238ab | 818 | return buffer |
pavleradojkovic | 0:ba7e439238ab | 819 | |
pavleradojkovic | 0:ba7e439238ab | 820 | def unpack(self, buffer): |
pavleradojkovic | 0:ba7e439238ab | 821 | assert len(buffer) >= 2 |
pavleradojkovic | 0:ba7e439238ab | 822 | assert MessageType(buffer) == UNSUBACK |
pavleradojkovic | 0:ba7e439238ab | 823 | fhlen = self.fh.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 824 | assert len(buffer) >= fhlen + self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 825 | self.messageIdentifier = readInt16(buffer[fhlen:]) |
pavleradojkovic | 0:ba7e439238ab | 826 | assert self.messageIdentifier > 0, "[MQTT-2.3.1-1] packet indentifier must be > 0" |
pavleradojkovic | 0:ba7e439238ab | 827 | self.messageIdentifier = readInt16(buffer[fhlen:]) |
pavleradojkovic | 0:ba7e439238ab | 828 | assert self.fh.DUP == False, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 829 | assert self.fh.QoS == 0, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 830 | assert self.fh.RETAIN == False, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 831 | return fhlen + self.fh.remainingLength |
pavleradojkovic | 0:ba7e439238ab | 832 | |
pavleradojkovic | 0:ba7e439238ab | 833 | def __repr__(self): |
pavleradojkovic | 0:ba7e439238ab | 834 | return repr(self.fh)+", MsgId="+repr(self.messageIdentifier)+")" |
pavleradojkovic | 0:ba7e439238ab | 835 | |
pavleradojkovic | 0:ba7e439238ab | 836 | def __eq__(self, packet): |
pavleradojkovic | 0:ba7e439238ab | 837 | return Packets.__eq__(self, packet) and \ |
pavleradojkovic | 0:ba7e439238ab | 838 | self.messageIdentifier == packet.messageIdentifier |
pavleradojkovic | 0:ba7e439238ab | 839 | |
pavleradojkovic | 0:ba7e439238ab | 840 | |
pavleradojkovic | 0:ba7e439238ab | 841 | class Pingreqs(Packets): |
pavleradojkovic | 0:ba7e439238ab | 842 | |
pavleradojkovic | 0:ba7e439238ab | 843 | def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False): |
pavleradojkovic | 0:ba7e439238ab | 844 | self.fh = FixedHeaders(PINGREQ) |
pavleradojkovic | 0:ba7e439238ab | 845 | self.fh.DUP = DUP |
pavleradojkovic | 0:ba7e439238ab | 846 | self.fh.QoS = QoS |
pavleradojkovic | 0:ba7e439238ab | 847 | self.fh.Retain = Retain |
pavleradojkovic | 0:ba7e439238ab | 848 | if buffer != None: |
pavleradojkovic | 0:ba7e439238ab | 849 | self.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 850 | |
pavleradojkovic | 0:ba7e439238ab | 851 | def unpack(self, buffer): |
pavleradojkovic | 0:ba7e439238ab | 852 | assert len(buffer) >= 2 |
pavleradojkovic | 0:ba7e439238ab | 853 | assert MessageType(buffer) == PINGREQ |
pavleradojkovic | 0:ba7e439238ab | 854 | fhlen = self.fh.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 855 | assert self.fh.remainingLength == 0 |
pavleradojkovic | 0:ba7e439238ab | 856 | assert self.fh.DUP == False, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 857 | assert self.fh.QoS == 0, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 858 | assert self.fh.RETAIN == False, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 859 | return fhlen |
pavleradojkovic | 0:ba7e439238ab | 860 | |
pavleradojkovic | 0:ba7e439238ab | 861 | def __repr__(self): |
pavleradojkovic | 0:ba7e439238ab | 862 | return repr(self.fh)+")" |
pavleradojkovic | 0:ba7e439238ab | 863 | |
pavleradojkovic | 0:ba7e439238ab | 864 | |
pavleradojkovic | 0:ba7e439238ab | 865 | class Pingresps(Packets): |
pavleradojkovic | 0:ba7e439238ab | 866 | |
pavleradojkovic | 0:ba7e439238ab | 867 | def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False): |
pavleradojkovic | 0:ba7e439238ab | 868 | self.fh = FixedHeaders(PINGRESP) |
pavleradojkovic | 0:ba7e439238ab | 869 | self.fh.DUP = DUP |
pavleradojkovic | 0:ba7e439238ab | 870 | self.fh.QoS = QoS |
pavleradojkovic | 0:ba7e439238ab | 871 | self.fh.Retain = Retain |
pavleradojkovic | 0:ba7e439238ab | 872 | if buffer != None: |
pavleradojkovic | 0:ba7e439238ab | 873 | self.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 874 | |
pavleradojkovic | 0:ba7e439238ab | 875 | def unpack(self, buffer): |
pavleradojkovic | 0:ba7e439238ab | 876 | assert len(buffer) >= 2 |
pavleradojkovic | 0:ba7e439238ab | 877 | assert MessageType(buffer) == PINGRESP |
pavleradojkovic | 0:ba7e439238ab | 878 | fhlen = self.fh.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 879 | assert self.fh.remainingLength == 0 |
pavleradojkovic | 0:ba7e439238ab | 880 | assert self.fh.DUP == False, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 881 | assert self.fh.QoS == 0, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 882 | assert self.fh.RETAIN == False, "[MQTT-2.1.2-1]" |
pavleradojkovic | 0:ba7e439238ab | 883 | return fhlen |
pavleradojkovic | 0:ba7e439238ab | 884 | |
pavleradojkovic | 0:ba7e439238ab | 885 | def __repr__(self): |
pavleradojkovic | 0:ba7e439238ab | 886 | return repr(self.fh)+")" |
pavleradojkovic | 0:ba7e439238ab | 887 | |
pavleradojkovic | 0:ba7e439238ab | 888 | classes = [None, Connects, Connacks, Publishes, Pubacks, Pubrecs, |
pavleradojkovic | 0:ba7e439238ab | 889 | Pubrels, Pubcomps, Subscribes, Subacks, Unsubscribes, |
pavleradojkovic | 0:ba7e439238ab | 890 | Unsubacks, Pingreqs, Pingresps, Disconnects] |
pavleradojkovic | 0:ba7e439238ab | 891 | |
pavleradojkovic | 0:ba7e439238ab | 892 | def unpackPacket(buffer): |
pavleradojkovic | 0:ba7e439238ab | 893 | if MessageType(buffer) != None: |
pavleradojkovic | 0:ba7e439238ab | 894 | packet = classes[MessageType(buffer)]() |
pavleradojkovic | 0:ba7e439238ab | 895 | packet.unpack(buffer) |
pavleradojkovic | 0:ba7e439238ab | 896 | else: |
pavleradojkovic | 0:ba7e439238ab | 897 | packet = None |
pavleradojkovic | 0:ba7e439238ab | 898 | return packet |
pavleradojkovic | 0:ba7e439238ab | 899 | |
pavleradojkovic | 0:ba7e439238ab | 900 | if __name__ == "__main__": |
pavleradojkovic | 0:ba7e439238ab | 901 | fh = FixedHeaders(CONNECT) |
pavleradojkovic | 0:ba7e439238ab | 902 | tests = [0, 56, 127, 128, 8888, 16383, 16384, 65535, 2097151, 2097152, |
pavleradojkovic | 0:ba7e439238ab | 903 | 20555666, 268435454, 268435455] |
pavleradojkovic | 0:ba7e439238ab | 904 | for x in tests: |
pavleradojkovic | 0:ba7e439238ab | 905 | try: |
pavleradojkovic | 0:ba7e439238ab | 906 | assert x == fh.decode(fh.encode(x))[0] |
pavleradojkovic | 0:ba7e439238ab | 907 | except AssertionError: |
pavleradojkovic | 0:ba7e439238ab | 908 | print("Test failed for x =", x, fh.decode(fh.encode(x))) |
pavleradojkovic | 0:ba7e439238ab | 909 | try: |
pavleradojkovic | 0:ba7e439238ab | 910 | fh.decode(fh.encode(268435456)) |
pavleradojkovic | 0:ba7e439238ab | 911 | print("Error") |
pavleradojkovic | 0:ba7e439238ab | 912 | except AssertionError: |
pavleradojkovic | 0:ba7e439238ab | 913 | pass |
pavleradojkovic | 0:ba7e439238ab | 914 | |
pavleradojkovic | 0:ba7e439238ab | 915 | for packet in classes[1:]: |
pavleradojkovic | 0:ba7e439238ab | 916 | before = str(packet()) |
pavleradojkovic | 0:ba7e439238ab | 917 | after = str(unpackPacket(packet().pack())) |
pavleradojkovic | 0:ba7e439238ab | 918 | try: |
pavleradojkovic | 0:ba7e439238ab | 919 | assert before == after |
pavleradojkovic | 0:ba7e439238ab | 920 | except: |
pavleradojkovic | 0:ba7e439238ab | 921 | print("before:", before, "\nafter:", after) |
pavleradojkovic | 0:ba7e439238ab | 922 | print("End") |
pavleradojkovic | 0:ba7e439238ab | 923 |