annotate sat/plugins/plugin_xep_0198.py @ 3011:93da7c6f8e0c

plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection: Missing one2one messages are now retrieved with MAM on hot reconnection, and buffered ones (which have most probably not been received by the server) are resent at the end of the reconnection workflow. IQ results are not re-sent on hot reconnection, as they don't make sense anymore with a new session. fix 330
author Goffi <goffi@goffi.org>
date Wed, 17 Jul 2019 09:28:35 +0200
parents c8c68a3b0a79
children c9f03b1eb64d
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
1 #!/usr/bin/env python2
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
2 # -*- coding: utf-8 -*-
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
3
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
4 # SàT plugin for managing raw XML log
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
5 # Copyright (C) 2011 Jérôme Poisson (goffi@goffi.org)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
6
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
7 # This program is free software: you can redistribute it and/or modify
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
8 # it under the terms of the GNU Affero General Public License as published by
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
9 # the Free Software Foundation, either version 3 of the License, or
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
10 # (at your option) any later version.
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
11
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
12 # This program is distributed in the hope that it will be useful,
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
15 # GNU Affero General Public License for more details.
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
16
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
17 # You should have received a copy of the GNU Affero General Public License
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
19
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
20 from sat.core.i18n import _
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
21 from sat.core.constants import Const as C
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
22 from sat.core import exceptions
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
23 from sat.core.log import getLogger
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
24 from twisted.words.protocols.jabber import client as jabber_client
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
25 from twisted.words.protocols.jabber import xmlstream
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
26 from twisted.words.xish import domish
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
27 from twisted.internet import defer
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
28 from twisted.internet import task, reactor
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
29 from functools import partial
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
30 from wokkel import disco, iwokkel
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
31 from zope.interface import implements
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
32 import collections
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
33 import time
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
34
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
35 log = getLogger(__name__)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
36
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
37 PLUGIN_INFO = {
3008
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
38 C.PI_NAME: u"Stream Management",
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
39 C.PI_IMPORT_NAME: u"XEP-0198",
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
40 C.PI_TYPE: u"XEP",
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
41 C.PI_MODES: C.PLUG_MODE_BOTH,
3008
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
42 C.PI_PROTOCOLS: [u"XEP-0198"],
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
43 C.PI_DEPENDENCIES: [],
3011
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
44 C.PI_RECOMMENDATIONS: [u"XEP-0045", u"XEP-0313"],
3008
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
45 C.PI_MAIN: u"XEP_0198",
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
46 C.PI_HANDLER: u"yes",
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
47 C.PI_DESCRIPTION: _(u"""Implementation of Stream Management"""),
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
48 }
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
49
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
50 NS_SM = u"urn:xmpp:sm:3"
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
51 SM_ENABLED = '/enabled[@xmlns="' + NS_SM + '"]'
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
52 SM_RESUMED = '/resumed[@xmlns="' + NS_SM + '"]'
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
53 SM_FAILED = '/failed[@xmlns="' + NS_SM + '"]'
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
54 SM_R_REQUEST = '/r[@xmlns="' + NS_SM + '"]'
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
55 SM_A_REQUEST = '/a[@xmlns="' + NS_SM + '"]'
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
56 SM_H_REQUEST = '/h[@xmlns="' + NS_SM + '"]'
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
57 # Max number of stanza to send before requesting ack
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
58 MAX_STANZA_ACK_R = 5
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
59 # Max number of seconds before requesting ack
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
60 MAX_DELAY_ACK_R = 30
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
61 MAX_COUNTER = 2**32
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
62 RESUME_MAX = 5*60
2725
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
63 # if we don't have an answer to ACK REQUEST after this delay, connection is aborted
2729
edd230651138 plugin XEP-0198: rised ACK_TIMEOUT + set req_time to None when timing out to be ready after resuming
Goffi <goffi@goffi.org>
parents: 2727
diff changeset
64 ACK_TIMEOUT = 35
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
65
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
66
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
67 class ProfileSessionData(object):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
68 out_counter = 0
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
69 in_counter = 0
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
70 session_id = None
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
71 location = None
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
72 session_max = None
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
73 # True when an ack answer is expected
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
74 ack_requested = False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
75 last_ack_r = 0
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
76 disconnected_time = None
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
77
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
78 def __init__(self, callback, **kw):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
79 self.buffer = collections.deque()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
80 self.buffer_idx = 0
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
81 self._enabled = False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
82 self.timer = None
2725
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
83 # time used when doing a ack request
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
84 # when it times out, connection is aborted
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
85 self.req_timer = None
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
86 self.callback_data = (callback, kw)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
87
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
88 @property
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
89 def enabled(self):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
90 return self._enabled
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
91
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
92 @enabled.setter
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
93 def enabled(self, enabled):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
94 if enabled:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
95 if self._enabled:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
96 raise exceptions.InternalError(
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
97 u"Stream Management can't be enabled twice")
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
98 self._enabled = True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
99 callback, kw = self.callback_data
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
100 self.timer = task.LoopingCall(callback, **kw)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
101 self.timer.start(MAX_DELAY_ACK_R, now=False)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
102 else:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
103 self._enabled = False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
104 if self.timer is not None:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
105 self.timer.stop()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
106 self.timer = None
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
107
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
108 @property
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
109 def resume_enabled(self):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
110 return self.session_id is not None
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
111
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
112 def reset(self):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
113 self.enabled = False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
114 self.buffer.clear()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
115 self.buffer_idx = 0
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
116 self.in_counter = self.out_counter = 0
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
117 self.session_id = self.location = None
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
118 self.ack_requested = False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
119 self.last_ack_r = 0
2865
9213c6dff48d plugin XEP-0198: reset req_timer on session.reset():
Goffi <goffi@goffi.org>
parents: 2796
diff changeset
120 if self.req_timer is not None:
9213c6dff48d plugin XEP-0198: reset req_timer on session.reset():
Goffi <goffi@goffi.org>
parents: 2796
diff changeset
121 if self.req_timer.active():
9213c6dff48d plugin XEP-0198: reset req_timer on session.reset():
Goffi <goffi@goffi.org>
parents: 2796
diff changeset
122 log.error(u"req_timer has been called/cancelled but not reset")
9213c6dff48d plugin XEP-0198: reset req_timer on session.reset():
Goffi <goffi@goffi.org>
parents: 2796
diff changeset
123 else:
9213c6dff48d plugin XEP-0198: reset req_timer on session.reset():
Goffi <goffi@goffi.org>
parents: 2796
diff changeset
124 self.req_timer.cancel()
9213c6dff48d plugin XEP-0198: reset req_timer on session.reset():
Goffi <goffi@goffi.org>
parents: 2796
diff changeset
125 self.req_timer = None
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
126
3011
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
127 def getBufferCopy(self):
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
128 return list(self.buffer)
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
129
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
130
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
131 class XEP_0198(object):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
132 # FIXME: location is not handled yet
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
133
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
134 def __init__(self, host):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
135 log.info(_("Plugin Stream Management initialization"))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
136 self.host = host
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
137 host.registerNamespace(u'sm', NS_SM)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
138 host.trigger.add("stream_hooks", self.addHooks)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
139 host.trigger.add("xml_init", self._XMLInitTrigger)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
140 host.trigger.add("disconnecting", self._disconnectingTrigger)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
141 host.trigger.add("disconnected", self._disconnectedTrigger)
2727
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
142 try:
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
143 self._ack_timeout = int(host.memory.getConfig("", "ack_timeout", ACK_TIMEOUT))
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
144 except ValueError:
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
145 log.error(_(u"Invalid ack_timeout value, please check your configuration"))
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
146 self._ack_timeout = ACK_TIMEOUT
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
147 if not self._ack_timeout:
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
148 log.info(_(u"Ack timeout disabled"))
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
149 else:
2729
edd230651138 plugin XEP-0198: rised ACK_TIMEOUT + set req_time to None when timing out to be ready after resuming
Goffi <goffi@goffi.org>
parents: 2727
diff changeset
150 log.info(_(u"Ack timeout set to {timeout}s").format(
2727
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
151 timeout=self._ack_timeout))
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
152
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
153 def profileConnecting(self, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
154 client._xep_0198_session = ProfileSessionData(callback=self.checkAcks,
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
155 client=client)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
156
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
157 def getHandler(self, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
158 return XEP_0198_handler(self)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
159
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
160 def addHooks(self, client, receive_hooks, send_hooks):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
161 """Add hooks to handle in/out stanzas counters"""
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
162 receive_hooks.append(partial(self.onReceive, client=client))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
163 send_hooks.append(partial(self.onSend, client=client))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
164 return True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
165
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
166 def _XMLInitTrigger(self, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
167 """Enable or resume a stream mangement"""
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
168 if not (NS_SM, u'sm') in client.xmlstream.features:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
169 log.warning(_(
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
170 u"Your server doesn't support stream management ({namespace}), this is "
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
171 u"used to improve connection problems detection (like network outages). "
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
172 u"Please ask your server administrator to enable this feature.".format(
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
173 namespace=NS_SM)))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
174 return True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
175 session = client._xep_0198_session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
176
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
177 # a disconnect timer from a previous disconnection may still be active
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
178 try:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
179 disconnect_timer = session.disconnect_timer
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
180 except AttributeError:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
181 pass
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
182 else:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
183 if disconnect_timer.active():
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
184 disconnect_timer.cancel()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
185 del session.disconnect_timer
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
186
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
187 if session.resume_enabled:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
188 # we are resuming a session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
189 resume_elt = domish.Element((NS_SM, 'resume'))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
190 resume_elt['h'] = unicode(session.in_counter)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
191 resume_elt['previd'] = session.session_id
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
192 client.send(resume_elt)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
193 session.resuming = True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
194 # session.enabled will be set on <resumed/> reception
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
195 return False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
196 else:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
197 # we start a new session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
198 assert session.out_counter == 0
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
199 enable_elt = domish.Element((NS_SM, 'enable'))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
200 enable_elt[u'resume'] = u'true'
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
201 client.send(enable_elt)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
202 session.enabled = True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
203 return True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
204
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
205 def _disconnectingTrigger(self, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
206 session = client._xep_0198_session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
207 if session.enabled:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
208 self.sendAck(client)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
209 # This is a requested disconnection, so we can reset the session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
210 # to disable resuming and close normally the stream
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
211 session.reset()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
212 return True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
213
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
214 def _disconnectedTrigger(self, client, reason):
2796
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
215 if client.is_component:
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
216 return True
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
217 session = client._xep_0198_session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
218 session.enabled = False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
219 if session.resume_enabled:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
220 session.disconnected_time = time.time()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
221 session.disconnect_timer = reactor.callLater(session.session_max,
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
222 client.disconnectProfile,
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
223 reason)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
224 # disconnectProfile must not be called at this point
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
225 # because session can be resumed
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
226 return False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
227 else:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
228 return True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
229
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
230 def checkAcks(self, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
231 """Request ack if needed"""
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
232 session = client._xep_0198_session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
233 # log.debug("checkAcks (in_counter={}, out_counter={}, buf len={}, buf idx={})"
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
234 # .format(session.in_counter, session.out_counter, len(session.buffer),
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
235 # session.buffer_idx))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
236 if session.ack_requested or not session.buffer:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
237 return
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
238 if (session.out_counter - session.buffer_idx >= MAX_STANZA_ACK_R
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
239 or time.time() - session.last_ack_r >= MAX_DELAY_ACK_R):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
240 self.requestAck(client)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
241 session.ack_requested = True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
242 session.last_ack_r = time.time()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
243
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
244 def updateBuffer(self, session, server_acked):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
245 """Update buffer and buffer_index"""
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
246 if server_acked > session.buffer_idx:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
247 diff = server_acked - session.buffer_idx
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
248 for i in xrange(diff):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
249 session.buffer.pop()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
250 session.buffer_idx += diff
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
251
3011
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
252 def replayBuffer(self, client, buffer_, discard_results=False):
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
253 """Resend all stanza in buffer
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
254
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
255 @param buffer_(collection.deque, list): buffer to replay
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
256 the buffer will be cleared by this method
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
257 @param discard_results(bool): if True, don't replay IQ result stanzas
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
258 """
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
259 while True:
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
260 try:
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
261 stanza = buffer_.pop()
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
262 except IndexError:
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
263 break
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
264 else:
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
265 if ((discard_results
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
266 and stanza.name == u'iq'
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
267 and stanza.getAttribute(u'type') == 'result')):
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
268 continue
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
269 client.send(stanza)
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
270
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
271 def sendAck(self, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
272 """Send an answer element with current IN counter"""
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
273 a_elt = domish.Element((NS_SM, 'a'))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
274 a_elt['h'] = unicode(client._xep_0198_session.in_counter)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
275 client.send(a_elt)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
276
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
277 def requestAck(self, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
278 """Send a request element"""
2725
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
279 session = client._xep_0198_session
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
280 r_elt = domish.Element((NS_SM, 'r'))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
281 client.send(r_elt)
2725
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
282 if session.req_timer is not None:
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
283 raise exceptions.InternalError("req_timer should not be set")
2727
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
284 if self._ack_timeout:
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
285 session.req_timer = reactor.callLater(self._ack_timeout, self.onAckTimeOut,
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
286 client)
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
287
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
288 def _connectionFailed(self, failure_, connector):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
289 normal_host, normal_port = connector.normal_location
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
290 del connector.normal_location
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
291 log.warning(_(
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
292 u"Connection failed using location given by server (host: {host}, port: "
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
293 u"{port}), switching to normal host and port (host: {normal_host}, port: "
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
294 u"{normal_port})".format(host=connector.host, port=connector.port,
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
295 normal_host=normal_host, normal_port=normal_port)))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
296 connector.host, connector.port = normal_host, normal_port
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
297 connector.connectionFailed = connector.connectionFailed_ori
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
298 del connector.connectionFailed_ori
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
299 return connector.connectionFailed(failure_)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
300
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
301 def onEnabled(self, enabled_elt, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
302 session = client._xep_0198_session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
303 session.in_counter = 0
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
304
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
305 # we check that resuming is possible and that we have a session id
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
306 resume = C.bool(enabled_elt.getAttribute(u'resume'))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
307 session_id = enabled_elt.getAttribute(u'id')
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
308 if not session_id:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
309 log.warning(_(u'Incorrect <enabled/> element received, no "id" attribute'))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
310 if not resume or not session_id:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
311 log.warning(_(
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
312 u"You're server doesn't support session resuming with stream management, "
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
313 u"please contact your server administrator to enable it"))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
314 return
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
315
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
316 session.session_id = session_id
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
317
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
318 # XXX: we disable resource binding, which must not be done
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
319 # when we resume the session.
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
320 client.factory.authenticator.res_binding = False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
321
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
322 # location, in case server want resuming session to be elsewhere
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
323 try:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
324 location = enabled_elt[u'location']
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
325 except KeyError:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
326 pass
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
327 else:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
328 # TODO: handle IPv6 here (in brackets, cf. XEP)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
329 try:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
330 domain, port = location.split(':', 1)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
331 port = int(port)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
332 except ValueError:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
333 log.warning(_(u"Invalid location received: {location}")
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
334 .format(location=location))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
335 else:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
336 session.location = (domain, port)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
337 # we monkey patch connector to use the new location
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
338 connector = client.xmlstream.transport.connector
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
339 connector.normal_location = connector.host, connector.port
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
340 connector.host = domain
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
341 connector.port = port
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
342 connector.connectionFailed_ori = connector.connectionFailed
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
343 connector.connectionFailed = partial(self._connectionFailed,
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
344 connector=connector)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
345
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
346 # resuming time
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
347 try:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
348 max_s = int(enabled_elt[u'max'])
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
349 except (ValueError, KeyError) as e:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
350 if isinstance(e, ValueError):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
351 log.warning(_(u'Invalid "max" attribute'))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
352 max_s = RESUME_MAX
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
353 log.info(_(u"Using default session max value ({max_s} s).".format(
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
354 max_s=max_s)))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
355 log.info(_(u"Stream Management enabled"))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
356 else:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
357 log.info(_(
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
358 u"Stream Management enabled, with a resumption time of {res_m} min"
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
359 .format(res_m = max_s/60)))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
360 session.session_max = max_s
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
361
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
362 def onResumed(self, enabled_elt, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
363 session = client._xep_0198_session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
364 assert not session.enabled
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
365 del session.resuming
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
366 server_acked = int(enabled_elt['h'])
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
367 self.updateBuffer(session, server_acked)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
368 resend_count = len(session.buffer)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
369 # we resend all stanza which have not been received properly
3011
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
370 self.replayBuffer(client, session.buffer)
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
371 # now we can continue the session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
372 session.enabled = True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
373 d_time = time.time() - session.disconnected_time
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
374 log.info(_(u"Stream session resumed (disconnected for {d_time} s, {count} "
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
375 u"stanza(s) resent)").format(d_time=int(d_time), count=resend_count))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
376
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
377 def onFailed(self, failed_elt, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
378 session = client._xep_0198_session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
379 condition_elt = failed_elt.firstChildElement()
3011
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
380 buffer_ = session.getBufferCopy()
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
381 session.reset()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
382
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
383 try:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
384 del session.resuming
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
385 except AttributeError:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
386 # stream management can't be started at all
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
387 msg = _(u"Can't use stream management")
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
388 if condition_elt is None:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
389 log.error(msg + u'.')
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
390 else:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
391 log.error(_(u"{msg}: {reason}").format(
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
392 msg=msg, reason=condition_elt.name))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
393 else:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
394 # only stream resumption failed, we can try full session init
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
395 # XXX: we try to start full session init from this point, with many
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
396 # variables/attributes already initialised with a potentially different
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
397 # jid. This is experimental and may not be safe. It may be more
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
398 # secured to abord the connection and restart everything with a fresh
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
399 # client.
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
400 msg = _(u"stream resumption not possible, restarting full session")
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
401
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
402 if condition_elt is None:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
403 log.warning(u'{msg}.'.format(msg=msg))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
404 else:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
405 log.warning(u"{msg}: {reason}".format(
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
406 msg=msg, reason=condition_elt.name))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
407 # stream resumption failed, but we still can do normal stream management
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
408 # we restore attributes as if the session was new, and init stream
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
409 # we keep everything initialized, and only do binding, roster request
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
410 # and initial presence sending.
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
411 if client.conn_deferred.called:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
412 client.conn_deferred = defer.Deferred()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
413 else:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
414 log.error(u"conn_deferred should be called at this point")
3008
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
415 plg_0045 = self.host.plugins.get(u'XEP-0045')
3011
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
416 plg_0313 = self.host.plugins.get(u'XEP-0313')
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
417
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
418 # FIXME: we should call all loaded plugins with generic callbacks
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
419 # (e.g. prepareResume and resume), so a hot resuming can be done
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
420 # properly for all plugins.
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
421
3008
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
422 if plg_0045 is not None:
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
423 # we have to remove joined rooms
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
424 muc_join_args = plg_0045.popRooms(client)
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
425 # we need to recreate roster
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
426 client.handlers.remove(client.roster)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
427 client.roster = client.roster.__class__(self.host)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
428 client.roster.setHandlerParent(client)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
429 # bind init is not done when resuming is possible, so we have to do it now
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
430 bind_init = jabber_client.BindInitializer(client.xmlstream)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
431 bind_init.required = True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
432 d = bind_init.start()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
433 # we set the jid, which may have changed
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
434 d.addCallback(lambda __: setattr(client.factory.authenticator, "jid", client.jid))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
435 # we call the trigger who will send the <enable/> element
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
436 d.addCallback(lambda __: self._XMLInitTrigger(client))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
437 # then we have to re-request the roster, as changes may have occured
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
438 d.addCallback(lambda __: client.roster.requestRoster())
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
439 # we add got_roster to be sure to have roster before sending initial presence
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
440 d.addCallback(lambda __: client.roster.got_roster)
3011
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
441 if plg_0313 is not None:
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
442 # we retrieve one2one MAM archives
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
443 d.addCallback(lambda __: plg_0313.resume(client))
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
444 # initial presence must be sent manually
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
445 d.addCallback(lambda __: client.presence.available())
3008
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
446 if plg_0045 is not None:
3011
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
447 # we re-join MUC rooms
3008
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
448 muc_d_list = defer.DeferredList(
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
449 [plg_0045.join(*args) for args in muc_join_args])
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
450 d.addCallback(lambda __: muc_d_list)
3011
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
451 # at the end we replay the buffer, as those stanzas have probably not
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
452 # been received
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
453 d.addCallback(lambda __: self.replayBuffer(client, buffer_,
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
454 discard_results=True))
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
455
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
456 def onReceive(self, element, client):
2796
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
457 if not client.is_component:
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
458 session = client._xep_0198_session
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
459 if session.enabled and element.name.lower() in C.STANZA_NAMES:
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
460 session.in_counter += 1 % MAX_COUNTER
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
461
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
462 def onSend(self, obj, client):
2796
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
463 if not client.is_component:
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
464 session = client._xep_0198_session
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
465 if (session.enabled
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
466 and domish.IElement.providedBy(obj)
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
467 and obj.name.lower() in C.STANZA_NAMES):
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
468 session.out_counter += 1 % MAX_COUNTER
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
469 session.buffer.appendleft(obj)
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
470 self.checkAcks(client)
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
471
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
472 def onAckRequest(self, r_elt, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
473 self.sendAck(client)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
474
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
475 def onAckAnswer(self, a_elt, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
476 session = client._xep_0198_session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
477 session.ack_requested = False
2727
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
478 if self._ack_timeout:
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
479 if session.req_timer is None:
3008
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
480 log.error("req_timer should be set")
2727
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
481 else:
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
482 session.req_timer.cancel()
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
483 session.req_timer = None
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
484 try:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
485 server_acked = int(a_elt['h'])
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
486 except ValueError:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
487 log.warning(_(u"Server returned invalid ack element, disabling stream "
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
488 u"management: {xml}").format(xml=a_elt))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
489 session.enabled = False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
490 return
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
491
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
492 if server_acked > session.out_counter:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
493 log.error(_(u"Server acked more stanzas than we have sent, disabling stream "
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
494 u"management."))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
495 session.reset()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
496 return
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
497
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
498 self.updateBuffer(session, server_acked)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
499 self.checkAcks(client)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
500
2725
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
501 def onAckTimeOut(self, client):
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
502 """Called when a requested ACK has not been received in time"""
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
503 log.info(_(u"Ack was not received in time, aborting connection"))
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
504 client.xmlstream.transport.abortConnection()
2795
25639611c303 plugin XEP-0198: fixed typo resulting in a crash on resume
Goffi <goffi@goffi.org>
parents: 2729
diff changeset
505 client._xep_0198_session.req_timer = None
2725
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
506
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
507
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
508 class XEP_0198_handler(xmlstream.XMPPHandler):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
509 implements(iwokkel.IDisco)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
510
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
511 def __init__(self, plugin_parent):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
512 self.plugin_parent = plugin_parent
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
513 self.host = plugin_parent.host
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
514
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
515 def connectionInitialized(self):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
516 self.xmlstream.addObserver(
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
517 SM_ENABLED, self.plugin_parent.onEnabled, client=self.parent
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
518 )
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
519 self.xmlstream.addObserver(
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
520 SM_RESUMED, self.plugin_parent.onResumed, client=self.parent
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
521 )
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
522 self.xmlstream.addObserver(
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
523 SM_FAILED, self.plugin_parent.onFailed, client=self.parent
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
524 )
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
525 self.xmlstream.addObserver(
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
526 SM_R_REQUEST, self.plugin_parent.onAckRequest, client=self.parent
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
527 )
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
528 self.xmlstream.addObserver(
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
529 SM_A_REQUEST, self.plugin_parent.onAckAnswer, client=self.parent
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
530 )
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
531
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
532 def getDiscoInfo(self, requestor, target, nodeIdentifier=""):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
533 return [disco.DiscoFeature(NS_SM)]
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
534
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
535 def getDiscoItems(self, requestor, target, nodeIdentifier=""):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
536 return []