handle proxy errors. fixes #799 (socks5 proxies should now be supported. tests needed)
This commit is contained in:
parent
56bcc2e1fa
commit
cba44a43a1
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -374,7 +374,10 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
|||
self.state = -2
|
||||
self.sendqueue = None
|
||||
self.remove_timeout()
|
||||
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
|
||||
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:
|
||||
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._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:
|
||||
|
|
Loading…
Reference in New Issue