comparison src/plugins/plugin_xep_0260.py @ 1758:a66d34353f34

plugin XEP-0260, XEP-0065: fixed session hash handling: with XEP-0260, we need to manage 2 hashes (one with SHA1(SID + Initiator JID + Responder JID) and the other with SHA1(SID + Responder JID + Initiator JID)). This was not handled correclty, resulting in transfer failure in several cases.
author Goffi <goffi@goffi.org>
date Thu, 17 Dec 2015 22:37:59 +0100
parents abd6d6f89006
children d17772b0fe22
comparison
equal deleted inserted replaced
1757:abd6d6f89006 1758:a66d34353f34
130 client = self.host.getClient(profile) 130 client = self.host.getClient(profile)
131 content_data = session['contents'][content_name] 131 content_data = session['contents'][content_name]
132 transport_data = content_data['transport_data'] 132 transport_data = content_data['transport_data']
133 sid = transport_data['sid'] = unicode(uuid.uuid4()) 133 sid = transport_data['sid'] = unicode(uuid.uuid4())
134 session_hash = transport_data['session_hash'] = self._s5b.getSessionHash(client.jid, session['peer_jid'], sid) 134 session_hash = transport_data['session_hash'] = self._s5b.getSessionHash(client.jid, session['peer_jid'], sid)
135 transport_data['peer_session_hash'] = self._s5b.getSessionHash(session['peer_jid'], client.jid, sid) # requester and target are inversed for peer candidates
135 transport_data['stream_d'] = self._s5b.registerHash(session_hash, None, profile) 136 transport_data['stream_d'] = self._s5b.registerHash(session_hash, None, profile)
136 candidates = transport_data['candidates'] = yield self._s5b.getCandidates(profile) 137 candidates = transport_data['candidates'] = yield self._s5b.getCandidates(profile)
137 mode = 'tcp' # XXX: we only manage tcp for now 138 mode = 'tcp' # XXX: we only manage tcp for now
138 transport_elt = self._buildCandidates(session, candidates, sid, session_hash, client, mode) 139 transport_elt = self._buildCandidates(session, candidates, sid, session_hash, client, mode)
139 140
219 if best_candidate is None or peer_best_candidate is None: 220 if best_candidate is None or peer_best_candidate is None:
220 choosed_candidate = best_candidate or peer_best_candidate 221 choosed_candidate = best_candidate or peer_best_candidate
221 else: 222 else:
222 if best_candidate.priority == peer_best_candidate.priority: 223 if best_candidate.priority == peer_best_candidate.priority:
223 # same priority, we choose initiator one according to XEP-0260 §2.4 #4 224 # same priority, we choose initiator one according to XEP-0260 §2.4 #4
224 log.debug(u"Candidates have same priority, we choose the initiator one") 225 log.debug(u"Candidates have same priority, we select the one choosed by initiator")
225 if session['initiator'] == client.jid: 226 if session['initiator'] == client.jid:
226 choosed_candidate = best_candidate 227 choosed_candidate = best_candidate
227 else: 228 else:
228 choosed_candidate = peer_best_candidate 229 choosed_candidate = peer_best_candidate
229 else: 230 else:
351 elif action == self._j.A_SESSION_ACCEPT: 352 elif action == self._j.A_SESSION_ACCEPT:
352 # initiator side, we select a candidate in the ones sent by responder 353 # initiator side, we select a candidate in the ones sent by responder
353 assert 'peer_candidates' not in transport_data 354 assert 'peer_candidates' not in transport_data
354 transport_data['peer_candidates'] = self._parseCandidates(transport_elt) 355 transport_data['peer_candidates'] = self._parseCandidates(transport_elt)
355 356
356 # elif action == self._j.A_START:
357 elif action == self._j.A_START: 357 elif action == self._j.A_START:
358 session_hash = transport_data['session_hash'] 358 session_hash = transport_data['session_hash']
359 peer_candidates = transport_data['peer_candidates'] 359 peer_candidates = transport_data['peer_candidates']
360 file_obj = content_data['file_obj'] 360 file_obj = content_data['file_obj']
361 self._s5b.associateFileObj(session_hash, file_obj, profile) 361 self._s5b.associateFileObj(session_hash, file_obj, profile)
362 stream_d = transport_data.pop('stream_d') 362 stream_d = transport_data.pop('stream_d')
363 stream_d.chainDeferred(content_data['finished_d']) 363 stream_d.chainDeferred(content_data['finished_d'])
364 d = self._s5b.getBestCandidate(peer_candidates, session_hash, profile) 364 peer_session_hash = transport_data['peer_session_hash']
365 d = self._s5b.getBestCandidate(peer_candidates, session_hash, peer_session_hash, profile)
365 d.addCallback(self._foundPeerCandidate, session, transport_data, content_name, client) 366 d.addCallback(self._foundPeerCandidate, session, transport_data, content_name, client)
366 367
367 elif action == self._j.A_SESSION_INITIATE: 368 elif action == self._j.A_SESSION_INITIATE:
368 # responder side, we select a candidate in the ones sent by initiator 369 # responder side, we select a candidate in the ones sent by initiator
369 # and we give our candidates 370 # and we give our candidates
370 assert 'peer_candidates' not in transport_data 371 assert 'peer_candidates' not in transport_data
371 sid = transport_data['sid'] = transport_elt['sid'] 372 sid = transport_data['sid'] = transport_elt['sid']
372 session_hash = transport_data['session_hash'] = self._s5b.getSessionHash(session['peer_jid'], client.jid, sid) 373 session_hash = transport_data['session_hash'] = self._s5b.getSessionHash(client.jid, session['peer_jid'], sid)
374 peer_session_hash = transport_data['peer_session_hash'] = self._s5b.getSessionHash(session['peer_jid'], client.jid, sid) # requester and target are inversed for peer candidates
373 peer_candidates = transport_data['peer_candidates'] = self._parseCandidates(transport_elt) 375 peer_candidates = transport_data['peer_candidates'] = self._parseCandidates(transport_elt)
374 file_obj = content_data['file_obj'] 376 file_obj = content_data['file_obj']
375 stream_d = self._s5b.registerHash(session_hash, file_obj, profile) 377 stream_d = self._s5b.registerHash(session_hash, file_obj, profile)
376 stream_d.chainDeferred(content_data['finished_d']) 378 stream_d.chainDeferred(content_data['finished_d'])
377 d = self._s5b.getBestCandidate(peer_candidates, session_hash, profile) 379 d = self._s5b.getBestCandidate(peer_candidates, session_hash, peer_session_hash, profile)
378 d.addCallback(self._foundPeerCandidate, session, transport_data, content_name, client) 380 d.addCallback(self._foundPeerCandidate, session, transport_data, content_name, client)
379 candidates = yield self._s5b.getCandidates(profile) 381 candidates = yield self._s5b.getCandidates(profile)
380 # we remove duplicate candidates 382 # we remove duplicate candidates
381 candidates = [candidate for candidate in candidates if candidate not in peer_candidates] 383 candidates = [candidate for candidate in candidates if candidate not in peer_candidates]
382 384
400 break 402 break
401 403
402 if candidate_elt is None: 404 if candidate_elt is None:
403 log.warning(u"Unexpected transport element: {}".format(transport_elt.toXml())) 405 log.warning(u"Unexpected transport element: {}".format(transport_elt.toXml()))
404 elif action == self._j.A_DESTROY: 406 elif action == self._j.A_DESTROY:
405 # the transport is remplaced (fallback ?). We need mainly to stop kill XEP-0065 session 407 # the transport is replaced (fallback ?), We need mainly to kill XEP-0065 session.
406 # note that sid argument is not necessary for sessions created by this plugin 408 # note that sid argument is not necessary for sessions created by this plugin
407 self._s5b.killSession(None, transport_data['session_hash'], None, client) 409 self._s5b.killSession(None, transport_data['session_hash'], None, client)
408 else: 410 else:
409 log.warning(u"FIXME: unmanaged action {}".format(action)) 411 log.warning(u"FIXME: unmanaged action {}".format(action))
410 412