1 from protocol import Acks
2 from protocol import NS_STREAM_MGMT
3 import logging
4 log = logging.getLogger('nbxmpp.smacks')
5
7 '''
8 This is Smacks is the Stream Management class. It takes care of requesting
9 and sending acks. Also, it keeps track of the unhandled outgoing stanzas.
10
11 The dispatcher has to be able to access this class to increment the
12 number of handled stanzas
13 '''
14
16 self.con = con
17 self.out_h = 0
18 self.in_h = 0
19 self.uqueue = []
20 self.session_id = None
21 self.resumption = False
22
23 self.max_queue = 5
24 self._owner = None
25 self.resuming = False
26 self.enabled = False
27 self.location = None
28 self.failed_resume = False
29 self.supports_sm = False
30
32 self._owner = owner
33
34 owner.Dispatcher.RegisterNamespace(NS_STREAM_MGMT)
35 owner.Dispatcher.RegisterHandler('enabled', self._neg_response,
36 xmlns=NS_STREAM_MGMT)
37 owner.Dispatcher.RegisterHandler('r', self.send_ack,
38 xmlns=NS_STREAM_MGMT)
39 owner.Dispatcher.RegisterHandler('a', self.check_ack,
40 xmlns=NS_STREAM_MGMT)
41 owner.Dispatcher.RegisterHandler('resumed', self.check_ack,
42 xmlns=NS_STREAM_MGMT)
43 owner.Dispatcher.RegisterHandler('failed', self.error_handling,
44 xmlns=NS_STREAM_MGMT)
45
47 r = stanza.getAttr('resume')
48 if r == 'true' or r == 'True' or r == '1':
49 self.resumption = True
50 self.session_id = stanza.getAttr('id')
51 if r == 'false' or r == 'False' or r == '0':
52 self.negociate(False)
53 l = stanza.getAttr('location')
54 if l:
55 self.location = l
56 if self.failed_resume:
57 self.con._discover_server_at_connection(self.con.connection)
58 self.failed_resume = False
59
61
62
63 self.uqueue = []
64 self.in_h = 0
65 self.out_h = 0
66 self.session_id = None
67 self.enabled = True
68
69 stanza = Acks()
70 stanza.buildEnable(resume)
71 self._owner.Connection.send(stanza, now=True)
72
74 if not self.session_id:
75 self.resuming = False
76 log.error('Attempted to resume without a valid session id ')
77 return
78 resume = Acks()
79 resume.buildResume(self.in_h, self.session_id)
80 self._owner.Connection.send(resume, False)
81
86
91
93 '''
94 Checks if the number of stanzas sent are the same as the
95 number of stanzas received by the server. Pops stanzas that were
96 handled by the server from the queue.
97 '''
98 h = int(stanza.getAttr('h'))
99 diff = self.out_h - h
100
101 if len(self.uqueue) < diff or diff < 0:
102 log.error('Server and client number of stanzas handled mismatch ')
103 else:
104 while (len(self.uqueue) > diff):
105 self.uqueue.pop(0)
106
107 if stanza.getName() == 'resumed':
108 self.enabled = True
109 self.resuming = True
110 self.con.set_oldst()
111 if self.uqueue != []:
112 for i in self.uqueue:
113 self._owner.Connection.send(i, False)
114
116
117
118 if stanza.getTag('item-not-found'):
119 self.resuming = False
120 self.enabled = False
121
122 self._owner.NonBlockingBind.resuming = False
123 self._owner._on_auth_bind(None)
124 self.failed_resume = True
125 return
126
127
128 if stanza.getTag('feature-not-implemented'):
129 self.negociate(False)
130 return
131
132 if stanza.getTag('unexpected-request'):
133 self.enabled = False
134 log.error('Gajim failed to negociate Stream Management')
135 return
136