Exemple #1
0
 def handlePacket(self, packet, sock):
     terminate = False
     if hasattr(sock, "fileno"):
         packet_string = str(packet)
         if len(packet_string) > 256:
             packet_string = packet_string[0:256] + '...' + (
                 ' payload length:' +
                 str(len(packet.data)) if hasattr(packet, "data") else "")
         logger.debug("in: (%d) %s", sock.fileno(), packet_string)
     if self.mscfile != None:
         self.mscfile.write("client%d=>broker[label=%s];\n" %
                            (sock.fileno(), str(packet).split("(")[0]))
     if sock not in self.clients.keys(
     ) and packet.fh.PacketType != MQTTV5.PacketTypes.CONNECT:
         self.disconnect(sock, packet)
         raise MQTTV5.MQTTException(
             "[MQTT5-3.1.0-1-error] Connect was not first packet on socket")
     else:
         if packet.fh.PacketType == MQTTV5.PacketTypes.CONNECT:
             logger.info(
                 "[MQTT5-3.1.0-1] Connect must be first packet on socket")
         getattr(self,
                 MQTTV5.Packets.Names[packet.fh.PacketType].lower())(sock,
                                                                     packet)
         if sock in self.clients.keys():
             self.clients[sock].lastPacket = time.monotonic()
     if packet.fh.PacketType == MQTTV5.PacketTypes.DISCONNECT:
         terminate = True
     return terminate
Exemple #2
0
  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
Exemple #3
0
 def handlePacket(self, packet, sock):
   terminate = False
   logger.info("in: "+str(packet))
   if sock not in self.clients.keys() and packet.fh.PacketType != MQTTV5.PacketTypes.CONNECT:
     self.disconnect(sock, packet)
     raise MQTTV5.MQTTException("[MQTT-3.1.0-1] Connect was not first packet on socket")
   else:
     getattr(self, MQTTV5.Packets.Names[packet.fh.PacketType].lower())(sock, packet)
     if sock in self.clients.keys():
       self.clients[sock].lastPacket = time.monotonic()
   if packet.fh.PacketType == MQTTV5.PacketTypes.DISCONNECT:
     terminate = True
   return terminate
Exemple #4
0
 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
Exemple #5
0
 def connect(self, sock, packet):
   resp = MQTTV5.Connacks()
   if packet.ProtocolName != "MQTT":
     self.disconnect(sock, None)
     raise MQTTV5.MQTTException("[MQTT-3.1.2-1] Wrong protocol name %s" % packet.ProtocolName)
   if packet.ProtocolVersion != 5:
     logger.error("[MQTT-3.1.2-2] Wrong protocol version %d", packet.ProtocolVersion)
     resp.reasonCode.set("Unsupported protocol version")
     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 MQTTV5.MQTTException("[MQTT-3.1.0-2] Second connect packet")
   if len(packet.ClientIdentifier) == 0:
     if self.zero_length_clientids == False or packet.CleanStart == 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.reasonCode.set("Client identifier not valid")
       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 = str(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)
       resp.properties.AssignedClientIdentifier = 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 cursock in self.clients.keys():
       if self.clients[cursock].id == packet.ClientIdentifier:
         logger.info("[MQTT-3.1.4-2] Disconnecting old client %s", packet.ClientIdentifier)
         self.disconnect(cursock, None)
         break
   me = None
   clean = False
   if packet.CleanStart:
     clean = True
   else:
     me = self.broker.getClient(packet.ClientIdentifier) # find existing state, if there is any
     # has that state expired?
     if me and me.sessionExpiryInterval >= 0 and time.monotonic() - me.sessionEndedTime > me.sessionExpiryInterval:
       me = None
       clean = True
     if me:
       logger.info("[MQTT-3.1.3-2] clientid used to retrieve client state")
   resp.sessionPresent = True if me else False
   # Connack topic alias maximum for incoming client created topic aliases
   if self.topicAliasMaximum > 0:
     resp.properties.TopicAliasMaximum = self.topicAliasMaximum
   if self.maximumPacketSize < MQTTV5.MAX_PACKET_SIZE:
     resp.properties.MaximumPacketSize = self.maximumPacketSize
   if self.receiveMaximum < MQTTV5.MAX_PACKETID:
     resp.properties.ReceiveMaximum = self.receiveMaximum
   keepalive = packet.KeepAliveTimer
   if packet.KeepAliveTimer > 0 and self.serverKeepAlive < packet.KeepAliveTimer:
     keepalive = self.serverKeepAlive
     resp.properties.ServerKeepAlive = keepalive
   # Session expiry
   if hasattr(packet.properties, "SessionExpiryInterval"):
     sessionExpiryInterval = packet.properties.SessionExpiryInterval
   else:
     sessionExpiryInterval = -1 # no expiry
   if me == None:
     me = MQTTClients(packet.ClientIdentifier, packet.CleanStart, sessionExpiryInterval, keepalive, sock, self)
   else:
     me.socket = sock # set existing client state to new socket
     me.cleanStart = packet.CleanStart
     me.keepalive = keepalive
     me.sessionExpiryInterval = sessionExpiryInterval
   # the topic alias maximum in the connect properties sets the maximum outgoing topic aliases for a client
   me.topicAliasMaximum = packet.properties.TopicAliasMaximum if hasattr(packet.properties, "TopicAliasMaximum") else 0
   me.maximumPacketSize = packet.properties.MaximumPacketSize if hasattr(packet.properties, "MaximumPacketSize") else MQTTV5.MAX_PACKET_SIZE
   assert me.maximumPacketSize <= MQTTV5.MAX_PACKET_SIZE # is this the correct value?
   me.receiveMaximum = packet.properties.ReceiveMaximum if hasattr(packet.properties, "ReceiveMaximum") else MQTTV5.MAX_PACKETID
   assert me.receiveMaximum <= MQTTV5.MAX_PACKETID
   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, clean)
   logger.info("[MQTT-3.2.0-1] the first response to a client must be a connack")
   resp.reasonCode.set("Success")
   respond(sock, resp)
   me.resend()
Exemple #6
0
 def connect(self, sock, packet):
     resp = MQTTV5.Connacks()
     if packet.ProtocolName != "MQTT":
         self.disconnect(sock, None)
         raise MQTTV5.MQTTException(
             "[MQTT5-3.1.2-1-error] Wrong protocol name %s" %
             packet.ProtocolName)
     logger.info("[MQTT5-3.1.2-1] Protocol name must be MQTT")
     if packet.ProtocolVersion != 5:
         logger.error("[MQTT5-3.1.2-2-error] Wrong protocol version %d",
                      packet.ProtocolVersion)
         resp.reasonCode.set("Unsupported protocol version")
         respond(sock, resp)
         logger.info(
             "[MQTT5-3.2.2-6] must set session present to 0 with non-zero connack"
         )
         logger.info(
             "[MQTT5-3.2.2-7] must close connection after connack reason >= 0x80"
         )
         self.disconnect(sock, None)
         logger.info(
             "[MQTT5-3.1.4-6] When rejecting connect, no more data must be processed"
         )
         return
     logger.info("[MQTT5-3.1.2-2] Protocol version must be 5")
     if sock in self.clients.keys():  # is socket is already connected?
         self.disconnect(sock, None)
         logger.info(
             "[MQTT5-3.1.4-6] When rejecting connect, no more data must be processed"
         )
         raise MQTTV5.MQTTException("[MQTT5-3.1.0-2] Second connect packet")
     if len(packet.ClientIdentifier) == 0:
         packet.ClientIdentifier = str(
             uuid.uuid4())  # give the client a unique clientid
         logger.info(
             "[MQTT5-3.1.3-6] 0-length clientid must be assigned a unique id %s",
             packet.ClientIdentifier)
         resp.properties.AssignedClientIdentifier = packet.ClientIdentifier  # returns the assigned client id
         logger.info("[MQTT5-3.1.3-7] must return the assigned client id")
     else:
         logger.info(
             "[MQTT5-3.1.3-5] Clientids of 1 to 23 chars and ascii alphanumeric must be allowed"
         )
         if False:  # reject clientid test
             logger.info(
                 "[MQTT5-3.1.3-8] server rejects clientid - may return connack"
             )
     if packet.ClientIdentifier in [
             client.id for client in self.clients.values()
     ]:  # is this client already connected on a different socket?
         for cursock in self.clients.keys():
             if self.clients[cursock].id == packet.ClientIdentifier:
                 logger.info("[MQTT5-3.1.4-3] Disconnecting old client %s",
                             packet.ClientIdentifier)
                 self.disconnect(cursock, reasonCode="Session taken over")
                 break
     me = None
     clean = False
     if packet.CleanStart:
         logger.info(
             "[MQTT5-3.1.2-4] discard existing session when cleanstart set to 1"
         )
         logger.info(
             "[MQTT5-3.1.4-4] server must perform clean start processing")
         clean = True
         logger.info(
             "[MQTT5-3.2.2-2] session present must be set to 0 if cleanstart is 1"
         )
     else:
         me = self.broker.getClient(
             packet.ClientIdentifier
         )  # find existing state, if there is any
         if not me:
             logger.info(
                 "[MQTT5-3.1.2-6] no existing session and cleanstart set to 0"
             )
         # has that state expired?
         if me and me.sessionExpiryInterval >= 0 and time.monotonic(
         ) - me.sessionEndedTime > me.sessionExpiryInterval:
             me = None
             clean = True
         else:
             logger.info(
                 "[MQTT5-3.1.2-5] resume an existing session when cleanstart set to 0"
             )
         if me:
             logger.info(
                 "[MQTT5-3.1.3-2] clientid used to retrieve client state")
             logger.info("[MQTT5-3.2.2-3] session present must be set to 1")
     resp.sessionPresent = True if me else False
     # Connack topic alias maximum for incoming client created topic aliases
     if self.options["topicAliasMaximum"] > 0:
         resp.properties.TopicAliasMaximum = self.options[
             "topicAliasMaximum"]
     if self.options["maximumPacketSize"] < MQTTV5.MAX_PACKET_SIZE:
         resp.properties.MaximumPacketSize = self.options[
             "maximumPacketSize"]
     if self.options["receiveMaximum"] < MQTTV5.MAX_PACKETID:
         resp.properties.ReceiveMaximum = self.options["receiveMaximum"]
     keepalive = packet.KeepAliveTimer
     if packet.KeepAliveTimer > 0 and self.options[
             "serverKeepAlive"] < packet.KeepAliveTimer:
         keepalive = self.options["serverKeepAlive"]
         resp.properties.ServerKeepAlive = keepalive
         logger.info(
             "[MQTT5-3.1.2-21] client must use server keep alive if returned on connack"
         )
     # Session expiry
     if hasattr(packet.properties, "SessionExpiryInterval"):
         sessionExpiryInterval = packet.properties.SessionExpiryInterval
     else:
         sessionExpiryInterval = 0  # immediate expiry - change to spec
     # will delay
     willDelayInterval = 0
     if hasattr(packet.WillProperties, "WillDelayInterval"):
         willDelayInterval = packet.WillProperties.WillDelayInterval
         delattr(packet.WillProperties,
                 "WillDelayInterval")  # must not be sent with will message
     if willDelayInterval > sessionExpiryInterval:
         willDelayInterval = sessionExpiryInterval
     if me == None:
         me = MQTTClients(packet.ClientIdentifier, packet.CleanStart,
                          sessionExpiryInterval, willDelayInterval,
                          keepalive, sock, self)
     else:
         me.socket = sock  # set existing client state to new socket
         me.cleanStart = packet.CleanStart
         me.keepalive = keepalive
         me.sessionExpiryInterval = sessionExpiryInterval
         me.willDelayInterval = willDelayInterval
     if me.delayedWillTime:
         me.delayedWillTime = None
         logger.info(
             "[MQTT5-3.1.3-9] don't send delayed will if client connects in time"
         )
     if me.id in self.broker.willMessageClients:
         self.broker.willMessageClients.remove(me.id)
     # the topic alias maximum in the connect properties sets the maximum outgoing topic aliases for a client
     me.topicAliasMaximum = packet.properties.TopicAliasMaximum if hasattr(
         packet.properties, "TopicAliasMaximum") else 0
     me.maximumPacketSize = packet.properties.MaximumPacketSize if hasattr(
         packet.properties, "MaximumPacketSize") else MQTTV5.MAX_PACKET_SIZE
     assert me.maximumPacketSize <= MQTTV5.MAX_PACKET_SIZE  # is this the correct value?
     me.receiveMaximum = packet.properties.ReceiveMaximum if hasattr(
         packet.properties, "ReceiveMaximum") else MQTTV5.MAX_PACKETID
     assert me.receiveMaximum <= MQTTV5.MAX_PACKETID
     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,
                packet.WillProperties) if packet.WillFlag else None
     if me.will != None:
         logger.info(
             "[MQTT5-3.1.2-7] the will message must be stored if the WillFlag is set"
         )
     self.broker.connect(me, clean)
     logger.info(
         "[MQTT5-3.2.0-1] the first response to a client must be a connack")
     logger.info(
         "[MQTT5-3.1.4-5] the server must acknowledge the connect with a connack success"
     )
     resp.reasonCode.set("Success")
     respond(sock, resp)
     me.resend()