handle proxy errors. fixes #799 (socks5 proxies should now be supported. tests needed)

This commit is contained in:
Yann Leboulanger 2007-02-07 22:05:52 +00:00
parent 56bcc2e1fa
commit cba44a43a1
3 changed files with 65 additions and 20 deletions

View File

@ -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)

View File

@ -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()

View File

@ -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: