changeset 2725:d0466af33483

plugin XEP-0198: abort connection if ack is not received after a timeout: If ack is not received after a given time (currently 25s), connection is aborted. This avoid waiting forever when TCP link is lost (i.e. switching from cable to wifi), and allows to use resuming mechanism.
author Goffi <goffi@goffi.org>
date Wed, 26 Dec 2018 14:37:13 +0100
parents 35a0ab3032bb
children a86f494457c2
files sat/plugins/plugin_xep_0198.py
diffstat 1 files changed, 19 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/sat/plugins/plugin_xep_0198.py	Wed Dec 12 08:58:52 2018 +0100
+++ b/sat/plugins/plugin_xep_0198.py	Wed Dec 26 14:37:13 2018 +0100
@@ -59,6 +59,8 @@
 MAX_DELAY_ACK_R = 30
 MAX_COUNTER = 2**32
 RESUME_MAX = 5*60
+# if we don't have an answer to ACK REQUEST after this delay, connection is aborted
+ACK_R_TIMEOUT = 25
 
 
 class ProfileSessionData(object):
@@ -77,6 +79,9 @@
         self.buffer_idx = 0
         self._enabled = False
         self.timer = None
+        # time used when doing a ack request
+        # when it times out, connection is aborted
+        self.req_timer = None
         self.callback_data = (callback, kw)
 
     @property
@@ -230,8 +235,12 @@
 
     def requestAck(self, client):
         """Send a request element"""
+        session = client._xep_0198_session
         r_elt = domish.Element((NS_SM, 'r'))
         client.send(r_elt)
+        if session.req_timer is not None:
+            raise exceptions.InternalError("req_timer should not be set")
+        session.req_timer = reactor.callLater(ACK_R_TIMEOUT, self.onAckTimeOut, client)
 
     def _connectionFailed(self, failure_, connector):
         normal_host, normal_port = connector.normal_location
@@ -404,6 +413,11 @@
     def onAckAnswer(self, a_elt, client):
         session = client._xep_0198_session
         session.ack_requested = False
+        if session.req_timer is None:
+            log.error("reg_timer should be set")
+        else:
+            session.req_timer.cancel()
+            session.req_timer = None
         try:
             server_acked = int(a_elt['h'])
         except ValueError:
@@ -421,6 +435,11 @@
         self.updateBuffer(session, server_acked)
         self.checkAcks(client)
 
+    def onAckTimeOut(self, client):
+        """Called when a requested ACK has not been received in time"""
+        log.info(_(u"Ack was not received in time, aborting connection"))
+        client.xmlstream.transport.abortConnection()
+
 
 class XEP_0198_handler(xmlstream.XMPPHandler):
     implements(iwokkel.IDisco)