diff --git a/src/common/connection.py b/src/common/connection.py index 0f3ea14f6aff641503bcc8784109efbbb8f21f59..c96316d51e1ab8e936cf84358187388a28d15d75 100644 --- a/src/common/connection.py +++ b/src/common/connection.py @@ -368,6 +368,15 @@ class Connection(ConnectionHandlers): self._hosts = [i for i in result_array] self.connect_to_next_host() + def on_proxy_failure(self, reason): + log.debug('Connection to proxy failed') + self.time_to_reconnect = None + self.on_connect_failure = None + self.disconnect(on_purpose = True) + self.dispatch('STATUS', 'offline') + self.dispatch('CONNECTION_LOST', + (_('Connection to proxy failed'), reason)) + def connect_to_next_host(self, retry = False): if len(self._hosts): if self.last_connection: @@ -377,10 +386,12 @@ class Connection(ConnectionHandlers): if gajim.verbose: con = common.xmpp.NonBlockingClient(self._hostname, caller = self, on_connect = self.on_connect_success, + on_proxy_failure = self.on_proxy_failure, on_connect_failure = self.connect_to_next_host) else: con = common.xmpp.NonBlockingClient(self._hostname, debug = [], caller = self, on_connect = self.on_connect_success, + on_proxy_failure = self.on_proxy_failure, on_connect_failure = self.connect_to_next_host) self.last_connection = con # increase default timeout for server responses @@ -397,7 +408,6 @@ class Connection(ConnectionHandlers): log.info("Connecting to %s: [%s:%d]", self.name, host['host'], host['port']) con.connect((host['host'], host['port']), proxy = self._proxy, secure = self._secure) - return else: if not retry and self.retrycount == 0: log.debug("Out of hosts, giving up connecting to %s", self.name) diff --git a/src/common/xmpp/client_nb.py b/src/common/xmpp/client_nb.py index f946bcfc0d393b0b2ab551991894e38a3c1738f6..6d3a852db4c048ed8cf279e8d26e39126d02e9f1 100644 --- a/src/common/xmpp/client_nb.py +++ b/src/common/xmpp/client_nb.py @@ -32,7 +32,7 @@ from client import * class NBCommonClient(CommonClient): ''' Base for Client and Component classes.''' def __init__(self, server, port=5222, debug=['always', 'nodebuilder'], caller=None, - on_connect=None, on_connect_failure=None): + on_connect=None, on_proxy_failure=None, on_connect_failure=None): ''' Caches server name and (optionally) port to connect to. "debug" parameter specifies the debug IDs that will go into debug output. You can either specifiy an "include" or "exclude" list. The latter is done via adding "always" pseudo-ID to the list. @@ -65,6 +65,7 @@ class NBCommonClient(CommonClient): self.idlequeue = None self.socket = None self.on_connect = on_connect + self.on_proxy_failure = on_proxy_failure self.on_connect_failure = on_connect_failure def set_idlequeue(self, idlequeue): @@ -108,14 +109,17 @@ class NBCommonClient(CommonClient): if proxy.has_key('type'): type_ = proxy['type'] if type_ == 'socks5': - self.socket = transports_nb.NBSOCKS5PROXYsocket(self._on_connected, + self.socket = transports_nb.NBSOCKS5PROXYsocket( + self._on_connected, self._on_proxy_failure, self._on_connected_failure, proxy, server) elif type_ == 'http': self.socket = transports_nb.NBHTTPPROXYsocket(self._on_connected, - self._on_connected_failure, proxy, server) + self._on_proxy_failure, self._on_connected_failure, proxy, + server) else: self.socket = transports_nb.NBHTTPPROXYsocket(self._on_connected, - self._on_connected_failure, proxy, server) + self._on_proxy_failure, self._on_connected_failure, proxy, + server) else: self.connected = 'tcp' self.socket = transports_nb.NonBlockingTcp(self._on_connected, @@ -127,6 +131,10 @@ class NBCommonClient(CommonClient): self.on_stream_start = on_stream_start self.onreceive(self._on_receive_document_attrs) + def _on_proxy_failure(self, reason): + if self.on_proxy_failure: + self.on_proxy_failure(reason) + def _on_connected_failure(self, retry = None): if self.socket: self.socket.disconnect() diff --git a/src/common/xmpp/transports_nb.py b/src/common/xmpp/transports_nb.py index 4f90e21b8d4f2418560f9cbfefddb905c5e074a5..15355689d3dd93a6c2affd8163b1c49cef483727 100644 --- a/src/common/xmpp/transports_nb.py +++ b/src/common/xmpp/transports_nb.py @@ -374,7 +374,10 @@ class NonBlockingTcp(PlugIn, IdleObject): self.state = -2 self.sendqueue = None self.remove_timeout() - self._owner.disconnected() + try: + self._owner.disconnected() + except: + pass self.idlequeue.unplug_idle(self.fd) sock = getattr(self, '_sock', None) if sock: @@ -609,7 +612,10 @@ class NonBlockingTcp(PlugIn, IdleObject): def getName(self): ''' Return the server's name, or 'getHost()' if not available.''' retval = None - retval = gattr(self._owner, 'name') + try: + retval = gattr(self._owner, 'name') + except: + pass if retval: return retval return self.getHost() @@ -834,12 +840,13 @@ class NBHTTPPROXYsocket(NonBlockingTcp): (optionally) simple authentication (using login and password). ''' - def __init__(self, on_connect =None, on_connect_failure = None,proxy = None,server = None,use_srv=True): + def __init__(self, on_connect =None, on_proxy_failure=None, on_connect_failure = None,proxy = None,server = None,use_srv=True): ''' Caches proxy and target addresses. 'proxy' argument is a dictionary with mandatory keys 'host' and 'port' (proxy address) and optional keys 'user' and 'password' to use for authentication. 'server' argument is a tuple of host and port - just like TCPsocket uses. ''' self.on_connect_proxy = on_connect + self.on_proxy_failure = on_proxy_failure self.on_connect_failure = on_connect_failure NonBlockingTcp.__init__(self, self._on_tcp_connect, on_connect_failure, server, use_srv) self.DBG_LINE=DBG_CONNECT_PROXY @@ -881,10 +888,12 @@ class NBHTTPPROXYsocket(NonBlockingTcp): except: log.error("_on_headers_sent:", exc_info=True) #traceback.print_exc() - raise error('Invalid proxy reply') + self.on_proxy_failure('Invalid proxy reply') + return if code <> '200': self.DEBUG('Invalid proxy reply: %s %s %s' % (proto, code, desc),'error') self._owner.disconnected() + self.on_proxy_failure('Invalid proxy reply') return if len(reply) != 2: pass @@ -893,9 +902,11 @@ class NBHTTPPROXYsocket(NonBlockingTcp): def _on_proxy_auth(self, reply): if self.reply.find('\n\n') == -1: if reply is None: - return + self.on_proxy_failure('Proxy authentification failed') + return if reply.find('\n\n') == -1: self.reply += reply.replace('\r', '') + self.on_proxy_failure('Proxy authentification failed') return self.DEBUG('Authentification successfull. Jabber server contacted.','ok') if self.on_connect_proxy: @@ -910,14 +921,15 @@ class NBSOCKS5PROXYsocket(NonBlockingTcp): redefines only connect method. Allows to use SOCKS5 proxies with (optionally) simple authentication (only USERNAME/PASSWORD auth). ''' - def __init__(self, on_connect = None, on_connect_failure = None, - proxy = None, server = None, use_srv = True): + def __init__(self, on_connect = None, on_proxy_failure = None, + on_connect_failure = None, proxy = None, server = None, use_srv = True): ''' Caches proxy and target addresses. 'proxy' argument is a dictionary with mandatory keys 'host' and 'port' (proxy address) and optional keys 'user' and 'password' to use for authentication. 'server' argument is a tuple of host and port - just like TCPsocket uses. ''' self.on_connect_proxy = on_connect + self.on_proxy_failure = on_proxy_failure self.on_connect_failure = on_connect_failure NonBlockingTcp.__init__(self, self._on_tcp_connect, on_connect_failure, server, use_srv) @@ -952,23 +964,31 @@ class NBSOCKS5PROXYsocket(NonBlockingTcp): if reply is None: return if len(reply) != 2: - raise error('Invalid proxy reply') + self.on_proxy_failure('Invalid proxy reply') + return if reply[0] != '\x05': self.DEBUG('Invalid proxy reply', 'error') self._owner.disconnected() + self.on_proxy_failure('Invalid proxy reply') return if reply[1] == '\x00': return self._on_proxy_auth('\x01\x00') elif reply[1] == '\x02': - # TODO: Do authentification + to_send = '\x01' + chr(len(self.proxy['user'])) + self.proxy['user'] +\ + chr(len(self.proxy['password'])) + self.proxy['password'] self.onreceive(self._on_proxy_auth) + self.send(to_send) else: if reply[1] == '\xff': self.DEBUG('Authentification to proxy impossible: no acceptable ' 'auth method', 'error') - else: - self.DEBUG('Invalid proxy reply', 'error') + self._owner.disconnected() + self.on_proxy_failure('Authentification to proxy impossible: no ' + 'acceptable authentification method') + return + self.DEBUG('Invalid proxy reply', 'error') self._owner.disconnected() + self.on_proxy_failure('Invalid proxy reply') return def _on_proxy_auth(self, reply): @@ -977,14 +997,17 @@ class NBSOCKS5PROXYsocket(NonBlockingTcp): if len(reply) != 2: self.DEBUG('Invalid proxy reply', 'error') self._owner.disconnected() - raise error('Invalid proxy reply') + self.on_proxy_failure('Invalid proxy reply') + return if reply[0] != '\x01': self.DEBUG('Invalid proxy reply', 'error') self._owner.disconnected() - raise error('Invalid proxy reply') + self.on_proxy_failure('Invalid proxy reply') + return if reply[1] != '\x00': self.DEBUG('Authentification to proxy failed', 'error') self._owner.disconnected() + self.on_proxy_failure('Authentification to proxy failed') return self.DEBUG('Authentification successfull. Jabber server contacted.','ok') # Request connection @@ -1014,11 +1037,13 @@ class NBSOCKS5PROXYsocket(NonBlockingTcp): if len(reply) < 10: self.DEBUG('Invalid proxy reply', 'error') self._owner.disconnected() - raise error('Invalid proxy reply') + self.on_proxy_failure('Invalid proxy reply') + return if reply[0] != '\x05': self.DEBUG('Invalid proxy reply', 'error') self._owner.disconnected() - raise error('Invalid proxy reply') + self.on_proxy_failure('Invalid proxy reply') + return if reply[1] != "\x00": # Connection failed self._owner.disconnected() @@ -1036,6 +1061,7 @@ class NBSOCKS5PROXYsocket(NonBlockingTcp): else: txt = 'Invalid proxy reply' self.DEBUG(txt, 'error') + self.on_proxy_failure(txt) return # Get the bound address/port elif reply[3] == "\x01": @@ -1045,6 +1071,7 @@ class NBSOCKS5PROXYsocket(NonBlockingTcp): else: self.DEBUG('Invalid proxy reply', 'error') self._owner.disconnected() + self.on_proxy_failure('Invalid proxy reply') return if self.on_connect_proxy: