fix FT proxy testing. We needed a receiver to connect to proxy to really test it

This commit is contained in:
Yann Leboulanger 2008-08-27 13:11:46 +00:00
parent 95b6855aa3
commit 9618bb77a4
2 changed files with 180 additions and 45 deletions

View file

@ -834,7 +834,10 @@ class ConnectionDisco:
track, self.name) track, self.name)
break break
if features.__contains__(common.xmpp.NS_BYTESTREAM): if features.__contains__(common.xmpp.NS_BYTESTREAM):
gajim.proxy65_manager.resolve(jid, self.connection, self.name) our_jid = helpers.parse_jid(gajim.get_jid_from_account(self.name) +\
'/' + self.server_resource)
gajim.proxy65_manager.resolve(jid, self.connection, our_jid,
self.name)
if features.__contains__(common.xmpp.NS_MUC) and is_muc: if features.__contains__(common.xmpp.NS_MUC) and is_muc:
type_ = transport_type or 'jabber' type_ = transport_type or 'jabber'
self.muc_jid[type_] = jid self.muc_jid[type_] = jid
@ -2242,10 +2245,12 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
def discover_ft_proxies(self): def discover_ft_proxies(self):
cfg_proxies = gajim.config.get_per('accounts', self.name, cfg_proxies = gajim.config.get_per('accounts', self.name,
'file_transfer_proxies') 'file_transfer_proxies')
our_jid = helpers.parse_jid(gajim.get_jid_from_account(self.name) + '/' +\
self.server_resource)
if cfg_proxies: if cfg_proxies:
proxies = map(lambda e:e.strip(), cfg_proxies.split(',')) proxies = map(lambda e:e.strip(), cfg_proxies.split(','))
for proxy in proxies: for proxy in proxies:
gajim.proxy65_manager.resolve(proxy, self.connection) gajim.proxy65_manager.resolve(proxy, self.connection, our_jid)
def _on_roster_set(self, roster): def _on_roster_set(self, roster):
raw_roster = roster.getRaw() raw_roster = roster.getRaw()

View file

@ -49,24 +49,24 @@ class Proxy65Manager:
self.proxies = {} self.proxies = {}
# dict {account: proxy} default proxy for account # dict {account: proxy} default proxy for account
self.default_proxies = {} self.default_proxies = {}
def resolve(self, proxy, connection, default = None): def resolve(self, proxy, connection, sender_jid, default=None):
''' start ''' ''' start '''
if self.proxies.has_key(proxy): if self.proxies.has_key(proxy):
resolver = self.proxies[proxy] resolver = self.proxies[proxy]
else: else:
# proxy is being ressolved for the first time # proxy is being ressolved for the first time
resolver = ProxyResolver(proxy) resolver = ProxyResolver(proxy, sender_jid)
self.proxies[proxy] = resolver self.proxies[proxy] = resolver
resolver.add_connection(connection) resolver.add_connection(connection)
if default: if default:
# add this proxy as default for account # add this proxy as default for account
self.default_proxies[default] = proxy self.default_proxies[default] = proxy
def disconnect(self, connection): def disconnect(self, connection):
for resolver in self.proxies.values(): for resolver in self.proxies.values():
resolver.disconnect(connection) resolver.disconnect(connection)
def resolve_result(self, proxy, query): def resolve_result(self, proxy, query):
if not self.proxies.has_key(proxy): if not self.proxies.has_key(proxy):
return return
@ -79,18 +79,18 @@ class Proxy65Manager:
self.proxies[proxy].resolve_result(host, port, jid) self.proxies[proxy].resolve_result(host, port, jid)
# we can have only one streamhost # we can have only one streamhost
raise common.xmpp.NodeProcessed raise common.xmpp.NodeProcessed
def error_cb(self, proxy, query): def error_cb(self, proxy, query):
sid = query.getAttr('sid') sid = query.getAttr('sid')
for resolver in self.proxies.values(): for resolver in self.proxies.values():
if resolver.sid == sid: if resolver.sid == sid:
resolver.keep_conf() resolver.keep_conf()
break break
def get_default_for_name(self, account): def get_default_for_name(self, account):
if self.default_proxies.has_key(account): if self.default_proxies.has_key(account):
return self.default_proxies[account] return self.default_proxies[account]
def get_proxy(self, proxy, account): def get_proxy(self, proxy, account):
if self.proxies.has_key(proxy): if self.proxies.has_key(proxy):
resolver = self.proxies[proxy] resolver = self.proxies[proxy]
@ -101,42 +101,53 @@ class Proxy65Manager:
class ProxyResolver: class ProxyResolver:
def resolve_result(self, host, port, jid): def resolve_result(self, host, port, jid):
''' test if host has a real proxy65 listening on port ''' ''' test if host has a real proxy65 listening on port '''
self.host = unicode(host) self.host = str(host)
self.port = int(port) self.port = int(port)
self.jid = unicode(jid) self.jid = unicode(jid)
self.state = S_RESOLVED self.state = S_RESOLVED
self.host_tester = HostTester(self.host, self.port, self.jid, self.receiver_tester = ReceiverTester(self.host, self.port, self.jid,
self._on_connect_success, self._on_connect_failure) self.sid, self.sender_jid, self._on_receiver_success,
self.host_tester.connect() self._on_connect_failure)
self.receiver_tester.connect()
def _on_receiver_success(self):
self.host_tester = HostTester(self.host, self.port, self.jid,
self.sid, self.sender_jid, self._on_connect_success,
self._on_connect_failure)
self.host_tester.connect()
def _on_connect_success(self): def _on_connect_success(self):
iq = common.xmpp.Protocol(name = 'iq', to = self.jid, typ = 'set') iq = common.xmpp.Protocol(name='iq', to=self.jid, typ='set')
query = iq.setTag('query') query = iq.setTag('query')
query.setNamespace(common.xmpp.NS_BYTESTREAM) query.setNamespace(common.xmpp.NS_BYTESTREAM)
query.setAttr('sid', self.sid) query.setAttr('sid', self.sid)
activate = query.setTag('activate') activate = query.setTag('activate')
activate.setData(self.jid + "/" + self.sid) activate.setData('test@gajim.org/test2')
if self.active_connection: if self.active_connection:
self.active_connection.send(iq) self.active_connection.SendAndCallForResponse(iq, self.keep_conf)
self.state = S_ACTIVATED self.state = S_ACTIVATED
else: else:
self.state = S_INITIAL self.state = S_INITIAL
def keep_conf(self): def keep_conf(self, data=None):
self.disconnect(self.active_connection)
self.state = S_FINISHED self.state = S_FINISHED
def _on_connect_failure(self): def _on_connect_failure(self):
self.state = S_FINISHED self.state = S_FINISHED
self.host = None self.host = None
self.port = 0 self.port = 0
self.jid = None self.jid = None
def disconnect(self, connection): def disconnect(self, connection):
if self.host_tester: if self.host_tester:
self.host_tester.disconnect() self.host_tester.disconnect()
self.host_tester = None self.host_tester = None
if self.receiver_tester:
self.receiver_tester.disconnect()
self.receiver_tester = None
try: try:
self.connections.remove(connection) self.connections.remove(connection)
except ValueError: except ValueError:
@ -146,42 +157,44 @@ class ProxyResolver:
if self.state != S_FINISHED: if self.state != S_FINISHED:
self.state = S_INITIAL self.state = S_INITIAL
self.try_next_connection() self.try_next_connection()
def try_next_connection(self): def try_next_connection(self):
''' try to resolve proxy with the next possible connection ''' ''' try to resolve proxy with the next possible connection '''
if self.connections: if self.connections:
connection = self.connections.pop(0) connection = self.connections.pop(0)
self.start_resolve(connection) self.start_resolve(connection)
def add_connection(self, connection): def add_connection(self, connection):
''' add a new connection in case the first fails ''' ''' add a new connection in case the first fails '''
self.connections.append(connection) self.connections.append(connection)
if self.state == S_INITIAL: if self.state == S_INITIAL:
self.start_resolve(connection) self.start_resolve(connection)
def start_resolve(self, connection): def start_resolve(self, connection):
''' request network address from proxy ''' ''' request network address from proxy '''
self.state = S_STARTED self.state = S_STARTED
self.active_connection = connection self.active_connection = connection
iq = common.xmpp.Protocol(name = 'iq', to = self.proxy, typ = 'get') iq = common.xmpp.Protocol(name='iq', to=self.proxy, typ='get')
query = iq.setTag('query') query = iq.setTag('query')
query.setNamespace(common.xmpp.NS_BYTESTREAM) query.setNamespace(common.xmpp.NS_BYTESTREAM)
connection.send(iq) connection.send(iq)
def __init__(self, proxy): def __init__(self, proxy, sender_jid):
self.proxy = proxy self.proxy = proxy
self.state = S_INITIAL self.state = S_INITIAL
self.active_connection = None self.active_connection = None
self.connections = [] self.connections = []
self.host_tester = None self.host_tester = None
self.receiver_tester = None
self.jid = None self.jid = None
self.host = None self.host = None
self.port = None self.port = None
self.sid = helpers.get_random_string_16() self.sid = helpers.get_random_string_16()
self.sender_jid = sender_jid
class HostTester(Socks5, IdleObject): class HostTester(Socks5, IdleObject):
''' fake proxy tester. ''' ''' fake proxy tester. '''
def __init__(self, host, port, jid, on_success, on_failure): def __init__(self, host, port, jid, sid, sender_jid, on_success, on_failure):
''' try to establish and auth to proxy at (host, port) ''' try to establish and auth to proxy at (host, port)
call on_success, or on_failure according to the result''' call on_success, or on_failure according to the result'''
self.host = host self.host = host
@ -190,9 +203,12 @@ class HostTester(Socks5, IdleObject):
self.on_success = on_success self.on_success = on_success
self.on_failure = on_failure self.on_failure = on_failure
self._sock = None self._sock = None
self.file_props = {} self.file_props = {'is_a_proxy': True,
'proxy_sender': sender_jid,
'proxy_receiver': 'test@gajim.org/test2'}
Socks5.__init__(self, gajim.idlequeue, host, port, None, None, None) Socks5.__init__(self, gajim.idlequeue, host, port, None, None, None)
self.sid = sid
def connect(self): def connect(self):
''' create the socket and plug it to the idlequeue ''' ''' create the socket and plug it to the idlequeue '''
if self.host is None: if self.host is None:
@ -206,15 +222,15 @@ class HostTester(Socks5, IdleObject):
self.do_connect() self.do_connect()
self.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT) self.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT)
return None return None
def read_timeout(self): def read_timeout(self):
self.idlequeue.remove_timeout(self.fd) self.idlequeue.remove_timeout(self.fd)
self.pollend() self.pollend()
def pollend(self): def pollend(self):
self.disconnect() self.disconnect()
self.on_failure() self.on_failure()
def pollout(self): def pollout(self):
self.idlequeue.remove_timeout(self.fd) self.idlequeue.remove_timeout(self.fd)
if self.state == 0: if self.state == 0:
@ -229,7 +245,7 @@ class HostTester(Socks5, IdleObject):
# unplug and plug for reading # unplug and plug for reading
gajim.idlequeue.plug_idle(self, False, True) gajim.idlequeue.plug_idle(self, False, True)
gajim.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT) gajim.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT)
def pollin(self): def pollin(self):
self.idlequeue.remove_timeout(self.fd) self.idlequeue.remove_timeout(self.fd)
if self.state == 2: if self.state == 2:
@ -246,17 +262,20 @@ class HostTester(Socks5, IdleObject):
version, method = struct.unpack('!BB', buff[:2]) version, method = struct.unpack('!BB', buff[:2])
if version != 0x05 or method == 0xff: if version != 0x05 or method == 0xff:
self.pollend() self.pollend()
self.disconnect() return
data = self._get_request_buff(self._get_sha1_auth())
self.send_raw(data)
self.state += 1
elif self.state == 3:
self.on_success() self.on_success()
else: self.state += 1
self.disconnect()
def do_connect(self): def do_connect(self):
try: try:
self._sock.connect((self.host, self.port)) self._sock.connect((self.host, self.port))
self._sock.setblocking(False) self._sock.setblocking(False)
self._send=self._sock.send self._send = self._sock.send
self._recv=self._sock.recv self._recv = self._sock.recv
except Exception, ee: except Exception, ee:
(errnum, errstr) = ee (errnum, errstr) = ee
# 56 is for freebsd # 56 is for freebsd
@ -270,12 +289,123 @@ class HostTester(Socks5, IdleObject):
return return
# socket is already connected # socket is already connected
self._sock.setblocking(False) self._sock.setblocking(False)
self._send=self._sock.send self._send = self._sock.send
self._recv=self._sock.recv self._recv = self._sock.recv
self.buff = ''
self.state = 1 # connected
self.idlequeue.plug_idle(self, True, False)
return
class ReceiverTester(Socks5, IdleObject):
''' fake proxy tester. '''
def __init__(self, host, port, jid, sid, sender_jid, on_success, on_failure):
''' try to establish and auth to proxy at (host, port)
call on_success, or on_failure according to the result'''
self.host = host
self.port = port
self.jid = jid
self.on_success = on_success
self.on_failure = on_failure
self._sock = None
self.file_props = {'is_a_proxy': True,
'proxy_sender': sender_jid,
'proxy_receiver': 'test@gajim.org/test2'}
Socks5.__init__(self, gajim.idlequeue, host, port, None, None, None)
self.sid = sid
def connect(self):
''' create the socket and plug it to the idlequeue '''
if self.host is None:
self.on_failure()
return None
self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._sock.setblocking(False)
self.fd = self._sock.fileno()
self.state = 0 # about to be connected
gajim.idlequeue.plug_idle(self, True, False)
self.do_connect()
self.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT)
return None
def read_timeout(self):
self.idlequeue.remove_timeout(self.fd)
self.pollend()
def pollend(self):
self.disconnect()
self.on_failure()
def pollout(self):
self.idlequeue.remove_timeout(self.fd)
if self.state == 0:
self.do_connect()
return
elif self.state == 1: # send initially: version and auth types
data = self._get_auth_buff()
self.send_raw(data)
else:
return
self.state += 1
# unplug and plug for reading
gajim.idlequeue.plug_idle(self, False, True)
gajim.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT)
def pollin(self):
self.idlequeue.remove_timeout(self.fd)
if self.state in (2, 3):
self.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT)
# begin negotiation. on success 'address' != 0
buff = self.receive()
if buff == '':
# end connection
self.pollend()
return
if self.state == 2:
# read auth response
if buff is None or len(buff) != 2:
return None
version, method = struct.unpack('!BB', buff[:2])
if version != 0x05 or method == 0xff:
self.pollend()
return
data = self._get_request_buff(self._get_sha1_auth())
self.send_raw(data)
self.state += 1
elif self.state == 3:
# read connect response
if buff is None or len(buff) < 2:
return None
version, reply = struct.unpack('!BB', buff[:2])
if version != 0x05 or reply != 0x00:
self.pollend()
return
self.on_success()
self.state += 1
def do_connect(self):
try:
self._sock.connect((self.host, self.port))
self._sock.setblocking(False)
self._send = self._sock.send
self._recv = self._sock.recv
except Exception, ee:
(errnum, errstr) = ee
# 56 is for freebsd
if errnum in (errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK):
# still trying to connect
return
# win32 needs this
if errnum not in (0, 10056, errno.EISCONN):
# connection failed
self.on_failure()
return
# socket is already connected
self._sock.setblocking(False)
self._send = self._sock.send
self._recv = self._sock.recv
self.buff = '' self.buff = ''
self.state = 1 # connected self.state = 1 # connected
self.idlequeue.plug_idle(self, True, False) self.idlequeue.plug_idle(self, True, False)
return return
# vim: se ts=3: # vim: se ts=3: