diff --git a/src/common/zeroconf/client_zeroconf.py b/src/common/zeroconf/client_zeroconf.py index 25f620419..266f406aa 100644 --- a/src/common/zeroconf/client_zeroconf.py +++ b/src/common/zeroconf/client_zeroconf.py @@ -99,10 +99,11 @@ class ZeroconfListener(IdleObject): ipaddr = sock[1][0] for jid in self.conn_holder.getRoster().keys(): entry = self.conn_holder.getRoster().getItem(jid) - if (entry['address'] == ipaddr): - from_jid = jid - break - P2PClient(sock[0], ipaddr, sock[1][1], self.conn_holder, [], from_jid) + for address in entry['addresses']: + if (address['address'] == ipaddr): + from_jid = jid + break + P2PClient(sock[0], [{'host': ipaddr, 'address': ipaddr, 'port': sock[1][1]}], self.conn_holder, [], from_jid) def disconnect(self, message=''): """ @@ -128,7 +129,7 @@ class ZeroconfListener(IdleObject): return _sock class P2PClient(IdleObject): - def __init__(self, _sock, host, port, conn_holder, stanzaqueue, to=None, + def __init__(self, _sock, addresses, conn_holder, stanzaqueue, to=None, on_ok=None, on_not_ok=None): self._owner = self self.Namespace = 'jabber:client' @@ -140,7 +141,7 @@ class P2PClient(IdleObject): self.conn_holder = conn_holder self.stanzaqueue = stanzaqueue self.to = to - self.Server = host + #self.Server = addresses[0]['host'] self.on_ok = on_ok self.on_not_ok = on_not_ok self.Connection = None @@ -150,8 +151,9 @@ class P2PClient(IdleObject): else: self.sock_type = TYPE_CLIENT self.fd = -1 - conn = P2PConnection('', _sock, host, port, self._caller, + conn = P2PConnection('', _sock, addresses, self._caller, self.on_connect, self) + self.Server = conn.host # set Server to the last host name / address tried if not self.conn_holder: # An error occured, disconnect() has been called if on_not_ok: @@ -159,7 +161,7 @@ class P2PClient(IdleObject): return self.sock_hash = conn._sock.__hash__ self.fd = conn.fd - self.conn_holder.add_connection(self, self.Server, port, self.to) + self.conn_holder.add_connection(self, self.Server, conn.port, self.to) # count messages in queue for val in self.stanzaqueue: stanza, is_message = val @@ -328,7 +330,7 @@ class P2PClient(IdleObject): nbxmpp.NS_JINGLE) class P2PConnection(IdleObject, PlugIn): - def __init__(self, sock_hash, _sock, host=None, port=None, caller=None, + def __init__(self, sock_hash, _sock, addresses=None, caller=None, on_connect=None, client=None): IdleObject.__init__(self) self._owner = client @@ -338,7 +340,7 @@ class P2PConnection(IdleObject, PlugIn): self.buff_is_message = False self._sock = _sock self.sock_hash = None - self.host, self.port = host, port + self.addresses = addresses self.on_connect = on_connect self.client = client self.writable = False @@ -346,6 +348,8 @@ class P2PConnection(IdleObject, PlugIn): self._exported_methods = [self.send, self.disconnect, self.onreceive] self.on_receive = None if _sock: + self.host = addresses[0]['host'] + self.port = addresses[0]['port'] self._sock = _sock self.state = 1 self._sock.setblocking(False) @@ -353,17 +357,26 @@ class P2PConnection(IdleObject, PlugIn): self.on_connect(self) else: self.state = 0 - try: - self.ais = socket.getaddrinfo(host, port, socket.AF_UNSPEC, - socket.SOCK_STREAM) - except socket.gaierror as e: - log.info('Lookup failure for %s: %s', host, str(e), - exc_info=True) - else: - self.connect_to_next_ip() + self.addresses_ = self.addresses + self.get_next_addrinfo() + + def get_next_addrinfo(self): + address = self.addresses_.pop(0) + self.host = address['host'] + self.port = address['port'] + try: + self.ais = socket.getaddrinfo(address['host'], address['port'], socket.AF_UNSPEC, + socket.SOCK_STREAM) + except socket.gaierror as e: + log.info('Lookup failure for %s: %s[%s]', host, e[1], + repr(e[0]), exc_info=True) + if len(self.addresses_) > 0: return self.get_next_addrinfo() + else: + self.connect_to_next_ip() def connect_to_next_ip(self): if len(self.ais) == 0: + if len(self.addresses_) > 0: return self.get_next_addrinfo() log.error('Connection failure to %s', str(self.host), exc_info=True) self.disconnect() return @@ -748,9 +761,13 @@ class ClientZeroconf: on_ok(id_) return - if item['address'] in self.ip_to_hash: - hash_ = self.ip_to_hash[item['address']] - if self.hash_to_port[hash_] == item['port']: + the_address = None + for address in item['addresses']: + if address['address'] in self.ip_to_hash: + the_address = address + if the_address and the_address['address'] in self.ip_to_hash: + hash_ = self.ip_to_hash[the_address['address']] + if self.hash_to_port[hash_] == the_address['port']: conn = self.connections[hash_] id_ = stanza.getID() or '' if conn.add_stanza(stanza, is_message): @@ -761,7 +778,10 @@ class ClientZeroconf: # otherwise open new connection if not stanza.getID(): stanza.setID('zero') - P2PClient(None, item['address'], item['port'], self, + addresses_ = [] + for address in item['addresses']: + addresses_ += [{'host': address['address'], 'address': address['address'], 'port': address['port']}] + P2PClient(None, addresses_, self, [(stanza, is_message)], to, on_ok=on_ok, on_not_ok=on_not_ok) def getAnID(self): @@ -807,10 +827,15 @@ class ClientZeroconf: conn = None if to in self.recipient_to_hash: conn = self.connections[self.recipient_to_hash[to]] - elif item and item['address'] in self.ip_to_hash: - hash_ = self.ip_to_hash[item['address']] - if self.hash_to_port[hash_] == item['port']: - conn = self.connections[hash_] + elif item: + the_address = None + for address in item['addresses']: + if address['address'] in self.ip_to_hash: + the_address = address + if the_address and the_address['address'] in self.ip_to_hash: + hash_ = self.ip_to_hash[the_address['address']] + if self.hash_to_port[hash_] == the_address['port']: + conn = self.connections[hash_] if func: conn.Dispatcher.on_responses[_waitid] = (func, args) conn.onreceive(conn.Dispatcher._WaitForData) diff --git a/src/common/zeroconf/roster_zeroconf.py b/src/common/zeroconf/roster_zeroconf.py index fe32392ae..ac88e9565 100644 --- a/src/common/zeroconf/roster_zeroconf.py +++ b/src/common/zeroconf/roster_zeroconf.py @@ -56,8 +56,14 @@ class Roster: if not contact: return - resolved_info = contact[zeroconf.C_RESOLVED_INFO] - host, aprotocol, address, port = resolved_info[0][zeroconf.C_RI_HOST:zeroconf.C_RI_PORT+1] + addresses = [] + i = 0 + for ri in contact[zeroconf.C_RESOLVED_INFO]: + addresses += [{}] + addresses[i]['host'] = ri[zeroconf.C_RI_HOST] + addresses[i]['address'] = ri[zeroconf.C_RI_ADDRESS] + addresses[i]['port'] = ri[zeroconf.C_RI_PORT] + i += 1 txt = contact[zeroconf.C_TXT] self._data[jid]={} @@ -65,9 +71,7 @@ class Roster: self._data[jid]['subscription'] = 'both' self._data[jid]['groups'] = [] self._data[jid]['resources'] = {} - self._data[jid]['address'] = address - self._data[jid]['host'] = host - self._data[jid]['port'] = port + self._data[jid]['addresses'] = addresses txt_dict = self.zeroconf.txt_array_to_dict(txt) status = txt_dict.get('status', '') if not status: