def unsubscribe(self, aClientid, aTopic):
     rc = []
     matchedAny = False
     if type(aTopic) == type([]):
         if len(aTopic) > 1:
             logger.info(
                 "[MQTT-3.10.4-6] each topic must be processed in sequence")
         for t in aTopic:
             matched = self.__unsubscribe(aClientid, t)
             rc.append(
                 MQTTV5.ReasonCodes(MQTTV5.PacketTypes.UNSUBACK, "Success")
                 if matched else MQTTV5.ReasonCodes(
                     MQTTV5.PacketTypes.UNSUBACK, "No subscription found"))
             if not matchedAny:
                 matchedAny = matched
     else:
         matchedAny = self.__unsubscribe(aClientid, aTopic)
         rc.append(
             ReasonCodes(UNSUBACK, "Success") if matched else ReasonCodes(
                 UNSUBACK, "No subscription found"))
     if not matchedAny:
         logger.info(
             "[MQTT-3.10.4-5] Unsuback must be sent even if no topics are matched"
         )
     return rc
 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 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()