Socket: Try all resolved addresses before scheduling a reconnect

Instead of assuming the first address returned from getaddrinfo can be
reached, try each one in turn until a connection is established.

Signed-off-by: James McCoy <jamessan@users.sourceforge.net>
This commit is contained in:
James McCoy 2013-08-22 23:43:09 -04:00
parent 88e4f73777
commit 5b329df6f0
1 changed files with 50 additions and 36 deletions

View File

@ -1,6 +1,6 @@
### ###
# Copyright (c) 2002-2004, Jeremiah Fincher # Copyright (c) 2002-2004, Jeremiah Fincher
# Copyright (c) 2010, James McCoy # Copyright (c) 2010, 2013, James McCoy
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@ -35,6 +35,7 @@ Contains simple socket drivers. Asyncore bugged (haha, pun!) me.
from __future__ import division from __future__ import division
import time import time
import errno
import select import select
import socket import socket
@ -163,43 +164,56 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
else: else:
drivers.log.debug('Not resetting %s.', self.irc) drivers.log.debug('Not resetting %s.', self.irc)
server = self._getNextServer() server = self._getNextServer()
host = server[0]
address = None
drivers.log.connect(self.currentServer) drivers.log.connect(self.currentServer)
try: for addrinfo in socket.getaddrinfo(server[0], None,
self.conn = utils.net.getSocket(server[0]) socket.AF_UNSPEC,
if self.networkGroup.get('ssl').value: socket.SOCK_STREAM):
if ssl: address = addrinfo[4][0]
self.plainconn = self.conn try:
self.conn = ssl.wrap_socket(self.conn) self.conn = socket.socket(addrinfo[0], addrinfo[1])
else: if self.networkGroup.get('ssl').value:
drivers.log.error('ssl module not available, ' if ssl:
'cannot connect to SSL servers.') self.plainconn = self.conn
return self.conn = ssl.wrap_socket(self.conn)
vhost = conf.supybot.protocols.irc.vhost() else:
self.conn.bind((vhost, 0)) drivers.log.error('ssl module not available, '
except socket.error, e: 'cannot connect to SSL servers.')
drivers.log.connectError(self.currentServer, e) return
vhost = conf.supybot.protocols.irc.vhost()
self.conn.bind((vhost, 0))
except socket.error, e:
msg = host
if host != address:
msg = '%s (%s)' % (host, address)
drivers.log.connectError(msg, e)
continue
# We allow more time for the connect here, since it might take longer.
# At least 10 seconds.
self.conn.settimeout(max(10, conf.supybot.drivers.poll()*10))
try:
self.conn.connect((addrinfo[4][0], server[1]))
self.conn.settimeout(conf.supybot.drivers.poll())
self.connected = True
self.resetDelay()
break
except socket.error, e:
if e.args[0] == errno.EINPROGRESS:
now = time.time()
when = now + 60
whenS = log.timestamp(when)
drivers.log.debug('Connection in progress, scheduling '
'connectedness check for %s', whenS)
self.writeCheckTime = when
break
msg = host
if host != address:
msg = '%s (%s)' % (host, address)
drivers.log.connectError(msg, e)
continue
if not self.connected:
self.scheduleReconnect() self.scheduleReconnect()
return
# We allow more time for the connect here, since it might take longer.
# At least 10 seconds.
self.conn.settimeout(max(10, conf.supybot.drivers.poll()*10))
try:
self.conn.connect(server)
self.conn.settimeout(conf.supybot.drivers.poll())
self.connected = True
self.resetDelay()
except socket.error, e:
if e.args[0] == 115:
now = time.time()
when = now + 60
whenS = log.timestamp(when)
drivers.log.debug('Connection in progress, scheduling '
'connectedness check for %s', whenS)
self.writeCheckTime = when
else:
drivers.log.connectError(self.currentServer, e)
self.scheduleReconnect()
return
def _checkAndWriteOrReconnect(self): def _checkAndWriteOrReconnect(self):
self.writeCheckTime = None self.writeCheckTime = None