Beispiel #1
0
 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
Beispiel #2
0
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
Beispiel #3
0
 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)
Beispiel #4
0
    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 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
Beispiel #6
0
 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
Beispiel #7
0
 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()