def connect2(self, host, port, newsocket,cleanstart, keepalive, protocolName,willFlag, willTopic, willMessage, willQoS, willRetain,properties, willProperties, username, password): if newsocket: try: self.sock.close() except: pass socket.setdefaulttimeout(5) self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.settimeout(5) self.sock.connect((host, port)) connect = MQTTV5.Connects() connect.ClientIdentifier = self.clientid connect.CleanStart = cleanstart connect.KeepAliveTimer = keepalive if protocolName: connect.ProtocolName = protocolName if willFlag: connect.WillFlag = True connect.WillTopic = willTopic connect.WillMessage = willMessage connect.WillQoS = willQoS connect.WillRETAIN = willRetain if willProperties: connect.WillProperties = willProperties if username: connect.usernameFlag = True connect.username = username if password: connect.passwordFlag = True connect.password = password if properties: connect.properties = properties sendtosocket(self.sock, connect.pack()) response = MQTTV5.unpackPacket(MQTTV5.getPacket(self.sock)) if not response: raise MQTTV5.MQTTException("connect failed - socket closed, no connack") assert response.fh.PacketType == MQTTV5.PacketTypes.CONNACK self.cleanstart = cleanstart # print("response =") # print(response) assert response.reasonCode.getName() == "Success", "connect was %s" % str(response) if self.cleanstart or self.__receiver == None: self.__receiver = internal.Receivers(self.sock) else: self.__receiver.socket = self.sock if self.callback: id = _thread.start_new_thread(self.__receiver, (self.callback,)) return response
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: traceback.print_exc() 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 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 handleRequest(self, sock): "this is going to be called from multiple threads, so synchronize" self.lock.acquire() raw_packet = None try: try: raw_packet = MQTTV5.getPacket(sock) except: pass # handled by raw_packet == None if raw_packet == None: logger.info( "[MQTT-4.8.0-1] 'transient error' reading packet, closing connection" ) # will message if sock in self.clients.keys(): self.disconnect(sock, None, sendWillMessage=True) terminate = True else: try: packet = MQTTV5.unpackPacket( raw_packet, self.options["maximumPacketSize"]) if self.options["visual"]: clientid = self.clients[ sock].id if sock in self.clients.keys() else "" if clientid == "" and hasattr(packet, "ClientIdentifier"): clientid = packet.ClientIdentifier try: data = { "direction": "CtoS", "socket": sock.fileno(), "clientid": clientid, "packet": packet.json() } databytes = bytes(json.dumps(data), 'utf-8') self.broker.publish('$internal', '$SYS/clients-packets', databytes, 0, 0, None, time.monotonic()) except: traceback.print_exc() if packet: terminate = self.handlePacket(packet, sock) else: self.disconnect(sock, reasonCode="Malformed packet", sendWillMessage=True) terminate = True except MQTTV5.MalformedPacket as error: traceback.print_exc() 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 receive(self, callback=None): packet = None try: packet = MQTTV5.unpackPacket(MQTTV5.getPacket(self.socket)) except: if not self.stopping and sys.exc_info()[0] != socket.timeout: logger.info("receive: unexpected exception %s", str(sys.exc_info())) #traceback.print_exc() raise if packet == None: time.sleep(0.1) return logger.debug("in :%s", str(packet)) if packet.fh.PacketType == MQTTV5.PacketTypes.SUBACK: if hasattr(callback, "subscribed"): callback.subscribed(packet.packetIdentifier, packet.reasonCodes) elif packet.fh.PacketType == MQTTV5.PacketTypes.DISCONNECT: if hasattr(callback, "disconnected"): callback.disconnected(packet.reasonCode, packet.properties) elif packet.fh.PacketType == MQTTV5.PacketTypes.UNSUBACK: if hasattr(callback, "unsubscribed"): callback.unsubscribed(packet.packetIdentifier) elif packet.fh.PacketType == MQTTV5.PacketTypes.PUBACK: "check if we are expecting a puback" if packet.packetIdentifier in self.outMsgs.keys() and \ self.outMsgs[packet.packetIdentifier].fh.QoS == 1: del self.outMsgs[packet.packetIdentifier] if hasattr(callback, "published"): callback.published(packet.packetIdentifier) else: raise Exception("No QoS 1 with that message id sent") elif packet.fh.PacketType == MQTTV5.PacketTypes.PUBREC: if packet.packetIdentifier in self.outMsgs.keys(): #self.outMsgs[packet.packetIdentifier].pubrec_received = True self.pubrel.packetIdentifier = packet.packetIdentifier logger.debug("out: %s", str(self.pubrel)) self.socket.send(self.pubrel.pack()) else: raise Exception("PUBREC received for unknown msg id "+ \ str(packet.packetIdentifier)) elif packet.fh.PacketType == MQTTV5.PacketTypes.PUBREL: "release QOS 2 publication to client, & send PUBCOMP" msgid = packet.packetIdentifier if packet.packetIdentifier not in self.inMsgs.keys(): pass # what should we do here? else: pub = self.inMsgs[packet.packetIdentifier] if callback == None or \ callback.publishArrived(pub.topicName, pub.data, 2, pub.fh.RETAIN, pub.packetIdentifier, pub.properties): del self.inMsgs[packet.packetIdentifier] self.pubcomp.packetIdentifier = packet.packetIdentifier logger.debug("out: %s", str(self.pubcomp)) self.socket.send(self.pubcomp.pack()) if callback == None: return (pub.topicName, pub.data, 2, pub.fh.RETAIN, pub.packetIdentifier) elif packet.fh.PacketType == MQTTV5.PacketTypes.PUBCOMP: "finished with this message id" if packet.packetIdentifier in self.outMsgs.keys(): del self.outMsgs[packet.packetIdentifier] if hasattr(callback, "published"): callback.published(packet.packetIdentifier) else: raise Exception("PUBCOMP received for unknown msg id "+ \ str(packet.packetIdentifier)) elif packet.fh.PacketType == MQTTV5.PacketTypes.PUBLISH: if self.paused: return if packet.fh.QoS == 0: if callback == None: return (packet.topicName, packet.data, 0, packet.fh.RETAIN, packet.packetIdentifier) else: callback.publishArrived(packet.topicName, packet.data, 0, packet.fh.RETAIN, packet.packetIdentifier, packet.properties) elif packet.fh.QoS == 1: if callback == None: return (packet.topicName, packet.data, 1, packet.fh.RETAIN, packet.packetIdentifier) else: if callback.publishArrived(packet.topicName, packet.data, 1, packet.fh.RETAIN, packet.packetIdentifier, packet.properties): self.puback.packetIdentifier = packet.packetIdentifier logger.debug("out: %s", str(self.puback)) self.socket.send(self.puback.pack()) elif packet.fh.QoS == 2: self.inMsgs[packet.packetIdentifier] = packet self.pubrec.packetIdentifier = packet.packetIdentifier logger.debug("out: %s", str(self.pubrec)) self.socket.send(self.pubrec.pack()) else: raise Exception("Unexpected packet" + str(packet))
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()
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()