def publish(self, sock, packet): packet.receivedTime = time.monotonic() if packet.topicName.find("+") != -1 or packet.topicName.find("#") != -1: raise ProtocolError("Topic name invalid %s" % packet.topicName) # Test Topic to disconnect the client if packet.topicName.startswith("cmd/"): self.handleBehaviourPublish(sock, packet.topicName, packet.data) else: if len(self.clients[sock].inbound) >= self.receiveMaximum: self.disconnect(sock, reasonCode="Receive maximum exceeded", sendWillMessage=True) elif packet.fh.QoS == 0: self.broker.publish(self.clients[sock].id, packet.topicName, packet.data, packet.fh.QoS, packet.properties, packet.receivedTime, packet.fh.RETAIN) elif packet.fh.QoS == 1: if packet.fh.DUP: logger.info("[MQTT-3.3.1-3] Incoming publish DUP 1 ==> outgoing publish with DUP 0") logger.info("[MQTT-4.3.2-2] server must store message in accordance with QoS 1") self.broker.publish(self.clients[sock].id, packet.topicName, packet.data, packet.fh.QoS, packet.properties, packet.receivedTime, packet.fh.RETAIN) resp = MQTTV5.Pubacks() logger.info("[MQTT-2.3.1-6] puback messge id same as publish") resp.packetIdentifier = packet.packetIdentifier respond(sock, resp) elif packet.fh.QoS == 2: myclient = self.clients[sock] if self.publish_on_pubrel: if packet.packetIdentifier in myclient.inbound.keys(): if packet.fh.DUP == 0: logger.error("[MQTT-3.3.1-2] duplicate QoS 2 message id %d found with DUP 0", packet.packetIdentifier) else: logger.info("[MQTT-3.3.1-2] DUP flag is 1 on redelivery") else: myclient.inbound[packet.packetIdentifier] = packet else: if packet.packetIdentifier in myclient.inbound: if packet.fh.DUP == 0: logger.error("[MQTT-3.3.1-2] duplicate QoS 2 message id %d found with DUP 0", packet.packetIdentifier) else: logger.info("[MQTT-3.3.1-2] DUP flag is 1 on redelivery") else: myclient.inbound.append(packet.packetIdentifier) logger.info("[MQTT-4.3.3-2] server must store message in accordance with QoS 2") self.broker.publish(myclient, packet.topicName, packet.data, packet.fh.QoS, packet.properties, packet.receivedTime, packet.fh.RETAIN) resp = MQTTV5.Pubrecs() logger.info("[MQTT-2.3.1-6] pubrec messge id same as publish") resp.packetIdentifier = packet.packetIdentifier respond(sock, resp)
def __init__(self, socket): logger.debug("initializing receiver") self.socket = socket self.stopping = False self.paused = False self.inMsgs = {} self.outMsgs = {} self.puback = MQTTV5.Pubacks() self.pubrec = MQTTV5.Pubrecs() self.pubrel = MQTTV5.Pubrels() self.pubcomp = MQTTV5.Pubcomps() self.running = False
def publish(self, sock, packet): packet.receivedTime = time.monotonic() if packet.topicName.find("+") != -1 or packet.topicName.find( "#") != -1: raise MQTTV5.AcksProtocolError("Topic name invalid %s" % packet.topicName) # Test Topic to disconnect the client if packet.topicName.startswith("cmd/"): self.handleBehaviourPublish(sock, packet.topicName, packet.data) else: if len(self.clients[sock].inbound ) >= self.options["receiveMaximum"]: self.disconnect(sock, reasonCode="Receive maximum exceeded", sendWillMessage=True) return if hasattr(packet.properties, "UserProperty") and len( packet.properties.UserProperty) > 1: logger.info( "[MQTT-3.1.3-10] Must maintain order of user properties") if packet.fh.QoS == 0: self.broker.publish(self.clients[sock].id, packet.topicName, packet.data, packet.fh.QoS, packet.fh.RETAIN, packet.properties, packet.receivedTime) elif packet.fh.QoS == 1: if packet.fh.DUP: logger.info( "[MQTT-3.3.1-3] Incoming publish DUP 1 ==> outgoing publish with DUP 0" ) logger.info( "[MQTT-4.3.2-2] server must store message in accordance with QoS 1" ) subscribers = self.broker.publish(self.clients[sock].id, packet.topicName, packet.data, packet.fh.QoS, packet.fh.RETAIN, packet.properties, packet.receivedTime) resp = MQTTV5.Pubacks() logger.info( "[MQTT5-2.2.1-5-puback] puback message id same as publish") resp.packetIdentifier = packet.packetIdentifier if subscribers == None: resp.reasonCode.set("No matching subscribers") if packet.topicName == "test_qos_1_2_errors": # specific error behaviour for testing resp.reasonCode.set("Not authorized") if hasattr(packet.properties, "UserProperty"): resp.properties.UserProperty = packet.properties.UserProperty respond(sock, resp) elif packet.fh.QoS == 2: myclient = self.clients[sock] subscribers = None if self.options["publish_on_pubrel"]: if packet.packetIdentifier in myclient.inbound.keys(): if packet.fh.DUP == 0: logger.error( "[MQTT-3.3.1-2] duplicate QoS 2 message id %d found with DUP 0", packet.packetIdentifier) else: logger.info( "[MQTT-3.3.1-2] DUP flag is 1 on redelivery") else: myclient.inbound[packet.packetIdentifier] = packet if len(packet.topicName) == 0 and hasattr( packet.properties, "TopicAlias"): packet.topicName = self.broker.getAliasTopic( self.clients[sock].id, packet.properties.TopicAlias) subscribers = self.broker.se.getSubscriptions( packet.topicName) else: if packet.packetIdentifier in myclient.inbound: if packet.fh.DUP == 0: logger.error( "[MQTT-3.3.1-2] duplicate QoS 2 message id %d found with DUP 0", packet.packetIdentifier) else: logger.info( "[MQTT-3.3.1-2] DUP flag is 1 on redelivery") else: myclient.inbound.append(packet.packetIdentifier) logger.info( "[MQTT-4.3.3-2] server must store message in accordance with QoS 2" ) if len(packet.topicName) == 0 and hasattr( packet.properties, "TopicAlias"): packet.topicName = self.broker.getAliasTopic( self.clients[sock].id, packet.properties.TopicAlias) subscribers = self.broker.publish( self.clients[sock].id, packet.topicName, packet.data, packet.fh.QoS, packet.fh.RETAIN, packet.properties, packet.receivedTime) if packet.topicName == "test_qos_1_2_errors_pubcomp": myclient.pubcomp_error = packet.packetIdentifier resp = MQTTV5.Pubrecs() logger.info( "[MQTT5-2.2.1-5-pubrec] pubrec message id same as publish") resp.packetIdentifier = packet.packetIdentifier if subscribers == None: resp.reasonCode.set("No matching subscribers") if hasattr(packet, "topicName" ) and packet.topicName == "test_qos_1_2_errors": resp.reasonCode.set("Not authorized") if self.options["publish_on_pubrel"]: del myclient.inbound[packet.packetIdentifier] else: myclient.inbound.remove(packet.packetIdentifier) if hasattr(packet.properties, "UserProperty"): resp.properties.UserProperty = packet.properties.UserProperty respond(sock, resp)
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()