Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions examples/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ def on_service_state_change(zeroconf, service_type, name, state_change):
if state_change is ServiceStateChange.Added:
info = zeroconf.get_service_info(service_type, name)
if info:
print(" Address: %s:%d" % (socket.inet_ntoa(info.address), info.port))
addresses = ["%s:%d" % (socket.inet_ntoa(addr), info.port) for addr in info.addresses]
print(" Addresses: %s" % ", ".join(addresses))
print(" Weight: %d, priority: %d" % (info.weight, info.priority))
print(" Server: %s" % (info.server,))
if info.properties:
print(" Properties are:")
for key, value in info.properties.items():
print(" %s: %s" % (key, value))
print(" %s: %s" % (key.decode("utf-8"), value.decode("utf-8")))
else:
print(" No properties")
else:
Expand Down
32 changes: 32 additions & 0 deletions test_zeroconf.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,38 @@ def on_service_state_change(zeroconf, service_type, state_change, name):
zeroconf_browser.close()


def test_multiple_addresses():
type_ = "_http._tcp.local."
registration_name = "xxxyyy.%s" % type_
desc = {'path': '/~paulsm/'}
address = socket.inet_aton("10.0.1.2")

# Old way
info = ServiceInfo(
type_, registration_name,
address, 80, 0, 0,
desc, "ash-2.local.")

assert not hasattr(info, "address")
assert info.addresses == [address]

# Compatibility way
info = ServiceInfo(
type_, registration_name,
[address, address], 80, 0, 0,
desc, "ash-2.local.")

assert info.addresses == [address, address]

# New kwarg way
info = ServiceInfo(
type_, registration_name,
None, 80, 0, 0,
desc, "ash-2.local.", addresses=[address, address])

assert info.addresses == [address, address]


def test_listener_handles_closed_socket_situation_gracefully():
error = socket.error(socket.EBADF)
error.errno = socket.EBADF
Expand Down
58 changes: 39 additions & 19 deletions zeroconf.py
Original file line number Diff line number Diff line change
Expand Up @@ -1068,24 +1068,42 @@ class ServiceInfo(object):
"""Service information"""

def __init__(self, type, name, address=None, port=None, weight=0,
priority=0, properties=None, server=None):
priority=0, properties=None, server=None, addresses=None):
"""Create a service description.

For backwards compatibility/migration, address will also accept a
list of addresses.

type: fully qualified service type name
name: fully qualified service name
address: IP address as unsigned short, network byte order
address: IP address as unsigned short, network byte order (legacy)
port: port that the service runs on
weight: weight of the service
priority: priority of the service
properties: dictionary of properties (or a string holding the
bytes for the text field)
server: fully qualified name for service host (defaults to name)"""
server: fully qualified name for service host (defaults to name)
addresses: List of IP addresses as unsigned short, network byte
order"""

# Accept both none, or one, but not both.
assert (address is None and addresses is None) or \
(address is None and addresses) or \
(address and addresses is None)

if not name.endswith(type):
raise BadTypeInNameException
self.type = type
self.name = name
self.address = address
if addresses is not None:
self.addresses = addresses
elif address is not None:
if isinstance(address, list):
self.addresses = address
else:
self.addresses = [address]
else:
self.addresses = []
self.port = port
self.weight = weight
self.priority = priority
Expand Down Expand Up @@ -1174,7 +1192,8 @@ def update_record(self, zc, now, record):
if record.type == _TYPE_A:
# if record.name == self.name:
if record.name == self.server:
self.address = record.address
if record.address not in self.addresses:
self.addresses.append(record.address)
elif record.type == _TYPE_SRV:
if record.name == self.name:
self.server = record.server
Expand All @@ -1199,8 +1218,7 @@ def request(self, zc, timeout):
result = False
try:
zc.add_listener(self, DNSQuestion(self.name, _TYPE_ANY, _CLASS_IN))
while (self.server is None or self.address is None or
self.text is None):
while (self.server is None or self.text is None or not self.addresses):
if last <= now:
return False
if next <= now:
Expand Down Expand Up @@ -1440,9 +1458,9 @@ def register_service(self, info, ttl=_DNS_TTL):
info.server), 0)
out.add_answer_at_time(DNSText(info.name, _TYPE_TXT, _CLASS_IN,
ttl, info.text), 0)
if info.address:
for address in info.addresses:
out.add_answer_at_time(DNSAddress(info.server, _TYPE_A,
_CLASS_IN, ttl, info.address), 0)
_CLASS_IN, ttl, address), 0)
self.send(out)
i += 1
next_time += _REGISTER_TIME
Expand Down Expand Up @@ -1473,9 +1491,9 @@ def unregister_service(self, info):
info.name), 0)
out.add_answer_at_time(DNSText(info.name, _TYPE_TXT, _CLASS_IN,
0, info.text), 0)
if info.address:
for address in info.addresses:
out.add_answer_at_time(DNSAddress(info.server, _TYPE_A,
_CLASS_IN, 0, info.address), 0)
_CLASS_IN, 0, address), 0)
self.send(out)
i += 1
next_time += _UNREGISTER_TIME
Expand All @@ -1500,9 +1518,9 @@ def unregister_all_services(self):
info.port, info.server), 0)
out.add_answer_at_time(DNSText(info.name, _TYPE_TXT,
_CLASS_IN, 0, info.text), 0)
if info.address:
for address in info.addresses:
out.add_answer_at_time(DNSAddress(info.server,
_TYPE_A, _CLASS_IN, 0, info.address), 0)
_TYPE_A, _CLASS_IN, 0, address), 0)
self.send(out)
i += 1
next_time += _UNREGISTER_TIME
Expand Down Expand Up @@ -1621,9 +1639,10 @@ def handle_query(self, msg, addr, port):
if question.type in (_TYPE_A, _TYPE_ANY):
for service in self.services.values():
if service.server == question.name.lower():
out.add_answer(msg, DNSAddress(question.name,
_TYPE_A, _CLASS_IN | _CLASS_UNIQUE,
_DNS_TTL, service.address))
for address in service.addresses:
out.add_answer(msg, DNSAddress(question.name,
_TYPE_A, _CLASS_IN | _CLASS_UNIQUE,
_DNS_TTL, address))

service = self.services.get(question.name.lower(), None)
if not service:
Expand All @@ -1639,9 +1658,10 @@ def handle_query(self, msg, addr, port):
_TYPE_TXT, _CLASS_IN | _CLASS_UNIQUE,
_DNS_TTL, service.text))
if question.type == _TYPE_SRV:
out.add_additional_answer(DNSAddress(service.server,
_TYPE_A, _CLASS_IN | _CLASS_UNIQUE,
_DNS_TTL, service.address))
for address in service.addresses:
out.add_additional_answer(DNSAddress(service.server,
_TYPE_A, _CLASS_IN | _CLASS_UNIQUE,
_DNS_TTL, address))
except Exception as e: # TODO stop catching all Exceptions
log.exception('Unknown error, possibly benign: %r', e)

Expand Down