def __call__(self, sockid): logger.debug("*** running") self.running = True packet = None try: while True: packet = MQTTV3.unpackPacket(MQTTV3.getPacket(state.sockets[sockid])) if packet == None: break if test: logger.debug("received result %s", (sockid, packet)) test.addResult((sockid, packet)) if packet.fh.MessageType == MQTTV3.CONNACK: self.packets.append(packet) else: mbt.observe((sockid, packet)) if packet.fh.MessageType == MQTTV3.PUBREC: mbt.execution.pools["pubrecs"].append(mbt.Choices((sockid, packet))) elif packet.fh.MessageType == MQTTV3.PUBLISH and packet.fh.QoS in [1, 2]: mbt.execution.pools["publishes"].append(mbt.Choices((sockid, packet))) elif packet.fh.MessageType == MQTTV3.PUBREL: mbt.execution.pools["pubrels"].append(mbt.Choices((sockid, packet))) elif packet.fh.MessageType == MQTTV3.CONNACK: self.packets.append(packet) except: if sys.exc_info()[0] != socket.error: logger.debug("unexpected exception %s", sys.exc_info()) #mbt.log(traceback.format_exc()) self.running = False logger.debug("*** stopping "+str(packet))
def publish(self, sock, packet): packet.receivedTime = time.monotonic() if packet.topicName.find("+") != -1 or packet.topicName.find( "#") != -1: raise MQTTV3.MQTTException( "[MQTT-3.3.2-2][MQTT-4.7.1-1] wildcards not allowed in topic name" ) if packet.fh.QoS == 0: self.broker.publish(self.clients[sock].id, packet.topicName, packet.data, packet.fh.QoS, packet.fh.RETAIN, 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" ) self.broker.publish(self.clients[sock].id, packet.topicName, packet.data, packet.fh.QoS, packet.fh.RETAIN, packet.receivedTime) resp = MQTTV3.Pubacks() logger.info("[MQTT-2.3.1-6] puback messge id same as publish") resp.messageIdentifier = packet.messageIdentifier respond(sock, resp) elif packet.fh.QoS == 2: myclient = self.clients[sock] if self.publish_on_pubrel: if packet.messageIdentifier 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.messageIdentifier) else: logger.info( "[MQTT-3.3.1-2] DUP flag is 1 on redelivery") else: myclient.inbound[packet.messageIdentifier] = packet else: if packet.messageIdentifier 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.messageIdentifier) else: logger.info( "[MQTT-3.3.1-2] DUP flag is 1 on redelivery") else: myclient.inbound.append(packet.messageIdentifier) 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.fh.RETAIN, packet.receivedTime) resp = MQTTV3.Pubrecs() logger.info("[MQTT-2.3.1-6] pubrec messge id same as publish") resp.messageIdentifier = packet.messageIdentifier respond(sock, resp)
def handleRequest(self, sock): "this is going to be called from multiple threads, so synchronize" self.lock.acquire() terminate = False try: try: raw_packet = MQTTV3.getPacket(sock) except: raise MQTTV3.MQTTException( "[MQTT-4.8.0-1] 'transient error' reading packet, closing connection" ) if raw_packet == None: # will message self.disconnect(sock, None, terminate=True) terminate = True else: packet = MQTTV3.unpackPacket(raw_packet) if packet: terminate = self.handlePacket(packet, sock) else: raise MQTTV3.MQTTException( "[MQTT-2.0.0-1] handleRequest: badly formed MQTT packet" ) finally: self.lock.release() return terminate
def isValidTopicName(aName): logger.info("[MQTT-4.7.3-1] all topic names and filters must be at least 1 char") if len(aName) < 1: raise MQTTV3.MQTTException("MQTT-4.7.3-1] all topic names and filters must be at least 1 char") return False logger.info("[MQTT-4.7.3-3] all topic names and filters must be <= 65535 bytes long") if len(aName) > 65535: raise MQTTV3.MQTTException("[MQTT-4.7.3-3] all topic names and filters must be <= 65535 bytes long") return False rc = True # '#' wildcard can be only at the end of a topic (used to be beginning as well) logger.info("[MQTT-4.7.1-2] # must be last, and next to /") if aName[0:-1].find('#') != -1: raise MQTTV3.MQTTException("[MQTT-4.7.1-2] # must be last, and next to /") rc = False logger.info("[MQTT-4.7.1-3] + can be used at any complete level") # '#' or '+' only next to a slash separator or end of name wilds = '#+' for c in wilds: pos = 0 pos = aName.find(c, pos) while pos != -1: if pos > 0: # check previous char is '/' if aName[pos-1] != '/': raise MQTTV3.MQTTException("[MQTT-4.7.1-3] + can be used at any complete level") rc = False if pos < len(aName)-1: # check that subsequent char is '/' if aName[pos+1] != '/': raise MQTTV3.MQTTException("[MQTT-4.7.1-3] + can be used at any complete level") rc = False pos = aName.find(c, pos+1) return rc
def puback(publish: "publishes"): sockid, publish = publish sock = state.sockets[sockid] if publish.fh.QoS == 1: puback = MQTTV3.Pubacks() puback.messageIdentifier = publish.messageIdentifier sock.send(puback.pack()) elif publish.fh.QoS == 2: pubrec = MQTTV3.Pubrecs() pubrec.messageIdentifier = publish.messageIdentifier sock.send(pubrec.pack())
def connect2(self, host, port, cleansession, keepalive, newsocket, protocolName, willFlag, willTopic, willMessage, willQoS, willRetain, username, password): if newsocket: try: self.sock.close() except: pass self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.settimeout(.5) self.sock.connect((host, port)) connect = MQTTV3.Connects() #mqtt login connect.ClientIdentifier = self.clientid connect.CleanSession = cleansession 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 username: connect.usernameFlag = True connect.username = username if password: connect.passwordFlag = True connect.password = password sendtosocket(self.sock, connect.pack()) response = MQTTV3.unpackPacket(MQTTV3.getPacket(self.sock)) if not response: raise MQTTV3.MQTTException( "connect failed - socket closed, no connack") assert response.fh.MessageType == MQTTV3.CONNACK self.cleansession = cleansession assert response.returnCode == 0, "connect was %s" % str(response) if self.cleansession 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 handle(self): global brokers, clients, options, break_connections, control_broker if not hasattr(self, "ids"): self.ids = {} if not hasattr(self, "versions"): self.versions = {} inbuf = True i = o = e = None try: clients = self.request brokers = socket.socket(socket.AF_INET, socket.SOCK_STREAM) brokers.connect((brokerhost, brokerport)) while inbuf != None: (i, o, e) = select.select([clients, brokers], [], []) for s in i: if s == clients: inbuf = MQTTV3.getPacket(clients) # get one packet if inbuf == None: break try: packet = MQTTV3.unpackPacket(inbuf) if packet.fh.MessageType == MQTTV3.CONNECT: self.ids[id(clients)] = packet.ClientIdentifier self.versions[id(clients)] = 3 logger.debug("C to S " + self.ids[id(clients)] + " " + repr(packet)) #logger.debug([hex(b) for b in inbuf]) #logger.debug(inbuf) except: traceback.print_exc() brokers.send(inbuf) # pass it on elif s == brokers: inbuf = MQTTV3.getPacket(brokers) # get one packet if inbuf == None: break try: logger.debug("S to C " + self.ids[id(clients)] + " " + repr(MQTTV3.unpackPacket(inbuf))) except: traceback.print_exc() clients.send(inbuf) if id(clients) in self.ids.keys(): logger.info("client " + self.ids[id(clients)] + " connection closing") except: #logger.debug(repr((i, o, e)) + " " + repr(inbuf)) traceback.print_exc() if id(clients) in self.ids.keys(): del self.ids[id(clients)] elif id(clients) in self.versions.keys(): del self.versions[id(clients)]
def __init__(self, socket): logging.debug("initializing receiver") self.socket = socket self.stopping = False self.paused = False self.inMsgs = {} self.outMsgs = {} self.puback = MQTTV3.Pubacks() self.pubrec = MQTTV3.Pubrecs() self.pubrel = MQTTV3.Pubrels() self.pubcomp = MQTTV3.Pubcomps() self.running = False
def connect(self, host="localhost", port=1883, cleansession=True, keepalive=0, newsocket=True, protocolName=None, willFlag=False, willTopic=None, willMessage=None, willQoS=2, willRetain=False, username=None, password=None): if newsocket: try: self.sock.close() except: pass self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.settimeout(.5) self.sock.connect((host, port)) connect = MQTTV3.Connects() connect.ClientIdentifier = self.clientid connect.CleanSession = cleansession 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 username: connect.usernameFlag = True connect.username = username if password: connect.passwordFlag = True connect.password = password sendtosocket(self.sock, connect.pack()) response = MQTTV3.unpackPacket(MQTTV3.getPacket(self.sock)) if not response: raise MQTTV3.MQTTException("connect failed - socket closed, no connack") assert response.fh.MessageType == MQTTV3.CONNACK self.cleansession = cleansession assert response.returnCode == 0, "connect was %s" % str(response) if self.cleansession 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 handle(self): global brokers, clients, options, break_connections, control_broker if not hasattr(self, "ids"): self.ids = {} if not hasattr(self, "versions"): self.versions = {} inbuf = True i = o = e = None try: clients = self.request brokers = socket.socket(socket.AF_INET, socket.SOCK_STREAM) brokers.connect((brokerhost, brokerport)) while inbuf != None: (i, o, e) = select.select([clients, brokers], [], []) for s in i: if s == clients: inbuf = MQTTV3.getPacket(clients) # get one packet if inbuf == None: break try: packet = MQTTV3.unpackPacket(inbuf) if packet.fh.MessageType == MQTTV3.CONNECT: self.ids[id(clients)] = packet.ClientIdentifier self.versions[id(clients)] = 3 logger.debug("C to S "+self.ids[id(clients)]+" "+repr(packet)) #logger.debug([hex(b) for b in inbuf]) #logger.debug(inbuf) except: traceback.print_exc() brokers.send(inbuf) # pass it on elif s == brokers: inbuf = MQTTV3.getPacket(brokers) # get one packet if inbuf == None: break try: logger.debug("S to C "+self.ids[id(clients)]+" "+repr(MQTTV3.unpackPacket(inbuf))) except: traceback.print_exc() clients.send(inbuf) if id(clients) in self.ids.keys(): logger.info("client "+self.ids[id(clients)]+" connection closing") except: #logger.debug(repr((i, o, e)) + " " + repr(inbuf)) traceback.print_exc() if id(clients) in self.ids.keys(): del self.ids[id(clients)] elif id(clients) in self.versions.keys(): del self.versions[id(clients)]
def subscribe(self, sock, packet): topics = [] qoss = [] respqoss = [] for p in packet.data: if p[0] == "test/nosubscribe": respqoss.append(0x80) else: if p[0] == "test/QoS 1 only": respqoss.append(min(1), p[1]) elif p[0] == "test/QoS 0 only": respqoss.append(min(0), p[1]) else: respqoss.append(p[1]) topics.append(p[0]) qoss.append(respqoss[-1]) if len(topics) > 0: self.broker.subscribe(self.clients[sock].id, topics, qoss) resp = MQTTV3.Subacks() logger.info( "[MQTT-2.3.1-7][MQTT-3.8.4-2] Suback has same message id as subscribe" ) logger.info("[MQTT-3.8.4-1] Must respond with suback") resp.messageIdentifier = packet.messageIdentifier logger.info( "[MQTT-3.8.4-5] return code must be returned for each topic in subscribe" ) logger.info( "[MQTT-3.9.3-1] the order of return codes must match order of topics in subscribe" ) resp.data = respqoss respond(sock, resp)
def disconnect(self): if self.__receiver: self.__receiver.stopping = True count = 0 while (len(self.__receiver.inMsgs) > 0 or len(self.__receiver.outMsgs) > 0) and self.__receiver.paused == False: logger.debug("disconnecting %s %s", self.__receiver.inMsgs, self.__receiver.outMsgs) time.sleep(.2) count += 1 if count == 20: break if self.__receiver and self.__receiver.paused == False: assert self.__receiver.inMsgs == {}, self.__receiver.inMsgs assert self.__receiver.outMsgs == {}, self.__receiver.outMsgs disconnect = MQTTV3.Disconnects() sendtosocket(self.sock, disconnect.pack()) time.sleep(0.1) if self.cleansession: self.__receiver = None else: self.__receiver.socket = None self.sock.close() if self.__receiver: while self.__receiver.running: time.sleep(0.1) self.__receiver.stopping = False
def publishArrived(self, topic, msg, qos, retained=False): pub = MQTTV3.Publishes() logger.info("[MQTT-3.2.3-3] topic name must match the subscription's topic filter") pub.topicName = topic pub.data = msg pub.fh.QoS = qos pub.fh.RETAIN = retained if retained: logger.info("[MQTT-2.1.2-7] Last retained message on matching topics sent on subscribe") if pub.fh.RETAIN: logger.info("[MQTT-2.1.2-9] Set retained flag on retained messages") if qos == 2: pub.qos2state = "PUBREC" if qos in [1, 2]: pub.messageIdentifier = self.msgid logger.debug("client id: %d msgid: %d", self.id, self.msgid) if self.msgid == 65535: self.msgid = 1 else: self.msgid += 1 self.outbound.append(pub) self.outmsgs[pub.messageIdentifier] = pub logger.info("[MQTT-4.6.0-6] publish packets must be sent in order of receipt from any given client") if self.connected: respond(self.socket, pub) else: if qos == 0 and not self.broker.dropQoS0: self.outbound.append(pub) if qos in [1, 2]: logger.info("[MQTT-3.1.2-5] storing of QoS 1 and 2 messages for disconnected client %s", self.id)
def unsubscribe(self, topics): unsubscribe = MQTTV3.Unsubscribes() unsubscribe.messageIdentifier = self.__nextMsgid() unsubscribe.data = topics a = unsubscribe.pack() sendtosocket(self.sock, unsubscribe.pack()) return unsubscribe.messageIdentifier
def connect( sockid: "socket", clientid: "clientids", cleansession: "boolean", #willmsg : "willmsgs", # username : "******", password : "******" ) -> "connackrc": sock = state.sockets[sockid] connect = MQTTV3.Connects() connect.ClientIdentifier = clientid connect.CleanSession = cleansession connect.KeepAliveTimer = 60 #if username: # connect.usernameFlag = True # connect.username = username #if password: # connect.passwordFlag = True # connect.password = password #if willmsg: # connect.willFlag = True # connect.WillQoS = 0 # connect.WillRETAIN = 0 # connect.WillTopic = None # UTF-8 # connect.WillMessage = None # binary sock.send(connect.pack()) time.sleep(0.5) checksocket(sockid) response = state.clientlist[sockid].packets.pop( 0) #MQTTV3.unpackPacket(MQTTV3.getPacket(sock)) logger.debug("+++connect response", response) if response == None or response.returnCode not in [0, 2]: raise Exception("Return code " + str(response.returnCode) + " in connack") return response.returnCode
def resend(self): logger.debug("resending unfinished publications %s", str(self.outbound)) if len(self.outbound) > 0: logger.info("[MQTT-4.4.0-1] resending inflight QoS 1 and 2 messages") for pub in self.outbound: logger.debug("resending", pub) logger.info("[MQTT-4.4.0-2] dup flag must be set on in re-publish") if pub.fh.QoS == 0: respond(self.socket, pub) elif pub.fh.QoS == 1: pub.fh.DUP = 1 logger.info("[MQTT-2.1.2-3] Dup when resending QoS 1 publish id %d", pub.messageIdentifier) logger.info("[MQTT-2.3.1-4] Message id same as original publish on resend") logger.info("[MQTT-4.3.2-1] Resending QoS 1 with DUP flag") respond(self.socket, pub) elif pub.fh.QoS == 2: if pub.qos2state == "PUBREC": logger.info("[MQTT-2.1.2-3] Dup when resending QoS 2 publish id %d", pub.messageIdentifier) pub.fh.DUP = 1 logger.info("[MQTT-2.3.1-4] Message id same as original publish on resend") logger.info("[MQTT-4.3.3-1] Resending QoS 2 with DUP flag") respond(self.socket, pub) else: resp = MQTTV3.Pubrels() logger.info("[MQTT-2.3.1-4] Message id same as original publish on resend") resp.messageIdentifier = pub.messageIdentifier respond(self.socket, resp)
def pubrec(self, sock, packet): "confirmed reception of qos 2" myclient = self.clients[sock] if myclient.pubrec(packet.messageIdentifier): logger.info("[MQTT-3.5.4-1] must reply with pubrel in response to pubrec") resp = MQTTV3.Pubrels() resp.messageIdentifier = packet.messageIdentifier respond(sock, resp)
def unsubscribe(sockid: "socket", packetid: "packetids", topics: "topicLists"): sock = state.sockets[sockid] unsubscribe = MQTTV3.Unsubscribes() unsubscribe.messageIdentifier = packetid unsubscribe.data = topics sock.send(unsubscribe.pack()) checksocket(sockid) return unsubscribe.messageIdentifier
def subscribe(self, topics, qoss): subscribe = MQTTV3.Subscribes() subscribe.messageIdentifier = self.__nextMsgid() count = 0 for t in topics: subscribe.data.append((t, qoss[count])) count += 1 sendtosocket(self.sock, subscribe.pack()) return subscribe.messageIdentifier
def unsubscribe(self, sock, packet): self.broker.unsubscribe(self.clients[sock].id, packet.data) resp = MQTTV3.Unsubacks() logger.info("[MQTT-2.3.1-7] Unsuback has same message id as unsubscribe") logger.info("[MQTT-3.10.4-4] Unsuback must be sent - same message id as unsubscribe") me = self.clients[sock] if len(me.outbound) > 0: logger.info("[MQTT-3.10.4-3] sending unsuback has no effect on outward inflight messages") resp.messageIdentifier = packet.messageIdentifier respond(sock, resp)
def publish(sockid : "socket", packetid : "packetids", topic : "topics", payload : "payloads", qos : "QoSs", retained : "boolean"): sock = state.sockets[sockid] publish = MQTTV3.Publishes() publish.fh.QoS = qos publish.fh.RETAIN = retained publish.messageIdentifier = packetid publish.topicName = topic publish.data = payload sock.send(publish.pack()) checksocket(sockid) return publish.messageIdentifier
def subscribe(sockid : "socket", packetid : "packetids", topics : "topicLists", qoss : "qosLists"): sock = state.sockets[sockid] subscribe = MQTTV3.Subscribes() subscribe.messageIdentifier = packetid count = 0 for t in topics: subscribe.data.append((t, qoss[count])) count += 1 sock.send(subscribe.pack()) checksocket(sockid) return subscribe.messageIdentifier
def pubrel(self, sock, packet): myclient = self.clients[sock] pub = myclient.pubrel(packet.messageIdentifier) if pub: if self.publish_on_pubrel: self.broker.publish(myclient.id, pub.topicName, pub.data, pub.fh.QoS, pub.fh.RETAIN) del myclient.inbound[packet.messageIdentifier] else: myclient.inbound.remove(packet.messageIdentifier) resp = MQTTV3.Pubcomps() logger.info("[MQTT-2.3.1-6] pubcomp messge id same as publish") resp.messageIdentifier = packet.messageIdentifier respond(sock, resp)
def handleRequest(self, sock): "this is going to be called from multiple threads, so synchronize" self.lock.acquire() terminate = False try: try: raw_packet = MQTTV3.getPacket(sock) except: raise MQTTV3.MQTTException("[MQTT-4.8.0-1] 'transient error' reading packet, closing connection") if raw_packet == None: # will message self.disconnect(sock, None, terminate=True) terminate = True else: packet = MQTTV3.unpackPacket(raw_packet) if packet: terminate = self.handlePacket(packet, sock) else: raise MQTTV3.MQTTException("[MQTT-2.0.0-1] handleRequest: badly formed MQTT packet") finally: self.lock.release() return terminate
def handlePacket(self, packet, sock): terminate = False logger.info("in: "+repr(packet)) if sock not in self.clients.keys() and packet.fh.MessageType != MQTTV3.CONNECT: self.disconnect(sock, packet) raise MQTTV3.MQTTException("[MQTT-3.1.0-1] Connect was not first packet on socket") else: getattr(self, MQTTV3.packetNames[packet.fh.MessageType].lower())(sock, packet) if sock in self.clients.keys(): self.clients[sock].lastPacket = time.time() if packet.fh.MessageType == MQTTV3.DISCONNECT: terminate = True return terminate
def publish(self, topic, payload, qos=0, retained=False): publish = MQTTV3.Publishes() publish.fh.QoS = qos publish.fh.RETAIN = retained if qos == 0: publish.messageIdentifier = 0 else: publish.messageIdentifier = self.__nextMsgid() if publish.fh.QoS == 2: publish.pubrec_received = False self.__receiver.outMsgs[publish.messageIdentifier] = publish publish.topicName = topic publish.data = payload sendtosocket(self.sock, publish.pack()) return publish.messageIdentifier
def handlePacket(self, packet, sock): terminate = False packet_string = str(packet) if len(packet_string) > 256: packet_string = packet_string[:255] + '...' + ( ' payload length:' + str(len(packet.data)) if hasattr(packet, "data") else "") logger.debug("in: (%d) %s", sock.fileno(), packet_string) if sock not in self.clients.keys( ) and packet.fh.MessageType != MQTTV3.CONNECT: self.disconnect(sock, packet) raise MQTTV3.MQTTException( "[MQTT-3.1.0-1] Connect was not first packet on socket") else: getattr(self, MQTTV3.packetNames[packet.fh.MessageType].lower())(sock, packet) if sock in self.clients.keys(): self.clients[sock].lastPacket = time.time() if packet.fh.MessageType == MQTTV3.DISCONNECT: terminate = True return terminate
def connect(self, sock, packet): if packet.ProtocolName != "MQTT": self.disconnect(sock, None) raise MQTTV3.MQTTException( "[MQTT-3.1.2-1] Wrong protocol name %s" % packet.ProtocolName) if packet.ProtocolVersion != 4: logger.error("[MQTT-3.1.2-2] Wrong protocol version %d", packet.ProtocolVersion) resp = MQTTV3.Connacks() resp.returnCode = 1 respond(sock, resp) logger.info( "[MQTT-3.2.2-5] must close connection after non-zero connack") self.disconnect(sock, None) logger.info( "[MQTT-3.1.4-5] When rejecting connect, no more data must be processed" ) return if sock in self.clients.keys(): # is socket is already connected? self.disconnect(sock, None) logger.info( "[MQTT-3.1.4-5] When rejecting connect, no more data must be processed" ) raise MQTTV3.MQTTException("[MQTT-3.1.0-2] Second connect packet") if len(packet.ClientIdentifier) == 0: if self.zero_length_clientids == False or packet.CleanSession == False: if self.zero_length_clientids: logger.info( "[MQTT-3.1.3-8] Reject 0-length clientid with cleansession false" ) logger.info( "[MQTT-3.1.3-9] if clientid is rejected, must send connack 2 and close connection" ) resp = MQTTV3.Connacks() resp.returnCode = 2 respond(sock, resp) logger.info( "[MQTT-3.2.2-5] must close connection after non-zero connack" ) self.disconnect(sock, None) logger.info( "[MQTT-3.1.4-5] When rejecting connect, no more data must be processed" ) return else: logger.info( "[MQTT-3.1.3-7] 0-length clientid must have cleansession true" ) packet.ClientIdentifier = uuid.uuid4( ) # give the client a unique clientid logger.info( "[MQTT-3.1.3-6] 0-length clientid must be assigned a unique id %s", packet.ClientIdentifier) logger.info( "[MQTT-3.1.3-5] Clientids of 1 to 23 chars and ascii alphanumeric must be allowed" ) if packet.ClientIdentifier in [ client.id for client in self.clients.values() ]: # is this client already connected on a different socket? for s in self.clients.keys(): if self.clients[s].id == packet.ClientIdentifier: logger.info("[MQTT-3.1.4-2] Disconnecting old client %s", packet.ClientIdentifier) self.disconnect(s, None) break me = None if not packet.CleanSession: me = self.broker.getClient( packet.ClientIdentifier ) # find existing state, if there is any if me: logger.info( "[MQTT-3.1.3-2] clientid used to retrieve client state") resp = MQTTV3.Connacks() resp.flags = 0x01 if me else 0x00 if me == None: me = MQTTClients(packet.ClientIdentifier, packet.CleanSession, packet.KeepAliveTimer, sock, self) else: me.socket = sock # set existing client state to new socket me.cleansession = packet.CleanSession me.keepalive = packet.KeepAliveTimer logger.info( "[MQTT-4.1.0-1] server must store data for at least as long as the network connection lasts" ) self.clients[sock] = me me.will = (packet.WillTopic, packet.WillQoS, packet.WillMessage, packet.WillRETAIN) if packet.WillFlag else None self.broker.connect(me) logger.info( "[MQTT-3.2.0-1] the first response to a client must be a connack") resp.returnCode = 0 respond(sock, resp) me.resend()
def handle(self): if not hasattr(self, "ids"): self.ids = {} if not hasattr(self, "versions"): self.versions = {} inbuf = True i = o = e = None try: clients = self.request brokers = socket.socket(socket.AF_INET, socket.SOCK_STREAM) brokers.connect((brokerhost, brokerport)) while inbuf != None: (i, o, e) = select.select([clients, brokers], [], []) for s in i: if s == clients: inbuf = MQTTV3.getPacket(clients) # get one packet if inbuf == None: break try: packet = MQTTV3.unpackPacket(inbuf) if ( packet.fh.MessageType == MQTTV3.PUBLISH and packet.topicName == "MQTTSAS topic" and packet.data == "TERMINATE" ): print("Terminating client", self.ids[id(clients)]) brokers.close() clients.close() break else: if packet.fh.MessageType == MQTTV3.CONNECT: self.ids[id(clients)] = packet.ClientIdentifier self.versions[id(clients)] = 3 wx.CallAfter(myWindow.log, timestamp(), "C to S", self.ids[id(clients)], repr(packet)) except: traceback.print_exc() # next line should not be needed once things work properly print("C to S", timestamp(), repr(inbuf)) sys.exit() # print "C to S", timestamp(), repr(inbuf) brokers.send(inbuf) # pass it on elif s == brokers: inbuf = MQTTV3.getPacket(brokers) # get one packet if inbuf == None: break try: wx.CallAfter( myWindow.log, timestamp(), "S to C", self.ids[id(clients)], repr(MQTTV3.unpackPacket(inbuf)), ) except: traceback.print_exc() # next line should not be needed once things work properly print("S to C", timestamp(), repr(inbuf)) sys.exit() # print "S to C", timestamp(), repr(inbuf) clients.send(inbuf) wx.CallAfter(myWindow.status, timestamp() + " client " + self.ids[id(clients)] + " connection closing") except: print(repr((i, o, e)), repr(inbuf)) traceback.print_exc() if self.ids.has_key(id(clients)): del self.ids[id(clients)] elif self.versions.has_key(id(clients)): del self.versions[id(clients)]
def pubrel(pubrec: "pubrecs"): # pubrecs are observable events sockid, pubrec = pubrec sock = state.sockets[sockid] pubrel = MQTTV3.Pubrels() pubrel.messageIdentifier = pubrec.messageIdentifier sock.send(pubrel.pack())
def pingreq(): pingreq = MQTTV3.Pingreqs() state.sockets[0].send(pingreq.pack())
def receive(self, callback=None): packet = None try: packet = MQTTV3.unpackPacket(MQTTV3.getPacket(self.socket)) except: if not self.stopping and sys.exc_info()[0] != socket.timeout: logging.error("receive: unexpected exception %s", str(sys.exc_info())) #traceback.print_exc() raise if packet == None: time.sleep(0.1) return logging.debug("in :%s", str(packet)) if packet.fh.MessageType == MQTTV3.SUBACK: if hasattr(callback, "subscribed"): callback.subscribed(packet.messageIdentifier, packet.data) elif packet.fh.MessageType == MQTTV3.UNSUBACK: if hasattr(callback, "unsubscribed"): callback.unsubscribed(packet.messageIdentifier) elif packet.fh.MessageType == MQTTV3.PUBACK: "check if we are expecting a puback" if packet.messageIdentifier in self.outMsgs.keys() and \ self.outMsgs[packet.messageIdentifier].fh.QoS == 1: del self.outMsgs[packet.messageIdentifier] if hasattr(callback, "published"): callback.published(packet.messageIdentifier) else: raise Exception("No QoS 1 with that message id sent") elif packet.fh.MessageType == MQTTV3.PUBREC: if packet.messageIdentifier in self.outMsgs.keys(): self.outMsgs[packet.messageIdentifier].pubrec_received == True self.pubrel.messageIdentifier = packet.messageIdentifier logging.debug("out: %s", str(self.pubrel)) self.socket.send(self.pubrel.pack()) else: raise Exception("PUBREC received for unknown msg id "+ \ str(packet.messageIdentifier)) elif packet.fh.MessageType == MQTTV3.PUBREL: "release QOS 2 publication to client, & send PUBCOMP" msgid = packet.messageIdentifier if packet.messageIdentifier not in self.inMsgs.keys(): pass # what should we do here? else: pub = self.inMsgs[packet.messageIdentifier] if callback == None or \ callback.publishArrived(pub.topicName, pub.data, 2, pub.fh.RETAIN, pub.messageIdentifier): del self.inMsgs[packet.messageIdentifier] self.pubcomp.messageIdentifier = packet.messageIdentifier logging.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.messageIdentifier) elif packet.fh.MessageType == MQTTV3.PUBCOMP: "finished with this message id" if packet.messageIdentifier in self.outMsgs.keys(): del self.outMsgs[packet.messageIdentifier] if hasattr(callback, "published"): callback.published(packet.messageIdentifier) else: raise Exception("PUBCOMP received for unknown msg id "+ \ str(packet.messageIdentifier)) elif packet.fh.MessageType == MQTTV3.PUBLISH: if self.paused: return if packet.fh.QoS == 0: if callback == None: return (packet.topicName, packet.data, 0, packet.fh.RETAIN, packet.messageIdentifier) else: callback.publishArrived(packet.topicName, packet.data, 0, packet.fh.RETAIN, packet.messageIdentifier) elif packet.fh.QoS == 1: if callback == None: return (packet.topicName, packet.data, 1, packet.fh.RETAIN, packet.messageIdentifier) else: if callback.publishArrived(packet.topicName, packet.data, 1, packet.fh.RETAIN, packet.messageIdentifier): self.puback.messageIdentifier = packet.messageIdentifier logging.debug("out: %s", str(self.puback)) self.socket.send(self.puback.pack()) elif packet.fh.QoS == 2: self.inMsgs[packet.messageIdentifier] = packet self.pubrec.messageIdentifier = packet.messageIdentifier logging.debug("out: %s", str(self.pubrec)) self.socket.send(self.pubrec.pack()) else: raise Exception("Unexpected packet" + str(packet))
def receive(self, callback=None): packet = None try: packet = MQTTV3.unpackPacket(MQTTV3.getPacket(self.socket)) except: if not self.stopping and sys.exc_info()[0] != socket.timeout: logging.error("receive: unexpected exception %s", str(sys.exc_info())) #traceback.print_exc() raise if packet == None: time.sleep(0.1) return logging.debug("in :%s", str(packet)) if packet.fh.MessageType == MQTTV3.SUBACK: if hasattr(callback, "subscribed"): callback.subscribed(packet.messageIdentifier, packet.data) elif packet.fh.MessageType == MQTTV3.UNSUBACK: if hasattr(callback, "unsubscribed"): callback.unsubscribed(packet.messageIdentifier) elif packet.fh.MessageType == MQTTV3.PUBACK: "check if we are expecting a puback" if packet.messageIdentifier in self.outMsgs.keys() and \ self.outMsgs[packet.messageIdentifier].fh.QoS == 1: del self.outMsgs[packet.messageIdentifier] if hasattr(callback, "published"): callback.published(packet.messageIdentifier) else: raise Exception("No QoS 1 with that message id sent") elif packet.fh.MessageType == MQTTV3.PUBREC: if packet.messageIdentifier in self.outMsgs.keys(): self.outMsgs[packet.messageIdentifier].pubrec_received == True self.pubrel.messageIdentifier = packet.messageIdentifier logging.debug("out: %s", str(self.pubrel)) self.socket.send(self.pubrel.pack()) else: raise Exception("PUBREC received for unknown msg id "+ \ str(packet.messageIdentifier)) elif packet.fh.MessageType == MQTTV3.PUBREL: "release QOS 2 publication to client, & send PUBCOMP" msgid = packet.messageIdentifier if packet.messageIdentifier not in self.inMsgs.keys(): pass # what should we do here? else: pub = self.inMsgs[packet.messageIdentifier] if callback == None or \ callback.publishArrived(pub.topicName, pub.data, 2, pub.fh.RETAIN, pub.messageIdentifier): del self.inMsgs[packet.messageIdentifier] self.pubcomp.messageIdentifier = packet.messageIdentifier logging.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.messageIdentifier) elif packet.fh.MessageType == MQTTV3.PUBCOMP: "finished with this message id" if packet.messageIdentifier in self.outMsgs.keys(): del self.outMsgs[packet.messageIdentifier] if hasattr(callback, "published"): callback.published(packet.messageIdentifier) else: raise Exception("PUBCOMP received for unknown msg id "+ \ str(packet.messageIdentifier)) elif packet.fh.MessageType == MQTTV3.PUBLISH: if self.paused: return if packet.fh.QoS == 0: if callback == None: return (packet.topicName, packet.data, 0, packet.fh.RETAIN, packet.messageIdentifier) else: callback.publishArrived(packet.topicName, packet.data, 0, packet.fh.RETAIN, packet.messageIdentifier) elif packet.fh.QoS == 1: if callback == None: return (packet.topicName, packet.data, 1, packet.fh.RETAIN, packet.messageIdentifier) else: if callback.publishArrived(packet.topicName, packet.data, 1, packet.fh.RETAIN, packet.messageIdentifier): self.puback.messageIdentifier = packet.messageIdentifier logging.debug("out: %s", str(self.puback)) self.socket.send(self.puback.pack()) elif packet.fh.QoS == 2: self.inMsgs[packet.messageIdentifier] = packet self.pubrec.messageIdentifier = packet.messageIdentifier logging.debug("out: %s", str(self.pubrec)) self.socket.send(self.pubrec.pack()) else: raise Exception("Unexpected packet"+str(packet))
def pingreq(self, sock, packet): resp = MQTTV3.Pingresps() logger.info("[MQTT-3.12.4-1] sending pingresp in response to pingreq") respond(sock, resp)
def pubcomp(pubrel: "pubrels"): sockid, pubrel = pubrel sock = state.sockets[sockid] pubcomp = MQTTV3.Pubcomps() pubcomp.messageIdentifier = pubrel.messageIdentifier sock.send(pubcomp.pack())