Skip to content

Commit d236934

Browse files
committed
fix: avoid loading adapter list twice
Load adapter list only once if operating in dual-stack mode. Also fix typing around adapater list to match what ifaddr defines.
1 parent 389a8a2 commit d236934

2 files changed

Lines changed: 20 additions & 11 deletions

File tree

src/zeroconf/_utils/net.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
import socket
2929
import struct
3030
import sys
31-
from collections.abc import Sequence
31+
from collections.abc import Iterable, Sequence
3232
from typing import Any, Union, cast
3333

3434
import ifaddr
@@ -73,19 +73,27 @@ def _encode_address(address: str) -> bytes:
7373
return socket.inet_pton(address_family, address)
7474

7575

76-
def get_all_addresses() -> list[str]:
77-
return list({addr.ip for iface in ifaddr.get_adapters() for addr in iface.ips if addr.is_IPv4}) # type: ignore[misc]
76+
def get_all_addresses_ipv4(adapters: Iterable[ifaddr.Adapter]) -> list[str]:
77+
return list({addr.ip for iface in adapters for addr in iface.ips if addr.is_IPv4}) # type: ignore[misc]
7878

7979

80-
def get_all_addresses_v6() -> list[tuple[tuple[str, int, int], int]]:
80+
def get_all_addresses_ipv6(adapters: Iterable[ifaddr.Adapter]) -> list[tuple[tuple[str, int, int], int]]:
8181
# IPv6 multicast uses positive indexes for interfaces
8282
# TODO: What about multi-address interfaces?
8383
return list(
84-
{(addr.ip, iface.index) for iface in ifaddr.get_adapters() for addr in iface.ips if addr.is_IPv6} # type: ignore[misc]
84+
{(addr.ip, iface.index) for iface in adapters for addr in iface.ips if addr.is_IPv6} # type: ignore[misc]
8585
)
8686

8787

88-
def ip6_to_address_and_index(adapters: list[ifaddr.Adapter], ip: str) -> tuple[tuple[str, int, int], int]:
88+
def get_all_addresses() -> list[str]: # required for backwards compat
89+
return get_all_addresses_ipv4(ifaddr.get_adapters())
90+
91+
92+
def get_all_addresses_v6() -> list[tuple[tuple[str, int, int], int]]: # required for backwards compat
93+
return get_all_addresses_ipv6(ifaddr.get_adapters())
94+
95+
96+
def ip6_to_address_and_index(adapters: Iterable[ifaddr.Adapter], ip: str) -> tuple[tuple[str, int, int], int]:
8997
if "%" in ip:
9098
ip = ip[: ip.index("%")] # Strip scope_id.
9199
ipaddr = ipaddress.ip_address(ip)
@@ -102,7 +110,7 @@ def ip6_to_address_and_index(adapters: list[ifaddr.Adapter], ip: str) -> tuple[t
102110
raise RuntimeError(f"No adapter found for IP address {ip}")
103111

104112

105-
def interface_index_to_ip6_address(adapters: list[ifaddr.Adapter], index: int) -> tuple[str, int, int]:
113+
def interface_index_to_ip6_address(adapters: Iterable[ifaddr.Adapter], index: int) -> tuple[str, int, int]:
106114
for adapter in adapters:
107115
if adapter.index == index:
108116
for adapter_ip in adapter.ips:
@@ -152,10 +160,11 @@ def normalize_interface_choice(
152160
if ip_version != IPVersion.V6Only:
153161
result.append("0.0.0.0")
154162
elif choice is InterfaceChoice.All:
163+
adapters = ifaddr.get_adapters()
155164
if ip_version != IPVersion.V4Only:
156-
result.extend(get_all_addresses_v6())
165+
result.extend(get_all_addresses_ipv6(adapters))
157166
if ip_version != IPVersion.V6Only:
158-
result.extend(get_all_addresses())
167+
result.extend(get_all_addresses_ipv4(adapters))
159168
if not result:
160169
raise RuntimeError(
161170
f"No interfaces to listen on, check that any interfaces have IP version {ip_version}"

tests/utils/test_net.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ def test_ip6_addresses_to_indexes():
8484
def test_normalize_interface_choice_errors():
8585
"""Test we generate exception on invalid input."""
8686
with (
87-
patch("zeroconf._utils.net.get_all_addresses", return_value=[]),
88-
patch("zeroconf._utils.net.get_all_addresses_v6", return_value=[]),
87+
patch("zeroconf._utils.net.get_all_addresses_ipv4", return_value=[]),
88+
patch("zeroconf._utils.net.get_all_addresses_ipv6", return_value=[]),
8989
pytest.raises(RuntimeError),
9090
):
9191
netutils.normalize_interface_choice(r.InterfaceChoice.All)

0 commit comments

Comments
 (0)