SRV records are now properly supported (swich to another SRV record when first one is not available)

This commit is contained in:
Yann Leboulanger 2005-11-04 08:19:15 +00:00
parent e0bf58cba7
commit e8069e56ad
1 changed files with 63 additions and 26 deletions

View File

@ -30,6 +30,8 @@ import traceback
import threading import threading
import select import select
import socket import socket
import random
random.seed()
import signal import signal
if os.name != 'nt': if os.name != 'nt':
signal.signal(signal.SIGPIPE, signal.SIG_DFL) signal.signal(signal.SIGPIPE, signal.SIG_DFL)
@ -1415,6 +1417,30 @@ class Connection:
elif event == common.xmpp.transports.DATA_SENT: elif event == common.xmpp.transports.DATA_SENT:
self.dispatch('STANZA_SENT', unicode(data)) self.dispatch('STANZA_SENT', unicode(data))
def select_next_host(self, hosts):
hosts_best_prio = []
best_prio = 65535
sum_weight = 0
for h in hosts:
if h['prio'] < best_prio:
hosts_best_prio = [h]
best_prio = h['prio']
sum_weight = h['weight']
elif h['prio'] == best_prio:
hosts_best_prio.append(h)
sum_weight += h['weight']
if len(hosts_best_prio) == 1:
return hosts_best_prio[0]
r = random.randint(0, sum_weight)
min_w = sum_weight
# We return the one for which has the minimum weight and weight >= r
for h in hosts_best_prio:
if h['weight'] >= r:
if h['weight'] <= min_w:
min_w = h['weight']
to_return = h
return h
def connect(self, data = None): def connect(self, data = None):
"""Connect and authenticate to the Jabber server """Connect and authenticate to the Jabber server
Returns connection, and connection type ('tls', 'ssl', 'tcp', '') Returns connection, and connection type ('tls', 'ssl', 'tcp', '')
@ -1480,36 +1506,47 @@ class Connection:
p = custom_p p = custom_p
use_srv = False use_srv = False
hosts = []
# SRV resolver # SRV resolver
if use_srv and (HAVE_DNSPYTHON or HAVE_PYDNS): if use_srv and (HAVE_DNSPYTHON or HAVE_PYDNS):
possible_queries = ['_xmpp-client._tcp.' + h] query = '_xmpp-client._tcp.' + h
try:
for query in possible_queries: if HAVE_DNSPYTHON:
try: answers = [x for x in dns.resolver.query(query, 'SRV')]
if HAVE_DNSPYTHON: if answers:
answers = [x for x in dns.resolver.query(query, 'SRV')] for a in answers:
if answers: hosts.append({'host': str(a.target),
h = str(answers[0].target) 'port': int(a.port),
p = int(answers[0].port) 'prio': int(a.priority),
break 'weight': int(a.weight)})
elif HAVE_PYDNS: elif HAVE_PYDNS:
# ensure we haven't cached an old configuration # ensure we haven't cached an old configuration
DNS.ParseResolvConf() DNS.ParseResolvConf()
response = DNS.Request().req(query, qtype = 'SRV') response = DNS.Request().req(query, qtype = 'SRV')
answers = response.answers answers = response.answers
if len(answers) > 0: if len(answers) > 0:
# ignore the priority and weight for now # ignore the priority and weight for now
_t, _t, p, h = answers[0]['data'] for a in answers:
del _t prio, weight, port, host = answers[0]['data']
p = int(p) hosts.append({'host': host,
break 'port': port,
except: 'prio': prio,
gajim.log.debug('An error occurred while looking up %s' % query) 'weight': weight})
except:
gajim.log.debug('An error occurred while looking up %s' % query)
# end of SRV resolver # end of SRV resolver
con_type = con.connect((h, p), proxy = proxy, secure = secur) if len(hosts) == 0: # SRV fails or misconfigred on the server
if not self.connected: # We went offline during connecting process hosts = [ {'host': h, 'port': p, 'prio': 10, 'weight': 10} ]
return None, ''
con_type = None
while len(hosts) and not con_type:
host = self.select_next_host(hosts)
con_type = con.connect((host['host'], host['port']), proxy = proxy,
secure = secur)
if not self.connected: # We went offline during connecting process
return None, ''
hosts.remove(host)
if not con_type: if not con_type:
gajim.log.debug('Could not connect to %s' % h) gajim.log.debug('Could not connect to %s' % h)
if not self.retrycount: if not self.retrycount: