def _initsession(self, host=None, port=None, username=None, password=None, uri=None, cleansession=None) -> dict: # Load config broker_conf = self.config.get('broker', dict()).copy() if 'mqtt' not in broker_conf: broker_conf['scheme'] = 'mqtt' if 'username' not in broker_conf: broker_conf['username'] = None if 'password' not in broker_conf: broker_conf['password'] = None if uri is not None: result = urlparse(uri) if result.scheme: broker_conf['scheme'] = result.scheme if result.hostname: broker_conf['host'] = result.hostname if result.port: broker_conf['port'] = result.port if result.username: broker_conf['username'] = result.username if result.password: broker_conf['password'] = result.password if host: broker_conf['host'] = host if port: broker_conf['port'] = int(port) if username: broker_conf['username'] = username if password: broker_conf['password'] = password if cleansession is not None: broker_conf['cleansession'] = cleansession for key in ['scheme', 'host', 'port']: if not_in_dict_or_none(broker_conf, key): raise ClientException("Missing connection parameter '%s'" % key) s = Session() s.client_id = self.client_id s.remote_address = broker_conf['host'] s.remote_port = broker_conf['port'] s.username = broker_conf['username'] s.password = broker_conf['password'] s.scheme = broker_conf['scheme'] if cleansession is not None: s.cleansession = cleansession else: s.cleansession = self.config.get('cleansession', True) s.keep_alive = self.config['keep_alive'] if 'will' in self.config: s.will_flag = True s.will_retain = self.config['will']['retain'] s.will_topic = self.config['will']['topic'] s.will_message = self.config['will']['message'] else: s.will_flag = False s.will_retain = False s.will_topic = None s.will_message = None return s
def _initsession(self, uri=None, cleansession=None, cafile=None, capath=None, cadata=None) -> Session: # Load config broker_conf = self.config.get("broker", dict()).copy() if uri: broker_conf["uri"] = uri if cafile: broker_conf["cafile"] = cafile elif "cafile" not in broker_conf: broker_conf["cafile"] = None if capath: broker_conf["capath"] = capath elif "capath" not in broker_conf: broker_conf["capath"] = None if cadata: broker_conf["cadata"] = cadata elif "cadata" not in broker_conf: broker_conf["cadata"] = None if cleansession is not None: broker_conf["cleansession"] = cleansession for key in ["uri"]: if not_in_dict_or_none(broker_conf, key): raise ClientException("Missing connection parameter '%s'" % key) s = Session() s.broker_uri = uri s.client_id = self.client_id s.cafile = broker_conf["cafile"] s.capath = broker_conf["capath"] s.cadata = broker_conf["cadata"] if cleansession is not None: s.clean_session = cleansession else: s.clean_session = self.config.get("cleansession", True) s.keep_alive = self.config["keep_alive"] - self.config["ping_delay"] if "will" in self.config: s.will_flag = True s.will_retain = self.config["will"]["retain"] s.will_topic = self.config["will"]["topic"] s.will_message = self.config["will"]["message"] s.will_qos = self.config["will"]["qos"] else: s.will_flag = False s.will_retain = False s.will_topic = None s.will_message = None return s
def _initsession(self, uri=None, cleansession=None, cafile=None, capath=None, cadata=None) -> Session: # Load config broker_conf = self.config.get('broker', dict()).copy() if uri: broker_conf['uri'] = uri if cafile: broker_conf['cafile'] = cafile elif 'cafile' not in broker_conf: broker_conf['cafile'] = None if capath: broker_conf['capath'] = capath elif 'capath' not in broker_conf: broker_conf['capath'] = None if cadata: broker_conf['cadata'] = cadata elif 'cadata' not in broker_conf: broker_conf['cadata'] = None if cleansession is not None: broker_conf['cleansession'] = cleansession for key in ['uri']: if not_in_dict_or_none(broker_conf, key): raise ClientException("Missing connection parameter '%s'" % key) s = Session() s.broker_uri = uri s.client_id = self.client_id s.cafile = broker_conf['cafile'] s.capath = broker_conf['capath'] s.cadata = broker_conf['cadata'] if cleansession is not None: s.clean_session = cleansession else: s.clean_session = self.config.get('cleansession', True) s.keep_alive = self.config['keep_alive'] - self.config['ping_delay'] if 'will' in self.config: s.will_flag = True s.will_retain = self.config['will']['retain'] s.will_topic = self.config['will']['topic'] s.will_message = self.config['will']['message'] s.will_qos = self.config['will']['qos'] else: s.will_flag = False s.will_retain = False s.will_topic = None s.will_message = None return s
def _initsession( self, uri=None, cleansession=None, cafile=None, capath=None, cadata=None) -> Session: # Load config broker_conf = self.config.get('broker', dict()).copy() if uri: broker_conf['uri'] = uri if cafile: broker_conf['cafile'] = cafile elif 'cafile' not in broker_conf: broker_conf['cafile'] = None if capath: broker_conf['capath'] = capath elif 'capath' not in broker_conf: broker_conf['capath'] = None if cadata: broker_conf['cadata'] = cadata elif 'cadata' not in broker_conf: broker_conf['cadata'] = None if cleansession is not None: broker_conf['cleansession'] = cleansession for key in ['uri']: if not_in_dict_or_none(broker_conf, key): raise ClientException("Missing connection parameter '%s'" % key) s = Session() s.broker_uri = uri s.client_id = self.client_id s.cafile = broker_conf['cafile'] s.capath = broker_conf['capath'] s.cadata = broker_conf['cadata'] if cleansession is not None: s.clean_session = cleansession else: s.clean_session = self.config.get('cleansession', True) s.keep_alive = self.config['keep_alive'] - self.config['ping_delay'] if 'will' in self.config: s.will_flag = True s.will_retain = self.config['will']['retain'] s.will_topic = self.config['will']['topic'] s.will_message = self.config['will']['message'] s.will_qos = self.config['will']['qos'] else: s.will_flag = False s.will_retain = False s.will_topic = None s.will_message = None return s
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 client_connected(self, listener_name, reader: ReaderAdapter, writer: WriterAdapter): # Wait for connection available server = self._servers[listener_name] yield from server.acquire_connection() remote_address, remote_port = writer.get_peer_info() self.logger.debug("Connection from %s:%d on listener '%s'" % (remote_address, remote_port, listener_name)) # Wait for first packet and expect a CONNECT connect = None try: connect = yield from ConnectPacket.from_stream(reader) self.logger.debug(" <-in-- " + repr(connect)) self.check_connect(connect) except HBMQTTException as exc: self.logger.warn("[MQTT-3.1.0-1] %s: Can't read first packet an CONNECT: %s" % (format_client_message(address=remote_address, port=remote_port), exc)) yield from writer.close() self.logger.debug("Connection closed") return except BrokerException as be: self.logger.error('Invalid connection from %s : %s' % (format_client_message(address=remote_address, port=remote_port), be)) yield from writer.close() self.logger.debug("Connection closed") return connack = None if connect.variable_header.proto_level != 4: # only MQTT 3.1.1 supported self.logger.error('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.variable_header.username_flag and connect.payload.username is None: self.logger.error('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.variable_header.password_flag and connect.payload.password is None: self.logger.error('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.variable_header.clean_session_flag is False and connect.payload.client_id is None: self.logger.error('[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) self.logger.debug(" -out-> " + repr(connack)) if connack is not None: self.logger.debug(" -out-> " + repr(connack)) yield from connack.to_stream(writer) yield from writer.close() return client_session = None self.logger.debug("Clean session={0}".format(connect.variable_header.clean_session_flag)) self.logger.debug("known sessions={0}".format(self._sessions)) client_id = connect.payload.client_id if connect.variable_header.clean_session_flag: # Delete existing session and create a new one if client_id is not None: self.delete_session(client_id) client_session = Session() client_session.parent = 0 client_session.client_id = client_id self._sessions[client_id] = client_session else: # Get session from cache if client_id in self._sessions: self.logger.debug("Found old session %s" % repr(self._sessions[client_id])) client_session = self._sessions[client_id] client_session.parent = 1 else: client_session = Session() client_session.client_id = client_id self._sessions[client_id] = client_session client_session.parent = 0 if client_session.client_id is None: # Generate client ID client_session.client_id = gen_client_id() client_session.remote_address = remote_address client_session.remote_port = remote_port client_session.clean_session = connect.variable_header.clean_session_flag client_session.will_flag = connect.variable_header.will_flag client_session.will_retain = connect.variable_header.will_retain_flag client_session.will_qos = connect.variable_header.will_qos client_session.will_topic = connect.payload.will_topic client_session.will_message = connect.payload.will_message client_session.username = connect.payload.username client_session.password = connect.payload.password client_session.client_id = connect.payload.client_id if connect.variable_header.keep_alive > 0: client_session.keep_alive = connect.variable_header.keep_alive + self.config['timeout-disconnect-delay'] else: client_session.keep_alive = 0 client_session.publish_retry_delay = self.config['publish-retry-delay'] client_session.reader = reader client_session.writer = writer if self.authenticate(client_session): connack = ConnackPacket.build(client_session.parent, CONNECTION_ACCEPTED) self.logger.info('%s : connection accepted' % format_client_message(session=client_session)) self.logger.debug(" -out-> " + repr(connack)) yield from connack.to_stream(writer) else: connack = ConnackPacket.build(client_session.parent, NOT_AUTHORIZED) self.logger.info('%s : connection refused' % format_client_message(session=client_session)) self.logger.debug(" -out-> " + repr(connack)) yield from connack.to_stream(writer) yield from writer.close() return client_session.transitions.connect() handler = self._init_handler(reader, writer, client_session) self.logger.debug("%s Start messages handling" % client_session.client_id) yield from handler.start() self.logger.debug("Retained messages queue size: %d" % client_session.retained_messages.qsize()) yield from self.publish_session_retained_messages(client_session) self.logger.debug("%s Wait for disconnect" % client_session.client_id) connected = True wait_disconnect = asyncio.Task(handler.wait_disconnect()) wait_subscription = asyncio.Task(handler.get_next_pending_subscription()) wait_unsubscription = asyncio.Task(handler.get_next_pending_unsubscription()) wait_deliver = asyncio.Task(handler.mqtt_deliver_next_message()) while connected: done, pending = yield from asyncio.wait( [wait_disconnect, wait_subscription, wait_unsubscription, wait_deliver], return_when=asyncio.FIRST_COMPLETED) if wait_disconnect in done: result = wait_disconnect.result() self.logger.debug("%s Result from wait_diconnect: %s" % (client_session.client_id, result)) if result is None: self.logger.debug("Will flag: %s" % client_session.will_flag) # Connection closed anormally, send will message if client_session.will_flag: self.logger.debug("Client %s disconnected abnormally, sending will message" % format_client_message(client_session)) yield from self.broadcast_application_message( client_session, client_session.will_topic, client_session.will_message, client_session.will_qos) if client_session.will_retain: self.retain_message(client_session, client_session.will_topic, client_session.will_message, client_session.will_qos) connected = False if wait_unsubscription in done: self.logger.debug("%s handling unsubscription" % client_session.client_id) unsubscription = wait_unsubscription.result() for topic in unsubscription['topics']: self.del_subscription(topic, client_session) yield from handler.mqtt_acknowledge_unsubscription(unsubscription['packet_id']) wait_unsubscription = asyncio.Task(handler.get_next_pending_unsubscription()) if wait_subscription in done: self.logger.debug("%s handling subscription" % client_session.client_id) subscriptions = wait_subscription.result() return_codes = [] for subscription in subscriptions['topics']: return_codes.append(self.add_subscription(subscription, client_session)) yield from handler.mqtt_acknowledge_subscription(subscriptions['packet_id'], return_codes) for index, subscription in enumerate(subscriptions['topics']): if return_codes[index] != 0x80: yield from self.publish_retained_messages_for_subscription(subscription, client_session) wait_subscription = asyncio.Task(handler.get_next_pending_subscription()) self.logger.debug(repr(self._subscriptions)) if wait_deliver in done: self.logger.debug("%s handling message delivery" % client_session.client_id) publish_packet = wait_deliver.result() packet_id = publish_packet.variable_header.packet_id topic_name = publish_packet.variable_header.topic_name data = publish_packet.payload.data yield from self.broadcast_application_message(client_session, topic_name, data) if publish_packet.retain_flag: self.retain_message(client_session, topic_name, data) # Acknowledge message delivery yield from handler.mqtt_acknowledge_delivery(packet_id) wait_deliver = asyncio.Task(handler.mqtt_deliver_next_message()) wait_subscription.cancel() wait_unsubscription.cancel() wait_deliver.cancel() self.logger.debug("%s Client disconnecting" % client_session.client_id) yield from self._stop_handler(handler) client_session.transitions.disconnect() yield from writer.close() self.logger.debug("%s Session disconnected" % client_session.client_id) server.release_connection()
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.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 None or connect.payload.client_id == ""): 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
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
def client_connected(self, listener_name, reader: ReaderAdapter, writer: WriterAdapter): # Wait for connection available server = self._servers[listener_name] yield from server.acquire_connection() remote_address, remote_port = writer.get_peer_info() self.logger.debug("Connection from %s:%d on listener '%s'" % (remote_address, remote_port, listener_name)) # Wait for first packet and expect a CONNECT connect = None try: connect = yield from ConnectPacket.from_stream(reader) self.logger.debug(" <-in-- " + repr(connect)) self.check_connect(connect) except HBMQTTException as exc: self.logger.warn( "[MQTT-3.1.0-1] %s: Can't read first packet an CONNECT: %s" % (format_client_message(address=remote_address, port=remote_port), exc)) yield from writer.close() self.logger.debug("Connection closed") return except BrokerException as be: self.logger.error('Invalid connection from %s : %s' % (format_client_message(address=remote_address, port=remote_port), be)) yield from writer.close() self.logger.debug("Connection closed") return connack = None if connect.variable_header.proto_level != 4: # only MQTT 3.1.1 supported self.logger.error( '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.variable_header.username_flag and connect.payload.username is None: self.logger.error('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.variable_header.password_flag and connect.payload.password is None: self.logger.error('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.variable_header.clean_session_flag is False and connect.payload.client_id is None: self.logger.error( '[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) self.logger.debug(" -out-> " + repr(connack)) if connack is not None: self.logger.debug(" -out-> " + repr(connack)) yield from connack.to_stream(writer) yield from writer.close() return client_session = None self.logger.debug("Clean session={0}".format( connect.variable_header.clean_session_flag)) self.logger.debug("known sessions={0}".format(self._sessions)) client_id = connect.payload.client_id if connect.variable_header.clean_session_flag: # Delete existing session and create a new one if client_id is not None: self.delete_session(client_id) client_session = Session() client_session.parent = 0 client_session.client_id = client_id self._sessions[client_id] = client_session else: # Get session from cache if client_id in self._sessions: self.logger.debug("Found old session %s" % repr(self._sessions[client_id])) client_session = self._sessions[client_id] client_session.parent = 1 else: client_session = Session() client_session.client_id = client_id self._sessions[client_id] = client_session client_session.parent = 0 if client_session.client_id is None: # Generate client ID client_session.client_id = gen_client_id() client_session.remote_address = remote_address client_session.remote_port = remote_port client_session.clean_session = connect.variable_header.clean_session_flag client_session.will_flag = connect.variable_header.will_flag client_session.will_retain = connect.variable_header.will_retain_flag client_session.will_qos = connect.variable_header.will_qos client_session.will_topic = connect.payload.will_topic client_session.will_message = connect.payload.will_message client_session.username = connect.payload.username client_session.password = connect.payload.password client_session.client_id = connect.payload.client_id if connect.variable_header.keep_alive > 0: client_session.keep_alive = connect.variable_header.keep_alive + self.config[ 'timeout-disconnect-delay'] else: client_session.keep_alive = 0 client_session.publish_retry_delay = self.config['publish-retry-delay'] client_session.reader = reader client_session.writer = writer if self.authenticate(client_session): connack = ConnackPacket.build(client_session.parent, CONNECTION_ACCEPTED) self.logger.info('%s : connection accepted' % format_client_message(session=client_session)) self.logger.debug(" -out-> " + repr(connack)) yield from connack.to_stream(writer) else: connack = ConnackPacket.build(client_session.parent, NOT_AUTHORIZED) self.logger.info('%s : connection refused' % format_client_message(session=client_session)) self.logger.debug(" -out-> " + repr(connack)) yield from connack.to_stream(writer) yield from writer.close() return client_session.transitions.connect() handler = self._init_handler(reader, writer, client_session) self.logger.debug("%s Start messages handling" % client_session.client_id) yield from handler.start() self.logger.debug("Retained messages queue size: %d" % client_session.retained_messages.qsize()) yield from self.publish_session_retained_messages(client_session) self.logger.debug("%s Wait for disconnect" % client_session.client_id) connected = True wait_disconnect = asyncio.Task(handler.wait_disconnect()) wait_subscription = asyncio.Task( handler.get_next_pending_subscription()) wait_unsubscription = asyncio.Task( handler.get_next_pending_unsubscription()) wait_deliver = asyncio.Task(handler.mqtt_deliver_next_message()) while connected: done, pending = yield from asyncio.wait( [ wait_disconnect, wait_subscription, wait_unsubscription, wait_deliver ], return_when=asyncio.FIRST_COMPLETED) if wait_disconnect in done: result = wait_disconnect.result() self.logger.debug("%s Result from wait_diconnect: %s" % (client_session.client_id, result)) if result is None: self.logger.debug("Will flag: %s" % client_session.will_flag) # Connection closed anormally, send will message if client_session.will_flag: self.logger.debug( "Client %s disconnected abnormally, sending will message" % format_client_message(client_session)) yield from self.broadcast_application_message( client_session, client_session.will_topic, client_session.will_message, client_session.will_qos) if client_session.will_retain: self.retain_message(client_session, client_session.will_topic, client_session.will_message, client_session.will_qos) connected = False if wait_unsubscription in done: self.logger.debug("%s handling unsubscription" % client_session.client_id) unsubscription = wait_unsubscription.result() for topic in unsubscription['topics']: self.del_subscription(topic, client_session) yield from handler.mqtt_acknowledge_unsubscription( unsubscription['packet_id']) wait_unsubscription = asyncio.Task( handler.get_next_pending_unsubscription()) if wait_subscription in done: self.logger.debug("%s handling subscription" % client_session.client_id) subscriptions = wait_subscription.result() return_codes = [] for subscription in subscriptions['topics']: return_codes.append( self.add_subscription(subscription, client_session)) yield from handler.mqtt_acknowledge_subscription( subscriptions['packet_id'], return_codes) for index, subscription in enumerate(subscriptions['topics']): if return_codes[index] != 0x80: yield from self.publish_retained_messages_for_subscription( subscription, client_session) wait_subscription = asyncio.Task( handler.get_next_pending_subscription()) self.logger.debug(repr(self._subscriptions)) if wait_deliver in done: self.logger.debug("%s handling message delivery" % client_session.client_id) publish_packet = wait_deliver.result() packet_id = publish_packet.variable_header.packet_id topic_name = publish_packet.variable_header.topic_name data = publish_packet.payload.data yield from self.broadcast_application_message( client_session, topic_name, data) if publish_packet.retain_flag: self.retain_message(client_session, topic_name, data) # Acknowledge message delivery yield from handler.mqtt_acknowledge_delivery(packet_id) wait_deliver = asyncio.Task( handler.mqtt_deliver_next_message()) wait_subscription.cancel() wait_unsubscription.cancel() wait_deliver.cancel() self.logger.debug("%s Client disconnecting" % client_session.client_id) yield from self._stop_handler(handler) client_session.transitions.disconnect() yield from writer.close() self.logger.debug("%s Session disconnected" % client_session.client_id) server.release_connection()