def unsubscribe(self, aClientid, aTopic): rc = [] matchedAny = False if type(aTopic) == type([]): if len(aTopic) > 1: logger.info( "[MQTT-3.10.4-6] each topic must be processed in sequence") for t in aTopic: matched = self.__unsubscribe(aClientid, t) rc.append( MQTTV5.ReasonCodes(MQTTV5.PacketTypes.UNSUBACK, "Success") if matched else MQTTV5.ReasonCodes( MQTTV5.PacketTypes.UNSUBACK, "No subscription found")) if not matchedAny: matchedAny = matched else: matchedAny = self.__unsubscribe(aClientid, aTopic) rc.append( ReasonCodes(UNSUBACK, "Success") if matched else ReasonCodes( UNSUBACK, "No subscription found")) if not matchedAny: logger.info( "[MQTT-3.10.4-5] Unsuback must be sent even if no topics are matched" ) return rc
def handleRequest(self, sock): "this is going to be called from multiple threads, so synchronize" self.lock.acquire() sendWillMessage = False try: try: raw_packet = MQTTV5.getPacket(sock) except: raise MQTTV5.MQTTException("[MQTT-4.8.0-1] 'transient error' reading packet, closing connection") if raw_packet == None: # will message if sock in self.clients.keys(): self.disconnect(sock, None, sendWillMessage=True) terminate = True else: try: packet = MQTTV5.unpackPacket(raw_packet, self.maximumPacketSize) if packet: terminate = self.handlePacket(packet, sock) else: self.disconnect(sock, reasonCode="Malformed packet", sendWillMessage=True) terminate = True except MQTTV5.MalformedPacket as error: disconnect_properties = MQTTV5.Properties(MQTTV5.PacketTypes.DISCONNECT) disconnect_properties.ReasonString = error.args[0] self.disconnect(sock, reasonCode="Malformed packet", sendWillMessage=True) terminate = True except MQTTV5.ProtocolError as error: disconnect_properties = MQTTV5.Properties(MQTTV5.PacketTypes.DISCONNECT) disconnect_properties.ReasonString = error.args[0] self.disconnect(sock, reasonCode=error.args[0], properties=disconnect_properties, sendWillMessage=True) terminate = True finally: self.lock.release() return terminate
def test_flow_control1(self): testcallback = Callbacks() # no callback means no background thread, to control receiving testclient = mqtt_client.Client("myclientid".encode("utf-8")) # set receive maximum - the number of concurrent QoS 1 and 2 messages clientReceiveMaximum = 2 # set to low number so we can test connect_properties = MQTTV5.Properties(MQTTV5.PacketTypes.CONNECT) connect_properties.ReceiveMaximum = clientReceiveMaximum connect_properties.SessionExpiryInterval = 0 connack = testclient.connect(host=host, port=port, cleanstart=True, properties=connect_properties) serverReceiveMaximum = 2**16-1 # the default if hasattr(connack.properties, "ReceiveMaximum"): serverReceiveMaximum = connack.properties.ReceiveMaximum receiver = testclient.getReceiver() testclient.subscribe([topics[0]], [MQTTV5.SubscribeOptions(2)]) receiver.receive(testcallback) self.waitfor(testcallback.subscribeds, 1, 3) pubs = 0 for i in range(1, clientReceiveMaximum + 2): testclient.publish(topics[0], "message %d" % i, 1) pubs += 1 # get two publishes acks = 0 while True: response1 = MQTTV5.unpackPacket(MQTTV5.getPacket(testclient.sock)) if response1.fh.PacketType == MQTTV5.PacketTypes.PUBLISH: break self.assertEqual(response1.fh.PacketType, MQTTV5.PacketTypes.PUBACK) acks += 1 del receiver.outMsgs[response1.packetIdentifier] self.assertEqual(response1.fh.PacketType, MQTTV5.PacketTypes.PUBLISH) self.assertEqual(response1.fh.QoS, 1, response1.fh.QoS) while True: response2 = MQTTV5.unpackPacket(MQTTV5.getPacket(testclient.sock)) if response2.fh.PacketType == MQTTV5.PacketTypes.PUBLISH: break self.assertEqual(response2.fh.PacketType, MQTTV5.PacketTypes.PUBACK) acks += 1 del receiver.outMsgs[response2.packetIdentifier] self.assertEqual(response2.fh.PacketType, MQTTV5.PacketTypes.PUBLISH) self.assertEqual(response2.fh.QoS, 1, response1.fh.QoS) while acks < pubs: ack = MQTTV5.unpackPacket(MQTTV5.getPacket(testclient.sock)) self.assertEqual(ack.fh.PacketType, MQTTV5.PacketTypes.PUBACK) acks += 1 del receiver.outMsgs[ack.packetIdentifier] with self.assertRaises(socket.timeout): # this should time out because we haven't acknowledged the first one response3 = MQTTV5.unpackPacket(MQTTV5.getPacket(testclient.sock)) # ack the first one puback = MQTTV5.Pubacks() puback.packetIdentifier = response1.packetIdentifier testclient.sock.send(puback.pack()) # now get the next packet response3 = MQTTV5.unpackPacket(MQTTV5.getPacket(testclient.sock)) self.assertEqual(response3.fh.PacketType, MQTTV5.PacketTypes.PUBLISH) self.assertEqual(response3.fh.QoS, 1, response1.fh.QoS) # ack the second one puback.packetIdentifier = response2.packetIdentifier testclient.sock.send(puback.pack()) # ack the third one puback.packetIdentifier = response3.packetIdentifier testclient.sock.send(puback.pack()) testclient.disconnect()