Handle timeout on broker side (disconnect client if not message received until timeout specified on CONNECT)
pull/8/head
Nicolas Jouanin 2015-07-11 22:42:50 +02:00
rodzic 0181795192
commit d2d843fec4
4 zmienionych plików z 33 dodań i 8 usunięć

Wyświetl plik

@ -15,7 +15,8 @@ from hbmqtt.utils import format_client_message, gen_client_id
_defaults = { _defaults = {
'bind-address': 'localhost', 'bind-address': 'localhost',
'bind-port': 1883 'bind-port': 1883,
'timeout-disconnect-delay': 1
} }
@ -169,7 +170,7 @@ class Broker:
new_session.username = connect.payload.username new_session.username = connect.payload.username
new_session.password = connect.payload.password new_session.password = connect.payload.password
new_session.client_id = connect.payload.client_id new_session.client_id = connect.payload.client_id
new_session.keep_alive = connect.variable_header.keep_alive new_session.keep_alive = connect.variable_header.keep_alive + self.config['timeout-disconnect-delay']
new_session.reader = reader new_session.reader = reader
new_session.writer = writer new_session.writer = writer

Wyświetl plik

@ -34,6 +34,8 @@ class BrokerProtocolHandler(ProtocolHandler):
@asyncio.coroutine @asyncio.coroutine
def stop(self): def stop(self):
yield from super().stop() yield from super().stop()
if self._disconnect_waiter is not None and not self._disconnect_waiter.done():
self._disconnect_waiter.set_result(None)
@asyncio.coroutine @asyncio.coroutine
def wait_disconnect(self): def wait_disconnect(self):
@ -41,6 +43,12 @@ class BrokerProtocolHandler(ProtocolHandler):
self._disconnect_waiter = futures.Future(loop=self._loop) self._disconnect_waiter = futures.Future(loop=self._loop)
yield from self._disconnect_waiter yield from self._disconnect_waiter
def handle_write_timeout(self):
pass
def handle_read_timeout(self):
asyncio.Task(self.stop())
@asyncio.coroutine @asyncio.coroutine
def handle_disconnect(self, disconnect: DisconnectPacket): def handle_disconnect(self, disconnect: DisconnectPacket):
if self._disconnect_waiter is not None: if self._disconnect_waiter is not None:

Wyświetl plik

@ -40,9 +40,12 @@ class ClientProtocolHandler(ProtocolHandler):
except Exception: except Exception:
pass pass
def handle_keepalive(self): def handle_write_timeout(self):
self._ping_task = self._loop.call_soon(asyncio.async, self.mqtt_ping()) self._ping_task = self._loop.call_soon(asyncio.async, self.mqtt_ping())
def handle_read_timeout(self):
pass
@asyncio.coroutine @asyncio.coroutine
def mqtt_subscribe(self, topics, packet_id): def mqtt_subscribe(self, topics, packet_id):
""" """

Wyświetl plik

@ -19,6 +19,7 @@ from hbmqtt.mqtt.pubrec import PubrecPacket
from hbmqtt.mqtt.pubcomp import PubcompPacket from hbmqtt.mqtt.pubcomp import PubcompPacket
from hbmqtt.mqtt.suback import SubackPacket from hbmqtt.mqtt.suback import SubackPacket
from hbmqtt.mqtt.subscribe import SubscribePacket from hbmqtt.mqtt.subscribe import SubscribePacket
from hbmqtt.mqtt.unsubscribe import UnsubscribePacket
from hbmqtt.mqtt.unsuback import UnsubackPacket from hbmqtt.mqtt.unsuback import UnsubackPacket
from hbmqtt.mqtt.disconnect import DisconnectPacket from hbmqtt.mqtt.disconnect import DisconnectPacket
from hbmqtt.session import Session from hbmqtt.session import Session
@ -146,7 +147,10 @@ class ProtocolHandler:
while self._running: while self._running:
try: try:
self._reader_ready.set() self._reader_ready.set()
fixed_header = yield from asyncio.wait_for(MQTTFixedHeader.from_stream(self.session.reader), 5) keepalive_timeout = self.session.keep_alive
if keepalive_timeout <= 0:
keepalive_timeout = None
fixed_header = yield from asyncio.wait_for(MQTTFixedHeader.from_stream(self.session.reader), keepalive_timeout)
if fixed_header: if fixed_header:
cls = packet_class(fixed_header) cls = packet_class(fixed_header)
packet = yield from cls.from_stream(self.session.reader, fixed_header=fixed_header) packet = yield from cls.from_stream(self.session.reader, fixed_header=fixed_header)
@ -156,6 +160,8 @@ class ProtocolHandler:
asyncio.Task(self.handle_connack(packet)) asyncio.Task(self.handle_connack(packet))
elif packet.fixed_header.packet_type == PacketType.SUBSCRIBE: elif packet.fixed_header.packet_type == PacketType.SUBSCRIBE:
asyncio.Task(self.handle_subscribe(packet)) asyncio.Task(self.handle_subscribe(packet))
elif packet.fixed_header.packet_type == PacketType.UNSUBSCRIBE:
asyncio.Task(self.handle_unsubscribe(packet))
elif packet.fixed_header.packet_type == PacketType.SUBACK: elif packet.fixed_header.packet_type == PacketType.SUBACK:
asyncio.Task(self.handle_suback(packet)) asyncio.Task(self.handle_suback(packet))
elif packet.fixed_header.packet_type == PacketType.UNSUBACK: elif packet.fixed_header.packet_type == PacketType.UNSUBACK:
@ -185,6 +191,7 @@ class ProtocolHandler:
break break
except asyncio.TimeoutError: except asyncio.TimeoutError:
self.logger.debug("Input stream read timeout") self.logger.debug("Input stream read timeout")
self.handle_read_timeout()
except NoDataException as nde: except NoDataException as nde:
self.logger.debug("No data available") self.logger.debug("No data available")
except Exception as e: except Exception as e:
@ -209,8 +216,7 @@ class ProtocolHandler:
except asyncio.TimeoutError as ce: except asyncio.TimeoutError as ce:
self.logger.debug("Output queue get timeout") self.logger.debug("Output queue get timeout")
if self._running: if self._running:
self.logger.debug("PING for keepalive") self.handle_write_timeout()
self.handle_keepalive()
except Exception as e: except Exception as e:
self.logger.warn("Unhandled exception in writer coro: %s" % e) self.logger.warn("Unhandled exception in writer coro: %s" % e)
break break
@ -233,8 +239,11 @@ class ProtocolHandler:
inflight_message = yield from self.delivered_message.get() inflight_message = yield from self.delivered_message.get()
return inflight_message return inflight_message
def handle_keepalive(self): def handle_write_timeout(self):
self.logger.warn('keepalive unhandled') self.logger.warn('write timeout unhandled')
def handle_read_timeout(self):
self.logger.warn('read timeout unhandled')
@asyncio.coroutine @asyncio.coroutine
def handle_connack(self, connack: ConnackPacket): def handle_connack(self, connack: ConnackPacket):
@ -248,6 +257,10 @@ class ProtocolHandler:
def handle_subscribe(self, subscribe: SubscribePacket): def handle_subscribe(self, subscribe: SubscribePacket):
self.logger.warn('SUBSCRIBE unhandled') self.logger.warn('SUBSCRIBE unhandled')
@asyncio.coroutine
def handle_unsubscribe(self, subscribe: UnsubscribePacket):
self.logger.warn('UNSUBSCRIBE unhandled')
@asyncio.coroutine @asyncio.coroutine
def handle_suback(self, suback: SubackPacket): def handle_suback(self, suback: SubackPacket):
self.logger.warn('SUBACK unhandled') self.logger.warn('SUBACK unhandled')