Skip to content

Commit aa59998

Browse files
authored
Skip unavailable interfaces during socket bind (#1028)
- We already skip these when adding multicast members. Apply the same logic to the socket bind call
1 parent 8b0dc48 commit aa59998

2 files changed

Lines changed: 38 additions & 3 deletions

File tree

tests/utils/test_net.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44

55
"""Unit tests for zeroconf._utils.net."""
6-
from unittest.mock import Mock, patch
6+
from unittest.mock import MagicMock, Mock, patch
77

88
import errno
99
import ifaddr
@@ -198,3 +198,26 @@ def test_add_multicast_member():
198198
# No error should return True
199199
with patch("socket.socket.setsockopt"):
200200
assert netutils.add_multicast_member(sock, interface) is True
201+
202+
203+
def test_bind_raises_skips_address():
204+
"""Test bind failing in new_socket returns None on EADDRNOTAVAIL."""
205+
err = errno.EADDRNOTAVAIL
206+
207+
def _mock_socket(*args, **kwargs):
208+
sock = MagicMock()
209+
sock.bind = MagicMock(side_effect=OSError(err, "Error: {}".format(err)))
210+
return sock
211+
212+
with patch("socket.socket", _mock_socket):
213+
assert netutils.new_socket(("0.0.0.0", 0)) is None
214+
215+
err = errno.EAGAIN
216+
with pytest.raises(OSError), patch("socket.socket", _mock_socket):
217+
netutils.new_socket(("0.0.0.0", 0))
218+
219+
220+
def test_new_respond_socket_new_socket_returns_none():
221+
"""Test new_respond_socket returns None if new_socket returns None."""
222+
with patch.object(netutils, "new_socket", return_value=None):
223+
assert netutils.new_respond_socket(("0.0.0.0", 0)) is None

zeroconf/_utils/net.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ def new_socket(
218218
port: int = _MDNS_PORT,
219219
ip_version: IPVersion = IPVersion.V4Only,
220220
apple_p2p: bool = False,
221-
) -> socket.socket:
221+
) -> Optional[socket.socket]:
222222
log.debug(
223223
'Creating new socket with port %s, ip_version %s, apple_p2p %s and bind_addr %r',
224224
port,
@@ -243,7 +243,17 @@ def new_socket(
243243
# https://opensource.apple.com/source/xnu/xnu-4570.41.2/bsd/sys/socket.h
244244
s.setsockopt(socket.SOL_SOCKET, 0x1104, 1)
245245

246-
s.bind((bind_addr[0], port, *bind_addr[1:]))
246+
bind_tup = (bind_addr[0], port, *bind_addr[1:])
247+
try:
248+
s.bind(bind_tup)
249+
except OSError as ex:
250+
if ex.errno == errno.EADDRNOTAVAIL:
251+
log.warning(
252+
'Address not available when binding to %s, ' 'it is expected to happen on some systems',
253+
bind_tup,
254+
)
255+
return None
256+
raise
247257
log.debug('Created socket %s', s)
248258
return s
249259

@@ -323,6 +333,8 @@ def new_respond_socket(
323333
apple_p2p=apple_p2p,
324334
bind_addr=cast(Tuple[Tuple[str, int, int], int], interface)[0] if is_v6 else (cast(str, interface),),
325335
)
336+
if not respond_socket:
337+
return None
326338
log.debug('Configuring socket %s with multicast interface %s', respond_socket, interface)
327339
if is_v6:
328340
iface_bin = struct.pack('@I', cast(int, interface[1]))

0 commit comments

Comments
 (0)