-
-
Notifications
You must be signed in to change notification settings - Fork 37.5k
Handle aiodns pycares exceptions "leaking" #170048
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2969d62
ddc8343
733937f
fd6a423
5b1ad7d
79d6084
3a81bfb
6a367d3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,9 @@ | ||
| """Adds config flow for dnsip integration.""" | ||
|
|
||
| import asyncio | ||
| import contextlib | ||
| from typing import Any, Literal | ||
|
|
||
| import aiodns | ||
| from aiodns.error import DNSError | ||
| import voluptuous as vol | ||
|
|
||
| from homeassistant.config_entries import ( | ||
|
|
@@ -61,15 +59,16 @@ async def async_validate_hostname( | |
|
|
||
| async def async_check( | ||
| hostname: str, resolver: str, qtype: Literal["A", "AAAA"], port: int = 53 | ||
| ) -> bool: | ||
| """Return if able to resolve hostname.""" | ||
| result: bool = False | ||
| with contextlib.suppress(DNSError): | ||
| _resolver = aiodns.DNSResolver( | ||
| nameservers=[resolver], udp_port=port, tcp_port=port | ||
| ) | ||
| result = bool(await _resolver.query(hostname, qtype)) | ||
| ) -> list: | ||
| """Return list of hostnames.""" | ||
|
|
||
| _resolver = aiodns.DNSResolver( | ||
| nameservers=[resolver], udp_port=port, tcp_port=port | ||
| ) | ||
| try: | ||
| result = await _resolver.query(hostname, qtype) | ||
| finally: | ||
| await _resolver.close() | ||
| return result | ||
|
|
||
| result: dict[str, bool] = {} | ||
|
|
@@ -78,11 +77,14 @@ async def async_check( | |
| async_check(hostname, resolver_ipv4, "A", port=port), | ||
| async_check(hostname, resolver_ipv6, "AAAA", port=port_ipv6), | ||
| async_check(hostname, resolver_ipv4, "AAAA", port=port), | ||
| return_exceptions=True, | ||
| ) | ||
|
|
||
| result[CONF_IPV4] = tasks[0] | ||
| result[CONF_IPV6] = tasks[1] | ||
| result[CONF_IPV6_V4] = tasks[2] | ||
| result[CONF_IPV4] = bool(tasks[0]) if not isinstance(tasks[0], Exception) else False | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In Python 3.14, Consider using result[CONF_IPV4] = bool(tasks[0]) if not isinstance(tasks[0], BaseException) else FalseOr check for the expected success type directly: result[CONF_IPV4] = isinstance(tasks[0], list) and bool(tasks[0]) |
||
| result[CONF_IPV6] = bool(tasks[1]) if not isinstance(tasks[1], Exception) else False | ||
| result[CONF_IPV6_V4] = ( | ||
| bool(tasks[2]) if not isinstance(tasks[2], Exception) else False | ||
| ) | ||
|
|
||
| return result | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,7 +7,7 @@ | |
| from typing import Literal | ||
|
|
||
| import aiodns | ||
| from aiodns.error import DNSError | ||
| from pycares import AresError | ||
|
|
||
|
gjohansson-ST marked this conversation as resolved.
|
||
| from homeassistant.components.sensor import SensorEntity | ||
| from homeassistant.config_entries import ConfigEntry | ||
|
|
@@ -114,18 +114,20 @@ def create_dns_resolver(self) -> None: | |
|
|
||
| async def async_update(self) -> None: | ||
| """Get the current DNS IP address for hostname.""" | ||
| if self.resolver._closed: # noqa: SLF001 | ||
| self.create_dns_resolver() | ||
| response = None | ||
| try: | ||
| async with asyncio.timeout(10): | ||
| if self.resolver._closed: # noqa: SLF001 | ||
| self.create_dns_resolver() | ||
| response = await self.resolver.query(self.hostname, self.querytype) | ||
|
Comment on lines
119
to
122
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is for a separate PR |
||
| except TimeoutError as err: | ||
| _LOGGER.debug("Timeout while resolving host: %s", err) | ||
| await self.resolver.close() | ||
| except DNSError as err: | ||
| _LOGGER.warning("Exception while resolving host: %s", err) | ||
| await self.resolver.close() | ||
| if self.resolver: | ||
| await self.resolver.close() | ||
| except (aiodns.error.DNSError, AresError, asyncio.CancelledError) as err: | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's completely opposite of what we want
gjohansson-ST marked this conversation as resolved.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Catching Suggestion: handle except asyncio.CancelledError:
if self.resolver:
await self.resolver.close()
raise
except (aiodns.error.DNSError, AresError) as err:
_LOGGER.debug("Exception while resolving host: %s", err)
if self.resolver:
await self.resolver.close() |
||
| _LOGGER.debug("Exception while resolving host: %s", err) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This changed from |
||
| if self.resolver: | ||
| await self.resolver.close() | ||
|
|
||
| if response: | ||
| sorted_ips = sort_ips( | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.