Skip to content

Commit

Permalink
Skip each ssdp listener that fails to bind (#53670)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdraco authored and balloob committed Jul 29, 2021
1 parent d19d487 commit db8aa46
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 2 deletions.
16 changes: 14 additions & 2 deletions homeassistant/components/ssdp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,9 +256,21 @@ async def async_start(self) -> None:
self.hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_STARTED, self.flow_dispatcher.async_start
)
await asyncio.gather(
*(listener.async_start() for listener in self._ssdp_listeners)
results = await asyncio.gather(
*(listener.async_start() for listener in self._ssdp_listeners),
return_exceptions=True,
)
failed_listeners = []
for idx, result in enumerate(results):
if isinstance(result, Exception):
_LOGGER.warning(
"Failed to setup listener for %s: %s",
self._ssdp_listeners[idx].source_ip,
result,
)
failed_listeners.append(self._ssdp_listeners[idx])
for listener in failed_listeners:
self._ssdp_listeners.remove(listener)
self._cancel_scan = async_track_time_interval(
self.hass, self.async_scan, SCAN_INTERVAL
)
Expand Down
62 changes: 62 additions & 0 deletions tests/components/ssdp/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -790,3 +790,65 @@ def _callback(*_):
(IPv4Address("192.168.1.5"), IPv4Address("255.255.255.255")),
(IPv4Address("192.168.1.5"), None),
}


async def test_bind_failure_skips_adapter(hass, caplog):
"""Test that an adapter with a bind failure is skipped."""
mock_get_ssdp = {
"mock-domain": [
{
ssdp.ATTR_UPNP_DEVICE_TYPE: "ABC",
}
]
}
create_args = []
did_search = 0

@callback
def _callback(*_):
nonlocal did_search
did_search += 1
pass

def _generate_failing_ssdp_listener(*args, **kwargs):
create_args.append([args, kwargs])
listener = SSDPListener(*args, **kwargs)

async def _async_callback(*_):
if kwargs["source_ip"] == IPv6Address("2001:db8::"):
raise OSError
pass

listener.async_start = _async_callback
listener.async_search = _callback
return listener

with patch(
"homeassistant.components.ssdp.async_get_ssdp",
return_value=mock_get_ssdp,
), patch(
"homeassistant.components.ssdp.SSDPListener",
new=_generate_failing_ssdp_listener,
), patch(
"homeassistant.components.ssdp.network.async_get_adapters",
return_value=_ADAPTERS_WITH_MANUAL_CONFIG,
):
assert await async_setup_component(hass, ssdp.DOMAIN, {ssdp.DOMAIN: {}})
await hass.async_block_till_done()
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
await hass.async_block_till_done()

argset = set()
for argmap in create_args:
argset.add((argmap[1].get("source_ip"), argmap[1].get("target_ip")))

assert argset == {
(IPv6Address("2001:db8::"), None),
(IPv4Address("192.168.1.5"), IPv4Address("255.255.255.255")),
(IPv4Address("192.168.1.5"), None),
}
assert "Failed to setup listener for" in caplog.text

async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=200))
await hass.async_block_till_done()
assert did_search == 2

0 comments on commit db8aa46

Please sign in to comment.