From d0adcb1a054321a2e6ceabf0107dc7d86e553fd8 Mon Sep 17 00:00:00 2001 From: Zhenchao Li Date: Sat, 3 Jul 2010 16:22:47 +0800 Subject: [PATCH] dispatch iq-result for a jingle iq stanza, start listener after iq-result on session-initiate. --- src/common/jingle.py | 16 +++++++++++++--- src/common/jingle_ft.py | 28 ++++++++++++++++++++++++++++ src/common/jingle_session.py | 31 +++++++++++++++++++++++++++++-- src/common/protocol/bytestream.py | 3 ++- src/common/socks5.py | 7 +++++++ src/common/stanza_session.py | 2 +- 6 files changed, 80 insertions(+), 7 deletions(-) diff --git a/src/common/jingle.py b/src/common/jingle.py index 2dd933e2f..b63273a7c 100644 --- a/src/common/jingle.py +++ b/src/common/jingle.py @@ -84,16 +84,26 @@ class ConnectionJingle(object): raise xmpp.NodeProcessed jingle = stanza.getTag('jingle') - if not jingle: return - sid = jingle.getAttr('sid') + # a jingle element is not necessary in iq-result stanza + # don't check for that + if jingle: + sid = jingle.getAttr('sid') + else: + sid = None + for sesn in self.__sessions.values(): + if id in sesn.iq_ids: + sesn.on_stanza(stanza) + return # do we need to create a new jingle object if sid not in self.__sessions: #TODO: tie-breaking and other things... - newjingle = JingleSession(con=self, weinitiate=False, jid=jid, sid=sid) + newjingle = JingleSession(con=self, weinitiate=False, jid=jid, + iq_id = id, sid=sid) self.__sessions[sid] = newjingle # we already have such session in dispatcher... + self.__sessions[sid].collect_iq_id(id) self.__sessions[sid].on_stanza(stanza) # Delete invalid/unneeded sessions if sid in self.__sessions and self.__sessions[sid].state == JingleStates.ended: diff --git a/src/common/jingle_ft.py b/src/common/jingle_ft.py index 691dbba4b..ab0d7438e 100644 --- a/src/common/jingle_ft.py +++ b/src/common/jingle_ft.py @@ -23,6 +23,8 @@ import gajim import xmpp from jingle_content import contents, JingleContent from jingle_transport import JingleTransportICEUDP, JingleTransportSocks5 +from common import helpers + import logging log = logging.getLogger('gajim.c.jingle_ft') @@ -42,6 +44,7 @@ class JingleFileTransfer(JingleContent): self.callbacks['transport-replace'] += [self.__on_transport_replace] #fallback transport method self.callbacks['transport-reject'] += [self.__on_transport_reject] self.callbacks['transport-info'] += [self.__on_transport_info] + self.callbacks['iq-result'] += [self.__on_iq_result] self.file_props = file_props if file_props is None: @@ -51,6 +54,7 @@ class JingleFileTransfer(JingleContent): if self.file_props is not None: self.file_props['sender'] = session.ourjid + self.file_props['receiver'] = session.peerjid self.file_props['session-type'] = 'jingle' self.file_props['sid'] = session.sid self.file_props['transfered_size'] = [] @@ -129,6 +133,25 @@ class JingleFileTransfer(JingleContent): def __on_transport_info(self, stanza, content, error, action): log.info("__on_transport_info") + + def __on_iq_result(self, stanza, content, error, action): + log.info("__on_iq_result") + + if self.weinitiate: + receiver = self.file_props['receiver'] + sender = self.file_props['sender'] + + sha_str = helpers.get_auth_sha(self.file_props['sid'], sender, receiver) + self.file_props['sha_str'] = sha_str + + port = gajim.config.get('file_transfers_port') + + listener = gajim.socks5queue.start_listener(port, sha_str, + self._store_socks5_sid, self.file_props['sid']) + + if not listener: + return + # send error message, notify the user def _fill_content(self, content): description_node = xmpp.simplexml.Node(tag=xmpp.NS_JINGLE_FILE_TRANSFER + ' description') @@ -144,6 +167,11 @@ class JingleFileTransfer(JingleContent): description_node.addChild(node=sioffer) content.addChild(node=description_node) + + def _store_socks5_sid(self, sid, hash_id): + # callback from socsk5queue.start_listener + self.file_props['hash'] = hash_id + return def get_content(desc): return JingleFileTransfer diff --git a/src/common/jingle_session.py b/src/common/jingle_session.py index b2e9eb9c1..d0302359d 100644 --- a/src/common/jingle_session.py +++ b/src/common/jingle_session.py @@ -30,6 +30,8 @@ import gajim #Get rid of that? import xmpp from jingle_transport import get_jingle_transport from jingle_content import get_jingle_content, JingleContentSetupException +import logging +log = logging.getLogger("gajim.c.jingle_session") # FIXME: Move it to JingleSession.States? class JingleStates(object): @@ -58,7 +60,7 @@ class JingleSession(object): negotiated between an initiator and a responder. """ - def __init__(self, con, weinitiate, jid, sid=None): + def __init__(self, con, weinitiate, jid, iq_id = None, sid=None): """ con -- connection object, weinitiate -- boolean, are we the initiator? @@ -83,6 +85,14 @@ class JingleSession(object): if not sid: sid = con.connection.getAnID() self.sid = sid # sessionid + + # iq stanza id, used to determine which sessions to summon callback + # later on when iq-result stanza arrives + if iq_id is not None: + self.iq_ids = [iq_id] + else: + self.iq_ids = [] + self.accepted = True # is this session accepted by user @@ -110,10 +120,14 @@ class JingleSession(object): 'transport-replace': [self.__broadcast, self.__on_transport_replace], #TODO 'transport-accept': [self.__ack], #TODO 'transport-reject': [self.__ack], #TODO - 'iq-result': [], + 'iq-result': [self.__broadcast], 'iq-error': [self.__on_error], } + def collect_iq_id(self, iq_id): + if iq_id is not None: + self.iq_ids.append(iq_id) + def approve_session(self): """ Called when user accepts session in UI (when we aren't the initiator) @@ -463,6 +477,17 @@ class JingleSession(object): """ Broadcast the stanza contents to proper content handlers """ + #if jingle is None: # it is a iq-result stanza + # for cn in self.contents.values(): + # cn.on_stanza(stanza, None, error, action) + # return + + # special case: iq-result stanza does not come with a jingle element + if action == 'iq-result': + for cn in self.contents.values(): + cn.on_stanza(stanza, None, error, action) + return + for content in jingle.iterTags('content'): name = content['name'] creator = content['creator'] @@ -606,6 +631,7 @@ class JingleSession(object): self.__append_contents(jingle) self.__broadcast(stanza, jingle, None, 'session-initiate-sent') self.connection.connection.send(stanza) + self.collect_iq_id(stanza.getID()) self.state = JingleStates.pending def __session_accept(self): @@ -614,6 +640,7 @@ class JingleSession(object): self.__append_contents(jingle) self.__broadcast(stanza, jingle, None, 'session-accept-sent') self.connection.connection.send(stanza) + self.collect_iq_id(stanza.getID()) self.state = JingleStates.active def __session_info(self, payload=None): diff --git a/src/common/protocol/bytestream.py b/src/common/protocol/bytestream.py index f75ceca61..69b289125 100644 --- a/src/common/protocol/bytestream.py +++ b/src/common/protocol/bytestream.py @@ -147,7 +147,8 @@ class ConnectionBytestream: if not gajim.socks5queue.get_file_props(session.ourjid, sid): gajim.socks5queue.add_file_props(session.ourjid, file_props) gajim.socks5queue.connect_to_hosts(session.ourjid, sid, - None, None) + lambda streamhost: log.info("connected to" + str(streamhost)), + lambda a, b, c, d: log.info("connect error!" + a + b + c + d)) return iq = xmpp.Iq(to=unicode(file_props['sender']), typ='result') diff --git a/src/common/socks5.py b/src/common/socks5.py index 4d99cdb21..f411dae9f 100644 --- a/src/common/socks5.py +++ b/src/common/socks5.py @@ -35,6 +35,10 @@ from errno import EISCONN from errno import EINPROGRESS from errno import EAFNOSUPPORT from xmpp.idlequeue import IdleObject + +import logging +log = logging.getLogger('gajim.c.socks5') + MAX_BUFF_LEN = 65536 # after foo seconds without activity label transfer as 'stalled' @@ -257,6 +261,7 @@ class SocksQueue: def send_file(self, file_props, account): if 'hash' in file_props and file_props['hash'] in self.senders: + log.info("socks5: sending file") sender = self.senders[file_props['hash']] file_props['streamhost-used'] = True sender.account = account @@ -269,6 +274,8 @@ class SocksQueue: file_props['last-time'] = self.idlequeue.current_time() file_props['received-len'] = 0 sender.file_props = file_props + else: + log.info("socks5: NOT sending file") def add_file_props(self, account, file_props): """ diff --git a/src/common/stanza_session.py b/src/common/stanza_session.py index 028bee596..b4ab7c2dc 100644 --- a/src/common/stanza_session.py +++ b/src/common/stanza_session.py @@ -37,7 +37,7 @@ from hashlib import sha256 from hmac import HMAC from common import crypto -if gajim.HAVE_PYCRYPTO: +if gajim.HAVE_PYCRYPTO and False: from Crypto.Cipher import AES from Crypto.PublicKey import RSA