try all IPs of a given host in case first one fails. Fixes #2958
This commit is contained in:
parent
b936fa4bfe
commit
3aefee4700
|
@ -274,6 +274,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
||||||
# This prevents replug of same object with the same flags
|
# This prevents replug of same object with the same flags
|
||||||
self.writable = True
|
self.writable = True
|
||||||
self.readable = False
|
self.readable = False
|
||||||
|
self.ais = None
|
||||||
|
|
||||||
def plugin(self, owner):
|
def plugin(self, owner):
|
||||||
''' Fire up connection. Return non-empty string on success.
|
''' Fire up connection. Return non-empty string on success.
|
||||||
|
@ -298,43 +299,31 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
||||||
self.renew_send_timeout()
|
self.renew_send_timeout()
|
||||||
|
|
||||||
def connect(self,server=None, proxy = None, secure = None):
|
def connect(self,server=None, proxy = None, secure = None):
|
||||||
''' Try to establish connection. Returns True/False on success/failure. '''
|
''' Try to establish connection. '''
|
||||||
if not server:
|
if not server:
|
||||||
server=self._server
|
server=self._server
|
||||||
else:
|
else:
|
||||||
self._server = server
|
self._server = server
|
||||||
self.printed_error = False
|
self.printed_error = False
|
||||||
self.state = 0
|
self.state = 0
|
||||||
success = False
|
|
||||||
try:
|
try:
|
||||||
for ai in socket.getaddrinfo(server[0],server[1],socket.AF_UNSPEC,socket.SOCK_STREAM):
|
self.set_timeout(CONNECT_TIMEOUT_SECONDS)
|
||||||
try:
|
if len(server) == 2 and type(server[0]) in (str, unicode) and not \
|
||||||
self._sock=socket.socket(*ai[:3])
|
self.ais:
|
||||||
self._sock.setblocking(False)
|
# FIXME: blocks here
|
||||||
self._server=ai[4]
|
self.ais = socket.getaddrinfo(server[0],server[1],socket.AF_UNSPEC,socket.SOCK_STREAM)
|
||||||
success = True
|
log.info('Found IPs: %s', self.ais)
|
||||||
break
|
else:
|
||||||
except:
|
self.ais = (server,)
|
||||||
if sys.exc_value[0] == errno.EINPROGRESS:
|
self.connect_to_next_ip()
|
||||||
success = True
|
return
|
||||||
break
|
|
||||||
#for all errors, we try other addresses
|
|
||||||
continue
|
|
||||||
except socket.gaierror, e:
|
except socket.gaierror, e:
|
||||||
log.info("Lookup failure for %s: %s[%s]", self.getName(), e[1], repr(e[0]), exc_info=True)
|
log.info('Lookup failure for %s: %s[%s]', self.getName(), e[1], repr(e[0]), exc_info=True)
|
||||||
except:
|
except:
|
||||||
log.error("Exception trying to connect to %s:", self.getName(), exc_info=True)
|
log.error('Exception trying to connect to %s:', self.getName(), exc_info=True)
|
||||||
|
|
||||||
if not success:
|
if self.on_connect_failure:
|
||||||
if self.on_connect_failure:
|
self.on_connect_failure()
|
||||||
self.on_connect_failure()
|
|
||||||
return False
|
|
||||||
|
|
||||||
self.fd = self._sock.fileno()
|
|
||||||
self.idlequeue.plug_idle(self, True, False)
|
|
||||||
self.set_timeout(CONNECT_TIMEOUT_SECONDS)
|
|
||||||
self._do_connect()
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _plug_idle(self):
|
def _plug_idle(self):
|
||||||
readable = self.state != 0
|
readable = self.state != 0
|
||||||
|
@ -347,8 +336,9 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
||||||
|
|
||||||
def pollout(self):
|
def pollout(self):
|
||||||
if self.state == 0:
|
if self.state == 0:
|
||||||
return self._do_connect()
|
self.connect_to_next_ip()
|
||||||
return self._do_send()
|
return
|
||||||
|
self._do_send()
|
||||||
|
|
||||||
def plugout(self):
|
def plugout(self):
|
||||||
''' Disconnect from the remote server and unregister self.disconnected method from
|
''' Disconnect from the remote server and unregister self.disconnected method from
|
||||||
|
@ -538,17 +528,20 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
||||||
return
|
return
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _do_connect(self):
|
def connect_to_next_ip(self):
|
||||||
if self.state != 0:
|
if self.state != 0:
|
||||||
return
|
return
|
||||||
self._sock.setblocking(False)
|
if len(self.ais) == 0:
|
||||||
self._send = self._sock.send
|
if self.on_connect_failure:
|
||||||
self._recv = self._sock.recv
|
self.on_connect_failure()
|
||||||
errnum = 0
|
return
|
||||||
|
ai = self.ais.pop(0)
|
||||||
|
log.info('Trying to connect to %s:%s', ai[4][0], ai[4][1])
|
||||||
try:
|
try:
|
||||||
self._sock.connect(self._server)
|
self._sock = socket.socket(*ai[:3])
|
||||||
|
self._server=ai[4]
|
||||||
except socket.error, e:
|
except socket.error, e:
|
||||||
errnum = e[0]
|
errnum, errstr = e
|
||||||
|
|
||||||
# Ignore "Socket already connected".
|
# Ignore "Socket already connected".
|
||||||
# FIXME: This happens when we switch an already
|
# FIXME: This happens when we switch an already
|
||||||
|
@ -559,17 +552,35 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
||||||
|
|
||||||
# 10035 - winsock equivalent of EINPROGRESS
|
# 10035 - winsock equivalent of EINPROGRESS
|
||||||
if errnum not in (errno.EINPROGRESS, 10035) + workaround:
|
if errnum not in (errno.EINPROGRESS, 10035) + workaround:
|
||||||
log.error("_do_connect:", exc_info=True)
|
log.error('Could not connect to %s: %s [%s]', ai[4][0], errnum,
|
||||||
|
errstr, exc_info=True)
|
||||||
#traceback.print_exc()
|
#traceback.print_exc()
|
||||||
|
self.connect_to_next_ip()
|
||||||
|
return
|
||||||
|
self.fd = self._sock.fileno()
|
||||||
|
self.idlequeue.plug_idle(self, True, False)
|
||||||
|
self._send = self._sock.send
|
||||||
|
self._recv = self._sock.recv
|
||||||
|
self._do_connect()
|
||||||
|
|
||||||
|
def _do_connect(self):
|
||||||
|
errnum = 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._sock.connect(self._server)
|
||||||
|
self._sock.setblocking(False)
|
||||||
|
except Exception, ee:
|
||||||
|
(errnum, errstr) = ee
|
||||||
# in progress, or would block
|
# in progress, or would block
|
||||||
if errnum in (errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK):
|
if errnum in (errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK):
|
||||||
|
self.state = 1
|
||||||
return
|
return
|
||||||
# 10056 - already connected, only on win32
|
# 10056 - already connected, only on win32
|
||||||
# code 'WS*' is not available on GNU, so we use its numeric value
|
# code 'WS*' is not available on GNU, so we use its numeric value
|
||||||
elif errnum not in (0, 10056, errno.EISCONN):
|
elif errnum not in (0, 10056, errno.EISCONN):
|
||||||
self.remove_timeout()
|
log.error('Could not connect to %s: %s [%s]', self._server[0], errnum,
|
||||||
if self.on_connect_failure:
|
errstr)
|
||||||
self.on_connect_failure()
|
self.connect_to_next_ip()
|
||||||
return
|
return
|
||||||
self.remove_timeout()
|
self.remove_timeout()
|
||||||
self._owner.Connection=self
|
self._owner.Connection=self
|
||||||
|
@ -579,8 +590,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
||||||
self._plug_idle()
|
self._plug_idle()
|
||||||
if self.on_connect:
|
if self.on_connect:
|
||||||
self.on_connect()
|
self.on_connect()
|
||||||
self.on_connect = None
|
self.on_connect = None
|
||||||
return True
|
|
||||||
|
|
||||||
def send(self, raw_data, now = False):
|
def send(self, raw_data, now = False):
|
||||||
'''Append raw_data to the queue of messages to be send.
|
'''Append raw_data to the queue of messages to be send.
|
||||||
|
|
Loading…
Reference in New Issue