Example #1
0
 def _reader_coro(self):
     self.logger.debug("Starting reader coro")
     while self._running:
         try:
             self._reader_ready.set()
             fixed_header = yield from asyncio.wait_for(MQTTFixedHeader.from_stream(self.session.reader), 5)
             if fixed_header:
                 cls = packet_class(fixed_header)
                 packet = yield from cls.from_stream(self.session.reader, fixed_header=fixed_header)
                 self.logger.debug(" <-in-- " + repr(packet))
                 yield from self.incoming_queues[packet.fixed_header.packet_type].put(packet)
                 self.packet_received.send(packet)
             else:
                 self.logger.debug("No more data, stopping reader coro")
                 break
         except asyncio.TimeoutError:
             self.logger.debug("Input stream read timeout")
         except NoDataException as nde:
             self.logger.debug("No data available")
         except Exception as e:
             self.logger.warn("Unhandled exception in reader coro: %s" % e)
             break
     self.logger.debug("Reader coro stopped")
Example #2
0
    def _reader_loop(self):
        self.logger.debug("%s Starting reader coro" % self.session.client_id)
        running_tasks = collections.deque()
        keepalive_timeout = self.session.keep_alive
        if keepalive_timeout <= 0:
            keepalive_timeout = None
        while True:
            try:
                self._reader_ready.set()
                while running_tasks and running_tasks[0].done():
                    running_tasks.popleft()
                if len(running_tasks) > 1:
                    self.logger.debug("handler running tasks: %d" %
                                      len(running_tasks))

                fixed_header = yield from asyncio.wait_for(
                    MQTTFixedHeader.from_stream(self.reader),
                    keepalive_timeout,
                    loop=self._loop)
                if fixed_header:
                    if fixed_header.packet_type == RESERVED_0 or fixed_header.packet_type == RESERVED_15:
                        self.logger.warning(
                            "%s Received reserved packet, which is forbidden: closing connection"
                            % (self.session.client_id))
                        yield from self.handle_connection_closed()
                    else:
                        cls = packet_class(fixed_header)
                        packet = yield from cls.from_stream(
                            self.reader, fixed_header=fixed_header)
                        yield from self.plugins_manager.fire_event(
                            EVENT_MQTT_PACKET_RECEIVED,
                            packet=packet,
                            session=self.session)
                        task = None
                        if packet.fixed_header.packet_type == CONNACK:
                            task = asyncio.ensure_future(
                                self.handle_connack(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == SUBSCRIBE:
                            task = asyncio.ensure_future(
                                self.handle_subscribe(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == UNSUBSCRIBE:
                            task = asyncio.ensure_future(
                                self.handle_unsubscribe(packet),
                                loop=self._loop)
                        elif packet.fixed_header.packet_type == SUBACK:
                            task = asyncio.ensure_future(
                                self.handle_suback(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == UNSUBACK:
                            task = asyncio.ensure_future(
                                self.handle_unsuback(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == PUBACK:
                            task = asyncio.ensure_future(
                                self.handle_puback(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == PUBREC:
                            task = asyncio.ensure_future(
                                self.handle_pubrec(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == PUBREL:
                            task = asyncio.ensure_future(
                                self.handle_pubrel(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == PUBCOMP:
                            task = asyncio.ensure_future(
                                self.handle_pubcomp(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == PINGREQ:
                            task = asyncio.ensure_future(
                                self.handle_pingreq(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == PINGRESP:
                            task = asyncio.ensure_future(
                                self.handle_pingresp(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == PUBLISH:
                            task = asyncio.ensure_future(
                                self.handle_publish(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == DISCONNECT:
                            task = asyncio.ensure_future(
                                self.handle_disconnect(packet),
                                loop=self._loop)
                        elif packet.fixed_header.packet_type == CONNECT:
                            self.handle_connect(packet)
                        else:
                            self.logger.warning(
                                "%s Unhandled packet type: %s" %
                                (self.session.client_id,
                                 packet.fixed_header.packet_type))
                        if task:
                            running_tasks.append(task)
                else:
                    self.logger.debug(
                        "%s No more data (EOF received), stopping reader coro"
                        % self.session.client_id)
                    break
            except MQTTException:
                self.logger.debug("Message discarded")
            except asyncio.CancelledError:
                self.logger.debug("Task cancelled, reader loop ending")
                break
            except asyncio.TimeoutError:
                self.logger.debug("%s Input stream read timeout" %
                                  self.session.client_id)
                self.handle_read_timeout()
            except NoDataException:
                self.logger.debug("%s No data available" %
                                  self.session.client_id)
            except BaseException as e:
                self.logger.warning(
                    "%s Unhandled exception in reader coro: %r" %
                    (type(self).__name__, e))
                break
        while running_tasks:
            running_tasks.popleft().cancel()
        yield from self.handle_connection_closed()
        self._reader_stopped.set()
        self.logger.debug("%s Reader coro stopped" % self.session.client_id)
        yield from self.stop()
Example #3
0
    def _reader_loop(self):
        self.logger.debug("%s Starting reader coro" % self.session.client_id)
        running_tasks = collections.deque()
        keepalive_timeout = self.session.keep_alive
        if keepalive_timeout <= 0:
            keepalive_timeout = None
        while True:
            try:
                self._reader_ready.set()
                while running_tasks and running_tasks[0].done():
                    running_tasks.popleft()
                if len(running_tasks) > 1:
                    self.logger.debug("handler running tasks: %d" % len(running_tasks))

                fixed_header = yield from asyncio.wait_for(MQTTFixedHeader.from_stream(self.reader),
                    keepalive_timeout, loop=self._loop)
                if fixed_header:
                    if fixed_header.packet_type == RESERVED_0 or fixed_header.packet_type == RESERVED_15:
                        self.logger.warning("%s Received reserved packet, which is forbidden: closing connection" %
                                         (self.session.client_id))
                        yield from self.handle_connection_closed()
                    else:
                        cls = packet_class(fixed_header)
                        packet = yield from cls.from_stream(self.reader, fixed_header=fixed_header)
                        yield from self.plugins_manager.fire_event(
                            EVENT_MQTT_PACKET_RECEIVED, packet=packet, session=self.session)
                        task = None
                        if packet.fixed_header.packet_type == CONNACK:
                            task = ensure_future(self.handle_connack(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == SUBSCRIBE:
                            task = ensure_future(self.handle_subscribe(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == UNSUBSCRIBE:
                            task = ensure_future(self.handle_unsubscribe(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == SUBACK:
                            task = ensure_future(self.handle_suback(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == UNSUBACK:
                            task = ensure_future(self.handle_unsuback(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == PUBACK:
                            task = ensure_future(self.handle_puback(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == PUBREC:
                            task = ensure_future(self.handle_pubrec(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == PUBREL:
                            task = ensure_future(self.handle_pubrel(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == PUBCOMP:
                            task = ensure_future(self.handle_pubcomp(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == PINGREQ:
                            task = ensure_future(self.handle_pingreq(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == PINGRESP:
                            task = ensure_future(self.handle_pingresp(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == PUBLISH:
                            task = ensure_future(self.handle_publish(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == DISCONNECT:
                            task = ensure_future(self.handle_disconnect(packet), loop=self._loop)
                        elif packet.fixed_header.packet_type == CONNECT:
                            self.handle_connect(packet)
                        else:
                            self.logger.warning("%s Unhandled packet type: %s" %
                                             (self.session.client_id, packet.fixed_header.packet_type))
                        if task:
                            running_tasks.append(task)
                else:
                    self.logger.debug("%s No more data (EOF received), stopping reader coro" % self.session.client_id)
                    break
            except MQTTException:
                self.logger.debug("Message discarded")
            except asyncio.CancelledError:
                self.logger.debug("Task cancelled, reader loop ending")
                break
            except asyncio.TimeoutError:
                self.logger.debug("%s Input stream read timeout" % self.session.client_id)
                self.handle_read_timeout()
            except NoDataException:
                self.logger.debug("%s No data available" % self.session.client_id)
            except BaseException as e:
                self.logger.warning("%s Unhandled exception in reader coro: %r" % (type(self).__name__, e))
                break
        while running_tasks:
            running_tasks.popleft().cancel()
        yield from self.handle_connection_closed()
        self._reader_stopped.set()
        self.logger.debug("%s Reader coro stopped" % self.session.client_id)
        yield from self.stop()
Example #4
0
    async def _reader_loop(self):
        self.logger.debug("%s Starting reader coro", self.session.client_id)
        keepalive_timeout = self.session.keep_alive
        if keepalive_timeout <= 0:
            keepalive_timeout = None

        try:
            async with anyio.create_task_group() as tg:
                self._reader_task = tg
                while True:
                    try:
                        async with anyio.fail_after(keepalive_timeout):
                            fixed_header = await MQTTFixedHeader.from_stream(
                                self.stream)
                        if fixed_header is None:
                            self.logger.debug(
                                "%s No more data (EOF received), stopping reader coro",
                                self.session.client_id)
                            break

                        if fixed_header.packet_type == RESERVED_0 or fixed_header.packet_type == RESERVED_15:
                            self.logger.warning(
                                "%s Received reserved packet, which is forbidden: closing connection",
                                self.session.client_id)
                            await self.handle_connection_closed()
                            break
                        cls = packet_class(fixed_header)
                        packet = await cls.from_stream(
                            self.stream, fixed_header=fixed_header)
                        self.logger.debug(
                            "< %s %r",
                            'B' if 'Broker' in type(self).__name__ else 'C',
                            packet)
                        await self.plugins_manager.fire_event(
                            EVENT_MQTT_PACKET_RECEIVED,
                            packet=packet,
                            session=self.session)
                        try:
                            pt, direct = PACKET_TYPES[
                                packet.fixed_header.packet_type]
                            fn = getattr(self, 'handle_' + pt)
                        except (KeyError, AttributeError):
                            self.logger.warning(
                                "%s Unhandled packet type: %s",
                                self.session.client_id,
                                packet.fixed_header.packet_type)
                        else:
                            try:
                                if direct:
                                    await fn(packet)
                                else:
                                    await tg.spawn(fn, packet)
                            except StopAsyncIteration:
                                break

                    except MQTTException:
                        self.logger.debug("Message discarded")
                    except TimeoutError:
                        self.logger.debug(
                            "%s Input stream read timeout",
                            self.session.client_id if self.session else '?')
                        await self.handle_read_timeout()
                    except NoDataException:
                        self.logger.debug("%s No data available",
                                          self.session.client_id)
                        break  # XXX
                    except anyio.get_cancelled_exc_class():
                        self.logger.warning("%s CANCEL", type(self).__name__)
                        raise
                    except BaseException as e:
                        self.logger.warning(
                            "%s Unhandled exception in reader coro",
                            type(self).__name__,
                            exc_info=e)
                        raise
                await tg.cancel_scope.cancel()
        finally:
            async with anyio.open_cancel_scope(shield=True):
                self.logger.debug(
                    "%s %s coro stopped",
                    'Broker' if 'Broker' in type(self).__name__ else 'Client',
                    self.session.client_id if self.session else '?')
                await self._reader_stopped.set()
                if self._reader_task is not None:
                    self._reader_task = None
                    await self.handle_connection_closed()
Example #5
0
    def _reader_coro(self):
        self.logger.debug("%s Starting reader coro" % self.session.client_id)
        while self._running:
            try:
                self._reader_ready.set()
                keepalive_timeout = self.session.keep_alive
                if keepalive_timeout <= 0:
                    keepalive_timeout = None
                fixed_header = yield from asyncio.wait_for(MQTTFixedHeader.from_stream(self.reader), keepalive_timeout)
                if fixed_header:
                    if fixed_header.packet_type == RESERVED_0 or fixed_header.packet_type == RESERVED_15:
                        self.logger.warn("%s Received reserved packet, which is forbidden: closing connection" %
                                         (self.session.client_id))
                        yield from self.handle_connection_closed()
                    else:
                        cls = packet_class(fixed_header)
                        packet = yield from cls.from_stream(self.reader, fixed_header=fixed_header)
                        self.logger.debug("%s <-in-- %s" % (self.session.client_id, repr(packet)))
                        self._loop.call_soon(self.on_packet_received.send, packet)

                        task = None
                        if packet.fixed_header.packet_type == CONNACK:
                            task = asyncio.Task(self.handle_connack(packet))
                        elif packet.fixed_header.packet_type == SUBSCRIBE:
                            task =  asyncio.Task(self.handle_subscribe(packet))
                        elif packet.fixed_header.packet_type == UNSUBSCRIBE:
                            task = asyncio.Task(self.handle_unsubscribe(packet))
                        elif packet.fixed_header.packet_type == SUBACK:
                            task = asyncio.Task(self.handle_suback(packet))
                        elif packet.fixed_header.packet_type == UNSUBACK:
                            task = asyncio.Task(self.handle_unsuback(packet))
                        elif packet.fixed_header.packet_type == PUBACK:
                            task = asyncio.Task(self.handle_puback(packet))
                        elif packet.fixed_header.packet_type == PUBREC:
                            task = asyncio.Task(self.handle_pubrec(packet))
                        elif packet.fixed_header.packet_type == PUBREL:
                            task = asyncio.Task(self.handle_pubrel(packet))
                        elif packet.fixed_header.packet_type == PUBCOMP:
                            task = asyncio.Task(self.handle_pubcomp(packet))
                        elif packet.fixed_header.packet_type == PINGREQ:
                            task = asyncio.Task(self.handle_pingreq(packet))
                        elif packet.fixed_header.packet_type == PINGRESP:
                            task = asyncio.Task(self.handle_pingresp(packet))
                        elif packet.fixed_header.packet_type == PUBLISH:
                            task = asyncio.Task(self.handle_publish(packet))
                        elif packet.fixed_header.packet_type == DISCONNECT:
                            task = asyncio.Task(self.handle_disconnect(packet))
                        elif packet.fixed_header.packet_type == CONNECT:
                            task = asyncio.Task(self.handle_connect(packet))
                        else:
                            self.logger.warn("%s Unhandled packet type: %s" %
                                             (self.session.client_id, packet.fixed_header.packet_type))
                        if task:
                            # Wait for message handling ends
                            asyncio.wait([task])
                else:
                    self.logger.debug("%s No more data (EOF received), stopping reader coro" % self.session.client_id)
                    yield from self.handle_connection_closed()
                    break
            except asyncio.TimeoutError:
                self.logger.debug("%s Input stream read timeout" % self.session.client_id)
                self.handle_read_timeout()
            except NoDataException as nde:
                self.logger.debug("%s No data available" % self.session.client_id)
            except Exception as e:
                self.logger.warn("%s Unhandled exception in reader coro: %s" % (self.session.client_id, e))
                break
        self.logger.debug("%s Reader coro stopped" % self.session.client_id)
Example #6
0
    def _reader_coro(self):
        self.logger.debug("%s Starting reader coro" % self.session.client_id)
        while self._running:
            try:
                self._reader_ready.set()
                keepalive_timeout = self.session.keep_alive
                if keepalive_timeout <= 0:
                    keepalive_timeout = None
                fixed_header = yield from asyncio.wait_for(
                    MQTTFixedHeader.from_stream(self.reader),
                    keepalive_timeout)
                if fixed_header:
                    if fixed_header.packet_type == RESERVED_0 or fixed_header.packet_type == RESERVED_15:
                        self.logger.warn(
                            "%s Received reserved packet, which is forbidden: closing connection"
                            % (self.session.client_id))
                        yield from self.handle_connection_closed()
                    else:
                        cls = packet_class(fixed_header)
                        packet = yield from cls.from_stream(
                            self.reader, fixed_header=fixed_header)
                        self.logger.debug(
                            "%s <-in-- %s" %
                            (self.session.client_id, repr(packet)))
                        self._loop.call_soon(self.on_packet_received.send,
                                             packet)

                        task = None
                        if packet.fixed_header.packet_type == CONNACK:
                            task = asyncio.Task(self.handle_connack(packet))
                        elif packet.fixed_header.packet_type == SUBSCRIBE:
                            task = asyncio.Task(self.handle_subscribe(packet))
                        elif packet.fixed_header.packet_type == UNSUBSCRIBE:
                            task = asyncio.Task(
                                self.handle_unsubscribe(packet))
                        elif packet.fixed_header.packet_type == SUBACK:
                            task = asyncio.Task(self.handle_suback(packet))
                        elif packet.fixed_header.packet_type == UNSUBACK:
                            task = asyncio.Task(self.handle_unsuback(packet))
                        elif packet.fixed_header.packet_type == PUBACK:
                            task = asyncio.Task(self.handle_puback(packet))
                        elif packet.fixed_header.packet_type == PUBREC:
                            task = asyncio.Task(self.handle_pubrec(packet))
                        elif packet.fixed_header.packet_type == PUBREL:
                            task = asyncio.Task(self.handle_pubrel(packet))
                        elif packet.fixed_header.packet_type == PUBCOMP:
                            task = asyncio.Task(self.handle_pubcomp(packet))
                        elif packet.fixed_header.packet_type == PINGREQ:
                            task = asyncio.Task(self.handle_pingreq(packet))
                        elif packet.fixed_header.packet_type == PINGRESP:
                            task = asyncio.Task(self.handle_pingresp(packet))
                        elif packet.fixed_header.packet_type == PUBLISH:
                            task = asyncio.Task(self.handle_publish(packet))
                        elif packet.fixed_header.packet_type == DISCONNECT:
                            task = asyncio.Task(self.handle_disconnect(packet))
                        elif packet.fixed_header.packet_type == CONNECT:
                            task = asyncio.Task(self.handle_connect(packet))
                        else:
                            self.logger.warn("%s Unhandled packet type: %s" %
                                             (self.session.client_id,
                                              packet.fixed_header.packet_type))
                        if task:
                            # Wait for message handling ends
                            asyncio.wait([task])
                else:
                    self.logger.debug(
                        "%s No more data (EOF received), stopping reader coro"
                        % self.session.client_id)
                    yield from self.handle_connection_closed()
                    break
            except asyncio.TimeoutError:
                self.logger.debug("%s Input stream read timeout" %
                                  self.session.client_id)
                self.handle_read_timeout()
            except NoDataException as nde:
                self.logger.debug("%s No data available" %
                                  self.session.client_id)
            except Exception as e:
                self.logger.warn("%s Unhandled exception in reader coro: %s" %
                                 (self.session.client_id, e))
                break
        self.logger.debug("%s Reader coro stopped" % self.session.client_id)
Example #7
0
    def client_connected(self, reader, writer):

        #handle connection and create session to add to the list of sessions
        #read connection packet from the client

        connect = yield from MQTTConnect.ConnectPacket.from_stream(reader)
        if (connect.payload.client_id is None):
            generate_id = True
        else:
            generate_id = False

        #send a connack packet to client depending on correct credentials
        connack = None
        if (connect.username == self._username
                and connect.password == self._password):
            connack = MQTTConnack.ConnackPacket.build(
                0, MQTTConnack.CONNECTION_ACCEPTED)
            connected = True
        else:
            connack = MQTTConnack.ConnackPacket.build(
                0, MQTTConnack.BAD_USERNAME_PASSWORD)
            connected = False

        writer.write(connack.to_bytes())

        if (not connected):
            return

        new_session = Session()
        if (generate_id):
            new_session.client_id = new_session.generate_client_id()
        else:
            new_session.client_id = connect.client_id
        new_session.remote_address = writer.get_extra_info('peername')
        new_session.remote_port = writer.get_extra_info('socket')
        new_session.username = connect.username
        new_session.password = connect.password
        new_session.keep_alive = connect.keep_alive
        new_session.writer = writer
        new_session.reader = reader

        self._sessions[new_session.client_id] = new_session
        print("New client; %s connected from %s with keep_alive: %s" %
              (new_session.client_id, new_session.remote_address,
               new_session.keep_alive))

        #received packets are checked and the corresponding method is used (publish, sub/unsub, disconnect)
        try:
            while connected:
                mqtt_header = yield from asyncio.wait_for(
                    MQTTFixedHeader.from_stream(reader),
                    new_session.keep_alive + 1,
                    loop=self._loop)

                cls = packet_class(fixed_header=mqtt_header)
                packet = yield from cls.from_stream(reader,
                                                    fixed_header=mqtt_header)

                if (packet.fixed_header.packet_type == SUBSCRIBE):
                    for (topic, qos) in packet.payload.topics:
                        if (qos != 0):
                            print("QoS is different than expected")
                            print(qos)
                        self.add_subscription(topic, new_session)
                elif (packet.fixed_header.packet_type == UNSUBSCRIBE):
                    for (topic, qos) in packet.payload.topics:
                        if (qos != 0):
                            print("QoS is different than expected")
                            print(qos)
                        self.del_subscription(topic, new_session)
                elif (packet.fixed_header.packet_type == PUBLISH):
                    topic = packet.variable_header.topic_name
                    message = packet.payload.data
                    print("Broadcast; Topic: %s, Payload: %s" %
                          (topic, message))
                    yield from self.broadcast_message(new_session, topic,
                                                      message)
                elif (packet.fixed_header.packet_type == DISCONNECT):
                    self.del_all_subscriptions(new_session)
                    self.del_session(new_session.client_id)
                    connected = False
                    print("Client: %s disconnected" % (new_session.client_id))
                elif (packet.fixed_header.packet_type == PINGREQ):
                    pingresp_packet = PingRespPacket.build()
                    writer.write(pingresp_packet.to_bytes())
                else:
                    print('Not yet supported packet received')
        except asyncio.TimeoutError:
            print("Client %s didn't respond; diconnecting" %
                  new_session.client_id)
            self.del_session(new_session.client_id)