def generatePacketData(packetID: int, reasonCode: int, reasonString: str, userProperties: dict) -> bytes: """ userProperties e un dictionar cu cheie string si valori de tip lista de string """ fixed = b"\x50" packet_id = struct.pack("!H", packetID) variable = packet_id + struct.pack("!B", reasonCode) properties = b"\x1f" + CustomUTF8.encode(reasonString) for key in userProperties.keys(): for value in userProperties[key]: properties += b"\x26" + CustomUTF8.encode( key) + CustomUTF8.encode(value) propertyLength = VariableByte.encode(len(properties)) variable += propertyLength variable += properties remainingLength = VariableByte.encode(len(variable)) fixed += remainingLength return fixed + variable
def generatePacketData(packetID: int, reasonString:str, userProperties:dict, payload:list) -> bytes: fixed = b"\x90" #TODO : add remaining length variable = struct.pack("!H", packetID) props = b"\x1F"+CustomUTF8.encode(reasonString) for key in userProperties.keys(): for value in userProperties[key]: props+=b"\x26"+CustomUTF8.encode(key)+CustomUTF8.encode(value) variable+=VariableByte.encode(len(props))+props remainingLength = VariableByte.encode(len(variable)) fixed+=remainingLength payload_data = b"" for response_reason_code in payload: payload_data += struct.pack("!B", response_reason_code) return fixed+variable+payload_data
def parseFixedHeader(self): fixed_part = self.data[:1] num = b"" for byte in self.data[1:]: num += struct.pack("!B", byte) if byte < 0x80: break required = len(num) self.fixed['type'], self.fixed['remainingLength'] = struct.unpack( "!B{}s".format(required), fixed_part + num) self.fixed['type'] >>= 4 self.fixed['remainingLength'] = VariableByte.decode( self.fixed['remainingLength']) self.fixed_size = 1 + required
def parseVariableHeader(self): variableHeader = self.data[self.fixed_size:] self.variable['packet_id'] = struct.unpack("!H", variableHeader[:2])[0] variableHeader = variableHeader[2:] # 2 bytes so far properties = variableHeader num = b"" for byte in properties: num += struct.pack("!B", byte) if byte < 0x80: break required = len(num) self.variable['propertyLength'] = struct.unpack( "!{}s".format(required), num)[0] self.variable['propertyLength'] = VariableByte.decode( self.variable['propertyLength']) self.variable['properties'] = {} self.variable['properties']['userProperty'] = {} self.variable_size = 2 + self.variable['propertyLength'] properties = properties[required:] i = 0 while i < self.variable['propertyLength']: if properties[i] == 0x0B: if 'subscription_identifier' not in self.variable[ 'properties'].keys(): self.variable['properties'][ 'subscription_identifier'] = struct.unpack( "!B", properties[i + 1:i + 2])[0] else: raise MQTTError( "Malformed Packet: Subscription Identifier already exist" ) if properties[i] == 0x26: offset1, str1 = readCustomUTF8String(properties[i + 1:]) offset2, str2 = readCustomUTF8String(properties[i + 1 + offset1:]) if str1 not in self.variable['properties'][ 'userProperty'].keys(): self.variable['properties']['userProperty'][str1] = [str2] else: self.variable['properties']['userProperty'][str1].append( str2) i += offset1 + offset2 i = i + 1
class SubscribePacket(MQTTPacket): def __init__(self, data): self.data = data self.fixed = {} self.fixed_size = 0 self.variable = {} self.variable_size = 0 self.payload = {} self.payload_size = 0 def parseFixedHeader(self): fixed_part = self.data[:1] num=b"" for byte in self.data[1:]: num+=struct.pack("!B", byte) if byte<0x80: break required=len(num) self.fixed['type'], self.fixed['remainingLength'] = struct.unpack("!B{}s".format(required), fixed_part+num) if self.fixed['type'] & 0x0F != 0x02: raise MQTTError("Malformed Packet") self.fixed['type']>>=4 self.fixed['remainingLength']=VariableByte.decode(self.fixed['remainingLength']) self.fixed_size=1+required
def parseVariableHeader(self): variableHeader = self.data[self.fixed_size:] #pubrec packed id packet_id_MSB, packet_id_LSB = struct.unpack("!2b", variableHeader[:2]) self.variable['packet_id'] = (packet_id_MSB << 8) + packet_id_LSB variableHeader = variableHeader[2:] #pubrec reason code pubrec_reason_code = struct.unpack("!B", variableHeader[:1])[0] self.variable['pubrec_reason_code'] = pubrec_reason_code if (self.fixed['remainingLength'] == 2): self.variable['pubrec_reason_code'] = 0x00 variableHeader = variableHeader[1:] #properties can be omitted if the reason code is Success #3 bytes so far (1 byte from packet_id_MSB + 1 byte from packet_id_LSB + 1 byte from reason code), this offset will help me for properties index #in case if reason code isn't Success, properties can't be omitted properties = self.data[self.fixed_size + 3:] #in num I add the properties byte by byte num = b"" for byte in properties: num += struct.pack("!B", byte) if byte < 0x80: break required = len(num) self.variable['propertyLength'] = struct.unpack( "!{}s".format(required), num)[0] #i will decode the byte format in order to have an integer which is in fact the length of properties self.variable['propertyLength'] = VariableByte.decode( self.variable['propertyLength']) #print("prop length:" + str(self.variable['propertyLength'])) if (self.fixed['remainingLength'] < 4): self.variable['propertyLength'] = 0 else: self.variable['properties'] = {} self.variable['properties']['userProperty'] = {} #my variable header is composed by the 3 bytes from above + all the properties #it means that its length is the sum of 3 bytes from above and the length of properties self.variable_size = self.variable['propertyLength'] + 3 properties = properties[required:] i = 0 while i < self.variable['propertyLength']: if properties[i] == 0x1f: if 'reason_string' not in self.variable['properties'].keys( ): OFFSET_TO_READ_START = i + 1 OFFSET_TO_READ_END = i + 3 to_read = properties[ OFFSET_TO_READ_START: OFFSET_TO_READ_END] #octetii care arata lungimea #print("to read: " + str(to_read)) efective_length = struct.unpack( "!H", to_read )[0] #transf in nr => lungimea stringului meu de 2 bytes #print("efective_lentgh: " + str(efective_length)) self.variable['properties'][ 'reason_string'] = CustomUTF8.decode( struct.unpack( "!{}s".format(2 + efective_length), properties[i + 1:i + 3 + efective_length])[0]) i = i + 2 + efective_length else: raise MQTTError( "Malformed Packet : reason string already exists") if properties[i] == 0x26: OFFSET_TO_READ_1_START = i + 1 OFFSET_TO_READ_1_END = i + 3 to_read = properties[ OFFSET_TO_READ_1_START:OFFSET_TO_READ_1_END] str1size = struct.unpack("!H", to_read)[0] str1 = struct.unpack( "!{}s".format(str1size + OFFSET_TO_READ_1_END - OFFSET_TO_READ_1_START), properties[ OFFSET_TO_READ_1_START:OFFSET_TO_READ_1_END + str1size])[0] OFFSET_TO_READ_2_START = i + 3 + str1size OFFSET_TO_READ_2_END = i + 5 + str1size to_read2 = properties[ OFFSET_TO_READ_2_START:OFFSET_TO_READ_2_END] str2size = struct.unpack("!H", to_read2)[0] str2 = struct.unpack( "!{}s".format(str2size + OFFSET_TO_READ_2_END - OFFSET_TO_READ_2_START), properties[ OFFSET_TO_READ_2_START:OFFSET_TO_READ_2_END + str2size])[0] if CustomUTF8.decode(str1) not in self.variable[ 'properties']['userProperty'].keys(): self.variable['properties']['userProperty'][ CustomUTF8.decode(str1)] = [ CustomUTF8.decode(str2) ] else: self.variable['properties']['userProperty'][ CustomUTF8.decode(str1)].append( CustomUTF8.decode(str2)) i += 4 + len(CustomUTF8.decode(str1)) + len( CustomUTF8.decode(str2)) i = i + 1
if __name__ == "__main__": #fixed header fixed = b"\x50" #variable header packet_id = b"\x05\x02" pubrec_reason_code = b"\x83" reason_string = b"\x1f" + CustomUTF8.encode("$sys/rcp") userProperty = b"\x26" + CustomUTF8.encode( "Munteanu_Letitia") + CustomUTF8.encode("Ioana") #properties properties = reason_string + userProperty property_length = VariableByte.encode(len(properties)) variableHeader = packet_id + pubrec_reason_code + property_length + properties length_of_variable_header = len(variableHeader) remainingLength = VariableByte.encode(length_of_variable_header) #print("RL:" + str(remainingLength)) data = fixed + remainingLength + variableHeader data = struct.pack("!{}s".format(len(data)), data) packet = PubrecPacket(data) packet.parseFixedHeader() packet.parseVariableHeader() print(packet.fixed) print(packet.variable)
def parseVariableHeader(self): variableHeader = self.data[self.fixed_size:] #pubcomp packed id packet_id_MSB, packet_id_LSB = struct.unpack("!2B", variableHeader[:2]) self.variable['packet_id'] = (packet_id_MSB << 8) + packet_id_LSB variableHeader = variableHeader[2:] #pubcomp reason code pubcomp_reason_code = struct.unpack("!B", variableHeader[:1])[0] self.variable['pubcomp_reason_code'] = pubcomp_reason_code if (self.fixed['remainingLength'] == 2): self.variable['pubcomp_reason_code'] = 0x00 variableHeader = variableHeader[1:] #properties can be omitted if the reason code is Success #3 bytes so far #in case if reason code isn't Success, properties can't be omitted properties = self.data[self.fixed_size + 3:] num = b"" for byte in properties: num += struct.pack("!B", byte) if byte < 0x80: break required = len(num) self.variable['propertyLength'] = struct.unpack( "!{}s".format(required), num)[0] #fac decode ca sa am prop length intr un int self.variable['propertyLength'] = VariableByte.decode( self.variable['propertyLength']) if (self.fixed['remainingLength'] < 4): self.variable['propertyLength'] = 0 else: self.variable['properties'] = {} self.variable['properties']['userProperty'] = {} self.variable_size = self.variable['propertyLength'] + 3 properties = properties[required:] i = 0 while i < self.variable['propertyLength']: if properties[i] == 0x1f: if 'reason_string' not in self.variable['properties'].keys( ): OFFSET_TO_READ_START = i + 1 OFFSET_TO_READ_END = i + 3 to_read = properties[ OFFSET_TO_READ_START:OFFSET_TO_READ_END] efective_length = struct.unpack("!H", to_read)[0] self.variable['properties'][ 'reason_string'] = CustomUTF8.decode( struct.unpack( "!{}s".format(2 + efective_length), properties[i + 1:i + 3 + efective_length])[0]) i = i + 2 + efective_length else: raise MQTTError( "Malformed Packet : reason string already exists") if properties[i] == 0x26: START = i + 1 END = i + 3 to_read = properties[START:END] str1size = struct.unpack("!H", to_read)[0] str1 = struct.unpack("!{}s".format(str1size + END - START), properties[START:END + str1size])[0] START_index = i + 3 + str1size END_index = i + 5 + str1size to_read2 = properties[START_index:END_index] str2size = struct.unpack("!H", to_read2)[0] str2 = struct.unpack( "!{}s".format(str2size + END_index - START_index), properties[START_index:END_index + str2size])[0] if CustomUTF8.decode(str1) not in self.variable[ 'properties']['userProperty'].keys(): self.variable['properties']['userProperty'][ CustomUTF8.decode(str1)] = [ CustomUTF8.decode(str2) ] else: self.variable['properties']['userProperty'][ CustomUTF8.decode(str1)].append( CustomUTF8.decode(str2)) i = i + 4 + len(CustomUTF8.decode(str1)) + len( CustomUTF8.decode(str2)) i = i + 1
def parseVariableHeader(self): variableHeader = self.data[self.fixed_size:] #pubrel packed id packet_id_MSB, packet_id_LSB = struct.unpack("!2b", variableHeader[:2]) self.variable['packet_id'] = (packet_id_MSB << 8) + packet_id_LSB print('packet_id: ' + str(self.variable['packet_id'])) variableHeader = variableHeader[2:] #pubrel reason code pubrec_reason_code = struct.unpack("!B", variableHeader[:1])[0] self.variable['pubrec_reason_code'] = pubrec_reason_code if (self.fixed['remainingLength'] == 2): self.variable['pubrec_reason_code'] = 0x00 print('pubrec_reason_code: ' + str(self.variable['pubrec_reason_code'])) variableHeader = variableHeader[1:] #properties can be omitted if the reason code is Success #3 bytes so far #in case if reason code isn't Success, properties can't be omitted properties = self.data[self.fixed_size + 3:] num = b"" for byte in properties: num += struct.pack("!B", byte) if byte < 0x80: break required = len(num) self.variable['propertyLength'] = struct.unpack( "!{}s".format(required), num)[0] #fac decode ca sa am prop length intr un int self.variable['propertyLength'] = VariableByte.decode( self.variable['propertyLength']) if (self.fixed['remainingLength'] < 4): self.variable['propertyLength'] = 0 else: self.variable['properties'] = {} self.variable['properties']['userProperty'] = {} self.variable_size = self.variable['propertyLength'] + 3 properties = properties[required:] i = 0 while i < self.variable['propertyLength']: if properties[i] == 0x1f: if 'reason_string' not in self.variable['properties'].keys( ): OFFSET_TO_READ_START = i + 1 OFFSET_TO_READ_END = i + 3 to_read = properties[ OFFSET_TO_READ_START: OFFSET_TO_READ_END] #octetii care arata lungimea #print("to read: " + str(to_read)) efective_length = struct.unpack( "!H", to_read )[0] #transf in nr => lungimea stringului meu de 2 bytes #print("efective_lentgh: " + str(efective_length)) self.variable['properties'][ 'reason_string'] = CustomUTF8.decode( struct.unpack( "!{}s".format(2 + efective_length), properties[i + 1:i + 3 + efective_length])[0]) i = i + 2 + efective_length else: raise MQTTError( "Malformed Packet : reason string already exists") if properties[i] == 0x26: OFFSET_TO_READ_1_START = i + 1 OFFSET_TO_READ_1_END = i + 3 to_read = properties[ OFFSET_TO_READ_1_START:OFFSET_TO_READ_1_END] str1size = struct.unpack("!H", to_read)[0] str1 = struct.unpack( "!{}s".format(str1size + OFFSET_TO_READ_1_END - OFFSET_TO_READ_1_START), properties[ OFFSET_TO_READ_1_START:OFFSET_TO_READ_1_END + str1size])[0] OFFSET_TO_READ_2_START = i + 3 + str1size OFFSET_TO_READ_2_END = i + 5 + str1size to_read2 = properties[ OFFSET_TO_READ_2_START:OFFSET_TO_READ_2_END] str2size = struct.unpack("!H", to_read2)[0] str2 = struct.unpack( "!{}s".format(str2size + OFFSET_TO_READ_2_END - OFFSET_TO_READ_2_START), properties[ OFFSET_TO_READ_2_START:OFFSET_TO_READ_2_END + str2size])[0] if CustomUTF8.decode(str1) not in self.variable[ 'properties']['userProperty'].keys(): self.variable['properties']['userProperty'][ CustomUTF8.decode(str1)] = [ CustomUTF8.decode(str2) ] else: self.variable['properties']['userProperty'][ CustomUTF8.decode(str1)].append( CustomUTF8.decode(str2)) i += 4 + len(CustomUTF8.decode(str1)) + len( CustomUTF8.decode(str2)) i = i + 1
def generatePacketData(ack_flags: bool, reason_code: int, properties: dict) -> bytes: data = b"\x20" if ack_flags: flags = b"\x01" else: flags = b"\x00" rc = struct.pack("!B", reason_code) props = b"" myProperties = list(properties.keys()) if 'SessionExpiryInterval' in myProperties: props += b"\x11" + \ struct.pack("!I", properties['SessionExpiryInterval']) myProperties.remove('SessionExpiryInterval') if 'ReceiveMaximum' in myProperties: props += b"\x21" + struct.pack("!H", properties['ReceiveMaximum']) myProperties.remove('ReceiveMaximum') if 'MaximumQoS' in myProperties: props += b"\x24" + struct.pack("!B", properties['MaximumQoS']) myProperties.remove('MaximumQoS') if 'RetainAvailable' in myProperties: props += b"\x25" + struct.pack("!B", properties['RetainAvailable']) myProperties.remove('RetainAvailable') if 'MaximumPacketSize' in myProperties: props += b"\x27" + struct.pack( "!I".properties['MaximumPacketSize']) myProperties.remove('MaximumPacketSize') if 'AssignedClientId' in myProperties: props += b"\x12" + CustomUTF8.encode( properties['AssignedClientId']) myProperties.remove('AssignedClientId') if 'TopicAliasMaximum' in myProperties: props += b"\x22" + struct.pack( "!H".properties['TopicAliasMaximum']) myProperties.remove('TopicAliasMaximum') if 'ReasonString' in myProperties: props += b"\x1F" + CustomUTF8.encode(properties['ReasonString']) myProperties.remove('ReasonString') if 'UserProperty' in myProperties: for key in properties['UserProperty'].keys(): for value in properties['UserProperty'][key]: props += b"\x26" + \ CustomUTF8.encode(key)+CustomUTF8.encode(value) myProperties.remove('UserProperty') if 'WildcardSubscriptionAvailable' in myProperties: props += b"\x28" + \ struct.pack("!B", properties['WildcardSubscriptionAvailable']) myProperties.remove('WildcardSubscriptionAvailable') if 'SubscriptionIdentifiersAvailable' in myProperties: props += b"\x29" + \ struct.pack( "!B", properties['SubscriptionIdentifiersAvailable']) myProperties.remove('SubscriptionIdentifiersAvailable') if 'SharedSubscriptionAvailable' in myProperties: props += b"\x2A" + \ struct.pack("!B", properties['SharedSubscriptionAvailable']) myProperties.remove('SharedSubscriptionAvailable') if 'ServerKeepAlive' in myProperties: props += b"\x13" + struct.pack("!H", properties['ServerKeepAlive']) myProperties.remove('ServerKeepAlive') if 'ResponseInformation' in myProperties: props += b"\x1A" + \ CustomUTF8.encode(properties['ResponseInformation']) myProperties.remove('ResponseInformation') if 'ServerReference' in myProperties: props += b"\x1C" + CustomUTF8.encode(properties['ServerReference']) myProperties.remove('ServerReference') if 'AuthenticationMethod' in myProperties: props += b"\x15" + \ CustomUTF8.encode(properties['AuthenticationMethod']) myProperties.remove('AuthenticationMethod') if 'AuthenticationData' in myProperties: props += b"\x16" + \ BinaryData.fromBytesToBinary(properties['AuthenticationData']) myProperties.remove('AuthenticationData') if myProperties != []: raise ValueError("Unknown property was not parsed") propertyLength = VariableByte.encode(len(props)) # 1 pentru flags si 1 pentru rc remainingLength = VariableByte.encode(2 + len(propertyLength) + len(props)) # len(propertyLength) pare stupid, dar e necesar # propertyLength e format ca variable Byte si face parte din continutul pachetului. data += remainingLength + flags + rc + propertyLength + props return data
def parseVariableHeader(self) -> None: variableHeader = self.data[self.fixed_size:] offset, self.variable['name'] = readCustomUTF8String(variableHeader) self.variable['length']=offset-2 variableHeader = variableHeader[offset:] protocol_version = struct.unpack("!B", variableHeader[:1])[0] self.variable['protocolVersion'] = protocol_version variableHeader = variableHeader[1:] connectFlags = struct.unpack("!B", variableHeader[:1])[0] self.variable['usernameFlag'] = (connectFlags & 128 == 128) self.variable['passwordFlag'] = (connectFlags & 64 == 64) self.variable['willRetain'] = (connectFlags & 32 == 32) self.variable['willQoS'] = connectFlags & 24 # 16+8 self.variable['willFlag'] = (connectFlags & 4 == 4) self.variable['cleanStart'] = (connectFlags & 2 == 2) reserved = (connectFlags & 1 == 1) if reserved: raise MQTTError("Not reserved") variableHeader = variableHeader[1:] keep_alive_msb, keep_alive_lsb = struct.unpack( "!2B", variableHeader[:2]) self.variable['KeepAlive'] = (keep_alive_msb << 8)+keep_alive_lsb # 10 bytes is the common variable header, without properties properties = self.data[10+self.fixed_size:] num = b"" for byte in properties: num += struct.pack("!B", byte) if byte < 0x80: break required = len(num) self.variable['propertyLength'] = struct.unpack( "!{}s".format(required), num)[0] self.variable['propertyLength'] = VariableByte.decode( self.variable['propertyLength']) self.variable['properties'] = {} self.variable['properties']['requestResponseInformation'] = 1 self.variable['properties']['userProperty'] = {} self.variable_size = self.variable['propertyLength']+10 properties = properties[required:] i = 0 while i < self.variable['propertyLength']: if properties[i] == 0x11: if 'sessionExpiry' not in self.variable['properties'].keys(): self.variable['properties']['sessionExpiry'] = struct.unpack( "!I", properties[i+1:i+5])[0] i += 4 else: raise MQTTError( "Malformed Packet : sessionExpiry already exists") if properties[i] == 0x21: if 'receiveMaximum' not in self.variable['properties'].keys(): self.variable['properties']['receiveMaximum'] = struct.unpack( "!H", properties[i+1:i+3])[0] if self.variable['properties']['receiveMaximum'] == 0: raise MQTTError( "Malformed Packet : sessionExpiry is set to 0") i += 2 else: raise MQTTError( "Malformed Packet : receiveMaximum already exists") if properties[i] == 0x27: if 'maximumPacketSize' not in self.variable['properties'].keys(): self.variable['properties']['maximumPacketSize'] = struct.unpack( "!I", properties[i+1:i+5])[0] if self.variable['properties']['maximumPacketSize'] == 0: raise MQTTError( "Malformed Packet : sessionExpiry is set to 0") i += 4 else: raise MQTTError( "Malformed Packet : sessionExpiry already exists") if properties[i] == 0x22: if 'topicAliasMaximum' not in self.variable['properties'].keys(): self.variable['properties']['topicAliasMaximum'] = struct.unpack( "!H", properties[i+1:i+3])[0] else: raise MQTTError( "Malformed Packet : topicAliasMaximum already exists") i += 2 if properties[i] == 0x19: if 'requestResponseInformation' not in self.variable['properties'].keys(): self.variable['properties']['requestResponseInformation'] = struct.unpack( "!B", properties[i+1:i+2])[0] if self.variable['properties']['requestResponseInformation'] not in [0, 1]: raise MQTTError( "Malformed Packet : requestResponseInformation is not 0 or 1") else: raise MQTTError( "Malformed Packet : requestResponseInformation already exists") if properties[i] == 0x17: if 'requestProblemInformation' not in self.variable['properties'].keys(): self.variable['properties']['requestProblemInformation'] = struct.unpack( "!B", properties[i+1:i+2])[0] if self.variable['properties']['requestProblemInformation'] not in [0, 1]: raise MQTTError( "Malformed Packet : requestProblemInformation is not in 0 or 1") else: raise MQTTError( "Malformed Packet : requestProblemInformation already exists") if properties[i] == 0x26: offset1, str1 = readCustomUTF8String(properties[i+1:]) offset2, str2 = readCustomUTF8String(properties[i+1+offset1:]) if str1 not in self.variable['properties']['userProperty'].keys(): self.variable['properties']['userProperty'][str1] = [str2] else: self.variable['properties']['userProperty'][str1].append(str2) i += offset1+offset2 if properties[i] == 0x15: if 'authMethod' not in self.variable['properties'].keys(): offset, self.variable['properties']['authMethod'] = readCustomUTF8String(properties[i+1:]) i += 2+len(self.variable['properties']['authMethod']) else: raise MQTTError( "Malformed Packet : authMethod already exists") if properties[i] == 0x16: if 'authData' not in self.variable['properties'].keys(): offset, self.variable['properties']['authData']=readBinaryData(properties[i+1:]) i += offset else: raise MQTTError( "Malformed Packet : authentication data already exists") i = i+1 if 'sessionExpiry' not in self.variable['properties'].keys(): self.variable['properties']['sessionExpiry'] = 0 if 'receiveMaximum' not in self.variable['properties'].keys(): self.variable['properties']['receiveMaximum'] = 65535 if 'topicAliasMaximum' not in self.variable['properties'].keys(): self.variable['properties']['topicAliasMaximum'] = 0 if 'requestResponseInformation' not in self.variable['properties'].keys(): self.variable['properties']['requestResponseInformation'] = 0 if 'requestProblemInformation' not in self.variable['properties'].keys(): self.variable['properties']['requestProblemInformation'] = 1
def parsePayloadHeader(self): offset = self.fixed_size+self.variable_size+1 self.payload_size = self.fixed['remainingLength']-self.variable_size payloadHeader = self.data[offset:] offset, self.payload['clientID'] = readCustomUTF8String(payloadHeader) payloadHeader=payloadHeader[offset:] if self.variable['willFlag']: self.payload['willProperties'] = {} self.payload['willProperties']['userProperty'] = {} num = b"" for byte in payloadHeader: num += struct.pack("!B", byte) if byte < 0x80: break self.payload['willProperties']['willLength'] = VariableByte.decode( num) i = 0 payloadHeader = payloadHeader[len(num):] while i < self.payload['willProperties']['willLength']: if payloadHeader[i] == 0x18: if 'willDelayInterval' not in self.payload['willProperties'].keys(): self.payload['willProperties']['willDelayInterval'] = struct.unpack( "!I", payloadHeader[i+1:i+5])[0] else: raise MQTTError( "Malformed Packet : willDelay already exists") i += 4 elif payloadHeader[i] == 0x01: if 'payloadFormatIndicator' not in self.payload['willProperties'].keys(): self.payload['willProperties']['payloadFormatIndicator'] = struct.unpack( "!B", payloadHeader[i+1:i+2])[0] if self.payload['willProperties']['payloadFormatIndicator'] not in [0, 1]: raise MQTTError("Malformed Packet : payloadFormatIndicator not in 0 or 1") else: raise MQTTError( "Malformed Packet : payloadFormatIndicator already exists") i += 1 elif payloadHeader[i] == 0x02: if 'messageExpiryInterval' not in self.payload['willProperties'].keys(): self.payload['willProperties']['messageExpiryInterval'] = ( True, struct.unpack("!I", payloadHeader[i+1:i+5])[0]) else: raise MQTTError( "Malformed Packet : messageExpiryInterval already exists") i += 4 elif payloadHeader[i] == 0x03: if 'contentType' not in self.payload['willProperties'].keys(): offset, self.payload['willProperties']['contentType'] = readCustomUTF8String(payloadHeader[i+1:]) else: raise MQTTError( "Malformed Packet : contentType already exists") i += offset elif payloadHeader[i] == 0x08: if 'responseTopic' not in self.payload['willProperties'].keys(): offset, self.payload['willProperties']['responseTopic'] = readCustomUTF8String(payloadHeader[i+1:]) else: raise MQTTError( "Malformed Packet : responseTopic already exists") i += offset elif payloadHeader[i] == 0x09: if 'correlationData' not in self.payload['willProperties'].keys(): length = struct.unpack("!H", payloadHeader[i+1:i+3])[0] self.payload['willProperties']['correlationData'] = payloadHeader[i+1:i+3+length] else: raise MQTTError("Malformed Packet : correlationData already exists") i += 2+length elif payloadHeader[i] == 0x26: offset1, str1 = readCustomUTF8String(payloadHeader[i+1:]) offset2, str2 = readCustomUTF8String(payloadHeader[i+1+offset1:]) if str1 not in self.payload['willProperties']['userProperty'].keys(): self.payload['willProperties']['userProperty'][str1] = [str2] else: self.payload['willProperties']['userProperty'][str1].append(str2) i += offset1+offset2 i += 1 if 'willDelayInterval' not in self.payload['willProperties'].keys(): self.payload['willProperties']['willDelayInterval'] = 0 if 'payloadFormatIndicator' not in self.payload['willProperties'].keys(): self.payload['willProperties']['payloadFormatIndicator'] = 0 if 'messageExpiryInterval' not in self.payload['willProperties'].keys(): self.payload['willProperties']['messageExpiryInterval'] = (False, 0) offset, self.payload['willTopic']=readCustomUTF8String(payloadHeader[self.payload['willProperties']['willLength']:]) payloadHeader=payloadHeader[offset+self.payload['willProperties']['willLength']:] offset, self.payload['willPayload']=readBinaryData(payloadHeader) payloadHeader=payloadHeader[offset:] if self.variable['usernameFlag']: offset, self.payload['username']=readCustomUTF8String(payloadHeader) payloadHeader=payloadHeader[offset:] if self.variable['passwordFlag']: offset, self.payload['password']=readBinaryData(payloadHeader) payloadHeader=payloadHeader[offset:]
if __name__ == "__main__": clientID = CustomUTF8.encode("r3allyrandomid") willDelay = struct.pack("!I", 35) payloadFormatIndicator = b"\x01\x01" messageExpiryInterval = b"\x02"+struct.pack("!I", 32) willTopic = CustomUTF8.encode("pc/temp") willPayload = CustomUTF8.encode("this is a test message to be sent as a will payload and be submitted as key-value pair") correlationData = b"\x09"+b"\x00\x02\x04\x08" contentType = b"\x03"+CustomUTF8.encode("application/x-pdf") responseTopic = b"\x08"+CustomUTF8.encode("my response topic") userProperties = b"\x26"+CustomUTF8.encode("salut_din_will")+CustomUTF8.encode("dev") will = b"\x18"+willDelay+ payloadFormatIndicator + messageExpiryInterval+userProperties+contentType+ correlationData willLength = VariableByte.encode(len(will)) username = CustomUTF8.encode("admin") password = CustomUTF8.encode("password") otherProps = willTopic+willPayload+username+password variableContents = b"\x00\x04MQTT\x05\xfe\x01\xff" properties = b"\x11\x00\x00\x00\x02\x21\x00\x02\x26"+CustomUTF8.encode("salut")+CustomUTF8.encode("Emil")+b"\x26"+CustomUTF8.encode("salut")+CustomUTF8.encode("bunaziua")+b"\x26"+CustomUTF8.encode( "hello")+CustomUTF8.encode("welcome")+b"\x15"+CustomUTF8.encode("userpass")+b"\x16\x00\x04\x02\x03\x04\x05"+b"\x26"+CustomUTF8.encode("salut")+CustomUTF8.encode("Andrei") propertyLength = VariableByte.encode(len(properties)) byte_data = b"\x10"+VariableByte.encode( len(variableContents+propertyLength+properties+clientID+willLength+will+otherProps)) packetContents = byte_data+variableContents + \ propertyLength+properties+clientID+willLength+will + otherProps data = struct.pack("!{}s".format(len(packetContents)), packetContents) packet = ConnectPacket(data) print(data)