Name of filetransfer content is now random to be able to have 2 transfer in the same session. send and handle content-add in filetranfer

This commit is contained in:
Yann Leboulanger 2010-08-26 10:36:58 +02:00
parent f03cdbbebf
commit 286d788da0
7 changed files with 64 additions and 53 deletions

View File

@ -48,7 +48,7 @@ class ConnectionJingle(object):
def __init__(self): def __init__(self):
# dictionary: sessionid => JingleSession object # dictionary: sessionid => JingleSession object
self.__sessions = {} self.__sessions__ = {}
# dictionary: (jid, iq stanza id) => JingleSession object, # dictionary: (jid, iq stanza id) => JingleSession object,
# one time callbacks # one time callbacks
@ -58,12 +58,12 @@ class ConnectionJingle(object):
""" """
Remove a jingle session from a jingle stanza dispatcher Remove a jingle session from a jingle stanza dispatcher
""" """
if sid in self.__sessions: if sid in self.__sessions__:
#FIXME: Move this elsewhere? #FIXME: Move this elsewhere?
for content in self.__sessions[sid].contents.values(): for content in self.__sessions__[sid].contents.values():
content.destroy() content.destroy()
self.__sessions[sid].callbacks = [] self.__sessions__[sid].callbacks = []
del self.__sessions[sid] del self.__sessions__[sid]
def _JingleCB(self, con, stanza): def _JingleCB(self, con, stanza):
""" """
@ -91,23 +91,23 @@ class ConnectionJingle(object):
sid = jingle.getAttr('sid') sid = jingle.getAttr('sid')
else: else:
sid = None sid = None
for sesn in self.__sessions.values(): for sesn in self.__sessions__.values():
if id in sesn.iq_ids: if id in sesn.iq_ids:
sesn.on_stanza(stanza) sesn.on_stanza(stanza)
return return
# do we need to create a new jingle object # do we need to create a new jingle object
if sid not in self.__sessions: if sid not in self.__sessions__:
#TODO: tie-breaking and other things... #TODO: tie-breaking and other things...
newjingle = JingleSession(con=self, weinitiate=False, jid=jid, newjingle = JingleSession(con=self, weinitiate=False, jid=jid,
iq_id = id, sid=sid) iq_id = id, sid=sid)
self.__sessions[sid] = newjingle self.__sessions__[sid] = newjingle
# we already have such session in dispatcher... # we already have such session in dispatcher...
self.__sessions[sid].collect_iq_id(id) self.__sessions__[sid].collect_iq_id(id)
self.__sessions[sid].on_stanza(stanza) self.__sessions__[sid].on_stanza(stanza)
# Delete invalid/unneeded sessions # Delete invalid/unneeded sessions
if sid in self.__sessions and self.__sessions[sid].state == JingleStates.ended: if sid in self.__sessions__ and self.__sessions__[sid].state == JingleStates.ended:
self.delete_jingle_session(sid) self.delete_jingle_session(sid)
raise xmpp.NodeProcessed raise xmpp.NodeProcessed
@ -120,7 +120,7 @@ class ConnectionJingle(object):
jingle.add_content('voice', JingleAudio(jingle)) jingle.add_content('voice', JingleAudio(jingle))
else: else:
jingle = JingleSession(self, weinitiate=True, jid=jid) jingle = JingleSession(self, weinitiate=True, jid=jid)
self.__sessions[jingle.sid] = jingle self.__sessions__[jingle.sid] = jingle
jingle.add_content('voice', JingleAudio(jingle)) jingle.add_content('voice', JingleAudio(jingle))
jingle.start_session() jingle.start_session()
return jingle.sid return jingle.sid
@ -133,7 +133,7 @@ class ConnectionJingle(object):
jingle.add_content('video', JingleVideo(jingle)) jingle.add_content('video', JingleVideo(jingle))
else: else:
jingle = JingleSession(self, weinitiate=True, jid=jid) jingle = JingleSession(self, weinitiate=True, jid=jid)
self.__sessions[jingle.sid] = jingle self.__sessions__[jingle.sid] = jingle
jingle.add_content('video', JingleVideo(jingle)) jingle.add_content('video', JingleVideo(jingle))
jingle.start_session() jingle.start_session()
return jingle.sid return jingle.sid
@ -150,24 +150,25 @@ class ConnectionJingle(object):
file_props['sid'] = jingle.sid file_props['sid'] = jingle.sid
c = JingleFileTransfer(jingle, file_props=file_props, c = JingleFileTransfer(jingle, file_props=file_props,
use_security=use_security) use_security=use_security)
jingle.add_content('file', c) jingle.add_content('file' + helpers.get_random_string_16(), c)
jingle.on_session_state_changed(c)
else: else:
jingle = JingleSession(self, weinitiate=True, jid=jid) jingle = JingleSession(self, weinitiate=True, jid=jid)
self.__sessions[jingle.sid] = jingle self.__sessions__[jingle.sid] = jingle
file_props['sid'] = jingle.sid file_props['sid'] = jingle.sid
c = JingleFileTransfer(jingle, file_props=file_props, c = JingleFileTransfer(jingle, file_props=file_props,
use_security=use_security) use_security=use_security)
jingle.add_content('file', c) jingle.add_content('file' + helpers.get_random_string_16(), c)
jingle.start_session() jingle.start_session()
return c.transport.sid return c.transport.sid
def iter_jingle_sessions(self, jid, sid=None, media=None): def iter_jingle_sessions(self, jid, sid=None, media=None):
if sid: if sid:
return (session for session in self.__sessions.values() if session.sid == sid) return (session for session in self.__sessions__.values() if session.sid == sid)
sessions = (session for session in self.__sessions.values() if session.peerjid == jid) sessions = (session for session in self.__sessions__.values() if session.peerjid == jid)
if media: if media:
if media not in ('audio', 'video'): if media not in ('audio', 'video', 'file'):
return tuple() return tuple()
else: else:
return (session for session in sessions if session.get_content(media)) return (session for session in sessions if session.get_content(media))
@ -177,14 +178,14 @@ class ConnectionJingle(object):
def get_jingle_session(self, jid, sid=None, media=None): def get_jingle_session(self, jid, sid=None, media=None):
if sid: if sid:
if sid in self.__sessions: if sid in self.__sessions__:
return self.__sessions[sid] return self.__sessions__[sid]
else: else:
return None return None
elif media: elif media:
if media not in ('audio', 'video'): if media not in ('audio', 'video', 'file'):
return None return None
for session in self.__sessions.values(): for session in self.__sessions__.values():
if session.peerjid == jid and session.get_content(media): if session.peerjid == jid and session.get_content(media):
return session return session

View File

@ -44,6 +44,7 @@ class JingleFileTransfer(JingleContent):
# events we might be interested in # events we might be interested in
self.callbacks['session-initiate'] += [self.__on_session_initiate] self.callbacks['session-initiate'] += [self.__on_session_initiate]
self.callbacks['content-add'] += [self.__on_session_initiate]
self.callbacks['session-accept'] += [self.__on_session_accept] self.callbacks['session-accept'] += [self.__on_session_accept]
self.callbacks['session-terminate'] += [self.__on_session_terminate] self.callbacks['session-terminate'] += [self.__on_session_terminate]
self.callbacks['transport-accept'] += [self.__on_transport_accept] self.callbacks['transport-accept'] += [self.__on_transport_accept]
@ -249,7 +250,7 @@ class JingleFileTransfer(JingleContent):
content = xmpp.Node('content') content = xmpp.Node('content')
content.setAttr('creator', 'initiator') content.setAttr('creator', 'initiator')
content.setAttr('name', 'file') content.setAttr('name', self.name)
transport = xmpp.Node('transport') transport = xmpp.Node('transport')
transport.setNamespace(xmpp.NS_JINGLE_BYTESTREAM) transport.setNamespace(xmpp.NS_JINGLE_BYTESTREAM)

View File

@ -85,14 +85,14 @@ class JingleSession(object):
if not sid: if not sid:
sid = con.connection.getAnID() sid = con.connection.getAnID()
self.sid = sid # sessionid self.sid = sid # sessionid
# iq stanza id, used to determine which sessions to summon callback # iq stanza id, used to determine which sessions to summon callback
# later on when iq-result stanza arrives # later on when iq-result stanza arrives
if iq_id is not None: if iq_id is not None:
self.iq_ids = [iq_id] self.iq_ids = [iq_id]
else: else:
self.iq_ids = [] self.iq_ids = []
self.accepted = True # is this session accepted by user self.accepted = True # is this session accepted by user
@ -127,7 +127,7 @@ class JingleSession(object):
def collect_iq_id(self, iq_id): def collect_iq_id(self, iq_id):
if iq_id is not None: if iq_id is not None:
self.iq_ids.append(iq_id) self.iq_ids.append(iq_id)
def approve_session(self): def approve_session(self):
""" """
Called when user accepts session in UI (when we aren't the initiator) Called when user accepts session in UI (when we aren't the initiator)
@ -340,7 +340,7 @@ class JingleSession(object):
break break
elif child.getNamespace() == xmpp.NS_STANZAS: elif child.getNamespace() == xmpp.NS_STANZAS:
error_name = child.getName() error_name = child.getName()
self.__dispatch_error(error_name, text, error.getAttribute('type')) self.__dispatch_error(error_name, text, error.getAttr('type'))
# FIXME: Not sure when we would want to do that... # FIXME: Not sure when we would want to do that...
def __on_transport_replace(self, stanza, jingle, error, action): def __on_transport_replace(self, stanza, jingle, error, action):
@ -482,13 +482,13 @@ class JingleSession(object):
# for cn in self.contents.values(): # for cn in self.contents.values():
# cn.on_stanza(stanza, None, error, action) # cn.on_stanza(stanza, None, error, action)
# return # return
# special case: iq-result stanza does not come with a jingle element # special case: iq-result stanza does not come with a jingle element
if action == 'iq-result': if action == 'iq-result':
for cn in self.contents.values(): for cn in self.contents.values():
cn.on_stanza(stanza, None, error, action) cn.on_stanza(stanza, None, error, action)
return return
for content in jingle.iterTags('content'): for content in jingle.iterTags('content'):
name = content['name'] name = content['name']
creator = content['creator'] creator = content['creator']
@ -673,7 +673,8 @@ class JingleSession(object):
stanza, jingle = self.__make_jingle('content-add') stanza, jingle = self.__make_jingle('content-add')
self.__append_content(jingle, content) self.__append_content(jingle, content)
self.__broadcast(stanza, jingle, None, 'content-add-sent') self.__broadcast(stanza, jingle, None, 'content-add-sent')
self.connection.connection.send(stanza) id_ = self.connection.connection.send(stanza)
self.collect_iq_id(id_)
def __content_accept(self, content): def __content_accept(self, content):
# TODO: test # TODO: test
@ -681,7 +682,8 @@ class JingleSession(object):
stanza, jingle = self.__make_jingle('content-accept') stanza, jingle = self.__make_jingle('content-accept')
self.__append_content(jingle, content) self.__append_content(jingle, content)
self.__broadcast(stanza, jingle, None, 'content-accept-sent') self.__broadcast(stanza, jingle, None, 'content-accept-sent')
self.connection.connection.send(stanza) id_ = self.connection.connection.send(stanza)
self.collect_iq_id(id_)
def __content_reject(self, content): def __content_reject(self, content):
assert self.state != JingleStates.ended assert self.state != JingleStates.ended

View File

@ -224,6 +224,13 @@ class JingleTransportSocks5(JingleTransport):
proxy_cand.append(c) proxy_cand.append(c)
self.candidates += proxy_cand self.candidates += proxy_cand
def get_content(self):
sesn = self.connection.get_jingle_session(self.ourjid,
self.file_props['session-sid'])
for content in sesn.contents.values():
if content.transport == self:
return content
def _on_proxy_auth_ok(self, proxy): def _on_proxy_auth_ok(self, proxy):
log.info('proxy auth ok for ' + str(proxy)) log.info('proxy auth ok for ' + str(proxy))
# send activate request to proxy, send activated confirmation to peer # send activate request to proxy, send activated confirmation to peer
@ -242,15 +249,15 @@ class JingleTransportSocks5(JingleTransport):
content = xmpp.Node('content') content = xmpp.Node('content')
content.setAttr('creator', 'initiator') content.setAttr('creator', 'initiator')
content.setAttr('name', 'file') c = self.get_content()
content.setAttr('name', c.name)
transport = xmpp.Node('transport') transport = xmpp.Node('transport')
transport.setNamespace(xmpp.NS_JINGLE_BYTESTREAM) transport.setNamespace(xmpp.NS_JINGLE_BYTESTREAM)
activated = xmpp.Node('activated') activated = xmpp.Node('activated')
cid = None cid = None
for host in self.candidates: for host in self.candidates:
if host['host'] == proxy['host'] and \ if host['host'] == proxy['host'] and host['jid'] == proxy['jid'] \
host['jid'] == proxy['jid'] and \ and host['port'] == proxy['port']:
host['port'] == proxy['port']:
cid = host['candidate_id'] cid = host['candidate_id']
break break
if cid is None: if cid is None:

View File

@ -29,7 +29,7 @@ pending_sessions = {} # key-exchange id -> session, accept that session once key
def key_exchange_pend(id, session): def key_exchange_pend(id, session):
pending_sessions[id] = session pending_sessions[id] = session
def approve_pending_session(id): def approve_pending_session(id):
session = pending_sessions[id] session = pending_sessions[id]
session.approve_session() session.approve_session()
@ -45,9 +45,11 @@ if PYOPENSSL_PRESENT:
from OpenSSL import SSL from OpenSSL import SSL
from OpenSSL.SSL import Context from OpenSSL.SSL import Context
from OpenSSL import crypto from OpenSSL import crypto
TYPE_RSA = crypto.TYPE_RSA
TYPE_DSA = crypto.TYPE_DSA
SELF_SIGNED_CERTIFICATE = 'localcert' SELF_SIGNED_CERTIFICATE = 'localcert'
def default_callback(connection, certificate, error_num, depth, return_code): def default_callback(connection, certificate, error_num, depth, return_code):
log.info("certificate: %s" % certificate) log.info("certificate: %s" % certificate)
return return_code return return_code
@ -95,7 +97,7 @@ def get_context(fingerprint, verify_cb=None):
ctx.set_verify(SSL.VERIFY_NONE|SSL.VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb or default_callback) ctx.set_verify(SSL.VERIFY_NONE|SSL.VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb or default_callback)
elif fingerprint == 'client': elif fingerprint == 'client':
ctx.set_verify(SSL.VERIFY_PEER, verify_cb or default_callback) ctx.set_verify(SSL.VERIFY_PEER, verify_cb or default_callback)
cert_name = os.path.join(gajim.MY_CERT_DIR, SELF_SIGNED_CERTIFICATE) cert_name = os.path.join(gajim.MY_CERT_DIR, SELF_SIGNED_CERTIFICATE)
ctx.use_privatekey_file (cert_name + '.pkey') ctx.use_privatekey_file (cert_name + '.pkey')
ctx.use_certificate_file(cert_name + '.cert') ctx.use_certificate_file(cert_name + '.cert')
@ -114,16 +116,16 @@ def send_cert(con, jid_from, sid):
certificate += line certificate += line
iq = common.xmpp.Iq('result', to=jid_from); iq = common.xmpp.Iq('result', to=jid_from);
iq.setAttr('id', sid) iq.setAttr('id', sid)
pubkey = iq.setTag('pubkeys') pubkey = iq.setTag('pubkeys')
pubkey.setNamespace(common.xmpp.NS_PUBKEY_PUBKEY) pubkey.setNamespace(common.xmpp.NS_PUBKEY_PUBKEY)
keyinfo = pubkey.setTag('keyinfo') keyinfo = pubkey.setTag('keyinfo')
name = keyinfo.setTag('name') name = keyinfo.setTag('name')
name.setData('CertificateHash') name.setData('CertificateHash')
cert = keyinfo.setTag('x509cert') cert = keyinfo.setTag('x509cert')
cert.setData(certificate) cert.setData(certificate)
con.send(iq) con.send(iq)
def handle_new_cert(con, obj, jid_from): def handle_new_cert(con, obj, jid_from):
@ -132,18 +134,18 @@ def handle_new_cert(con, obj, jid_from):
certpath += '.cert' certpath += '.cert'
id = obj.getAttr('id') id = obj.getAttr('id')
x509cert = obj.getTag('pubkeys').getTag('keyinfo').getTag('x509cert') x509cert = obj.getTag('pubkeys').getTag('keyinfo').getTag('x509cert')
cert = x509cert.getData() cert = x509cert.getData()
f = open(certpath, 'w') f = open(certpath, 'w')
f.write('-----BEGIN CERTIFICATE-----\n') f.write('-----BEGIN CERTIFICATE-----\n')
f.write(cert) f.write(cert)
f.write('-----END CERTIFICATE-----\n') f.write('-----END CERTIFICATE-----\n')
approve_pending_session(id) approve_pending_session(id)
def send_cert_request(con, to_jid): def send_cert_request(con, to_jid):
iq = common.xmpp.Iq('get', to=to_jid) iq = common.xmpp.Iq('get', to=to_jid)
id = con.connection.getAnID() id = con.connection.getAnID()
@ -155,9 +157,6 @@ def send_cert_request(con, to_jid):
# the following code is partly due to pyopenssl examples # the following code is partly due to pyopenssl examples
TYPE_RSA = crypto.TYPE_RSA
TYPE_DSA = crypto.TYPE_DSA
def createKeyPair(type, bits): def createKeyPair(type, bits):
""" """
Create a public/private key pair. Create a public/private key pair.

View File

@ -148,7 +148,8 @@ class ConnectionBytestream:
jingle_xtls.key_exchange_pend(id_, session) jingle_xtls.key_exchange_pend(id_, session)
return return
session.approve_session() session.approve_session()
session.approve_content('file')
session.approve_content('file')
return return
iq = xmpp.Iq(to=unicode(file_props['sender']), typ='result') iq = xmpp.Iq(to=unicode(file_props['sender']), typ='result')

View File

@ -914,7 +914,7 @@ class Socks5Listener(IdleObject):
# try the different possibilities (ipv6, ipv4, etc.) # try the different possibilities (ipv6, ipv4, etc.)
try: try:
self._serv = socket.socket(*ai[:3]) self._serv = socket.socket(*ai[:3])
if not self.fingerprint is None: if self.fingerprint is not None:
self._serv = OpenSSL.SSL.Connection( self._serv = OpenSSL.SSL.Connection(
jingle_xtls.get_context('server'), self._serv) jingle_xtls.get_context('server'), self._serv)
except socket.error, e: except socket.error, e: