def __init__(self, topic_name: str, packet_id: int = None): super().__init__() if '*' in topic_name: raise MQTTException( "[MQTT-3.3.2-2] Topic name in the PUBLISH Packet MUST NOT contain wildcard characters." ) self.topic_name = topic_name self.packet_id = packet_id
def decode_remaining_length(): """ Decode message length according to MQTT specifications :return: """ multiplier = 1 value = 0 buffer = bytearray() while True: encoded_byte = yield from reader.read(1) int_byte = unpack('!B', encoded_byte) buffer.append(int_byte[0]) value += (int_byte[0] & 0x7f) * multiplier if (int_byte[0] & 0x80) == 0: break else: multiplier *= 128 if multiplier > 128 * 128 * 128: raise MQTTException("Invalid remaining length bytes:%s, packet_type=%d" % (bytes_to_hex_str(buffer), msg_type)) return value
def from_stream(cls, reader: ReaderAdapter, fixed_header: MQTTFixedHeader): # protocol name protocol_name = yield from decode_string(reader) if protocol_name != "MQTT": raise MQTTException( '[MQTT-3.1.2-1] Incorrect protocol name: "%s"' % protocol_name) # protocol level protocol_level_byte = yield from read_or_raise(reader, 1) protocol_level = bytes_to_int(protocol_level_byte) # flags flags_byte = yield from read_or_raise(reader, 1) flags = bytes_to_int(flags_byte) # keep-alive keep_alive_byte = yield from read_or_raise(reader, 2) keep_alive = bytes_to_int(keep_alive_byte) return cls(flags, keep_alive, protocol_name, protocol_level)
def decode_remaining_length(): """ Decode message length according to MQTT specifications :return: """ multiplier = 1 value = 0 buffer = b'' while True: encoded_byte = yield from reader.read(1) buffer += encoded_byte int_byte = bytes_to_int(encoded_byte) value += (int_byte & 0x7f) * multiplier if (int_byte & 0x80) == 0: break else: multiplier *= 128 if multiplier > 128 * 128 * 128: raise MQTTException( "Invalid remaining length bytes:%s" % bytes_to_hex_str(buffer)) return value
async def init_from_connect(cls, stream: StreamAdapter, plugins_manager): """ :param stream: :param plugins_manager: :return: """ remote_address, remote_port = stream.get_peer_info() try: connect = await ConnectPacket.from_stream(stream) except NoDataException: raise MQTTException('Client closed the connection') logger.debug("< B %r", connect) await plugins_manager.fire_event(EVENT_MQTT_PACKET_RECEIVED, packet=connect) #this shouldn't be required anymore since broker generates for each client a random client_id if not provided #[MQTT-3.1.3-6] if connect.payload.client_id is None: raise MQTTException( '[[MQTT-3.1.3-3]] : Client identifier must be present') if connect.variable_header.will_flag: if connect.payload.will_topic is None or connect.payload.will_message is None: raise MQTTException( 'will flag set, but will topic/message not present in payload' ) if connect.variable_header.reserved_flag: raise MQTTException( '[MQTT-3.1.2-3] CONNECT reserved flag must be set to 0') if connect.proto_name != "MQTT": raise MQTTException( '[MQTT-3.1.2-1] Incorrect protocol name: "%s"' % connect.proto_name) connack = None error_msg = None if connect.proto_level != 4: # only MQTT 3.1.1 supported error_msg = 'Invalid protocol from %s: %d' % ( format_client_message(address=remote_address, port=remote_port), connect.proto_level) connack = ConnackPacket.build(0, UNACCEPTABLE_PROTOCOL_VERSION ) # [MQTT-3.2.2-4] session_parent=0 elif not connect.username_flag and connect.password_flag: connack = ConnackPacket.build( 0, BAD_USERNAME_PASSWORD) # [MQTT-3.1.2-22] elif connect.username_flag and not connect.password_flag: connack = ConnackPacket.build( 0, BAD_USERNAME_PASSWORD) # [MQTT-3.1.2-22] elif connect.username_flag and connect.username is None: error_msg = 'Invalid username from %s' % (format_client_message( address=remote_address, port=remote_port)) connack = ConnackPacket.build( 0, BAD_USERNAME_PASSWORD) # [MQTT-3.2.2-4] session_parent=0 elif connect.password_flag and connect.password is None: error_msg = 'Invalid password %s' % (format_client_message( address=remote_address, port=remote_port)) connack = ConnackPacket.build( 0, BAD_USERNAME_PASSWORD) # [MQTT-3.2.2-4] session_parent=0 elif connect.clean_session_flag is False and ( connect.payload.client_id_is_random): error_msg = '[MQTT-3.1.3-8] [MQTT-3.1.3-9] %s: No client Id provided (cleansession=0)' % ( format_client_message(address=remote_address, port=remote_port)) connack = ConnackPacket.build(0, IDENTIFIER_REJECTED) if connack is not None: logger.debug("B > %r", connack) await plugins_manager.fire_event(EVENT_MQTT_PACKET_SENT, packet=connack) await connack.to_stream(stream) await stream.close() raise MQTTException(error_msg) incoming_session = Session(plugins_manager) incoming_session.client_id = connect.client_id incoming_session.clean_session = connect.clean_session_flag incoming_session.will_flag = connect.will_flag incoming_session.will_retain = connect.will_retain_flag incoming_session.will_qos = connect.will_qos incoming_session.will_topic = connect.will_topic incoming_session.will_message = connect.will_message incoming_session.username = connect.username incoming_session.password = connect.password if connect.keep_alive > 0: incoming_session.keep_alive = connect.keep_alive else: incoming_session.keep_alive = 0 handler = cls(plugins_manager) return handler, incoming_session
def init_from_connect(cls, reader: ReaderAdapter, writer: WriterAdapter, plugins_manager, loop=None): """ :param reader: :param writer: :param plugins_manager: :param loop: :return: """ remote_address, remote_port = writer.get_peer_info() connect = yield from ConnectPacket.from_stream(reader) yield from plugins_manager.fire_event(EVENT_MQTT_PACKET_RECEIVED, packet=connect) if connect.payload.client_id is None: raise MQTTException('[[MQTT-3.1.3-3]] : Client identifier must be present' ) if connect.variable_header.will_flag: if connect.payload.will_topic is None or connect.payload.will_message is None: raise MQTTException('will flag set, but will topic/message not present in payload') if connect.variable_header.reserved_flag: raise MQTTException('[MQTT-3.1.2-3] CONNECT reserved flag must be set to 0') if connect.proto_name != "MQTT": raise MQTTException('[MQTT-3.1.2-1] Incorrect protocol name: "%s"' % connect.proto_name) connack = None error_msg = None if connect.proto_level != 4: # only MQTT 3.1.1 supported error_msg = 'Invalid protocol from %s: %d' % \ (format_client_message(address=remote_address, port=remote_port), connect.variable_header.protocol_level) connack = ConnackPacket.build(0, UNACCEPTABLE_PROTOCOL_VERSION) # [MQTT-3.2.2-4] session_parent=0 elif connect.username_flag and connect.username is None: error_msg = 'Invalid username from %s' % \ (format_client_message(address=remote_address, port=remote_port)) connack = ConnackPacket.build(0, BAD_USERNAME_PASSWORD) # [MQTT-3.2.2-4] session_parent=0 elif connect.password_flag and connect.password is None: error_msg = 'Invalid password %s' % (format_client_message(address=remote_address, port=remote_port)) connack = ConnackPacket.build(0, BAD_USERNAME_PASSWORD) # [MQTT-3.2.2-4] session_parent=0 elif connect.clean_session_flag is False and connect.payload.client_id is None: error_msg = '[MQTT-3.1.3-8] [MQTT-3.1.3-9] %s: No client Id provided (cleansession=0)' % \ format_client_message(address=remote_address, port=remote_port) connack = ConnackPacket.build(0, IDENTIFIER_REJECTED) if connack is not None: yield from plugins_manager.fire_event(EVENT_MQTT_PACKET_SENT, packet=connack) yield from connack.to_stream(writer) yield from writer.close() raise MQTTException(error_msg) incoming_session = Session(loop) incoming_session.client_id = connect.client_id incoming_session.clean_session = connect.clean_session_flag incoming_session.will_flag = connect.will_flag incoming_session.will_retain = connect.will_retain_flag incoming_session.will_qos = connect.will_qos incoming_session.will_topic = connect.will_topic incoming_session.will_message = connect.will_message incoming_session.username = connect.username incoming_session.password = connect.password if connect.keep_alive > 0: incoming_session.keep_alive = connect.keep_alive else: incoming_session.keep_alive = 0 handler = cls(plugins_manager, loop=loop) return handler, incoming_session