Skip to content

Commit

Permalink
fix: work around a bug in netifaces that crashes on Android
Browse files Browse the repository at this point in the history
  • Loading branch information
ntamas committed Jul 11, 2024
1 parent 402f282 commit 9429e74
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 9 deletions.
30 changes: 25 additions & 5 deletions src/flockwave/networking/interfaces.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
"""Generic networking-related utility functions."""

import sys

from ipaddress import (
ip_address,
ip_network,
IPv4Network,
IPv6Address,
IPv6Network,
)
from netifaces import AF_INET, AF_INET6, AF_LINK, ifaddresses, interfaces
from netifaces import AF_INET, AF_INET6, AF_LINK, ifaddresses, interfaces as _interfaces
from typing import Optional, Sequence, Union

from .addressing import canonicalize_mac_address
Expand All @@ -19,9 +21,23 @@
"get_all_ipv4_addresses",
"get_broadcast_address_of_network_interface",
"get_link_layer_address_mapping",
"list_network_interfaces",
"resolve_network_interface_or_address",
)

_is_android = hasattr(sys, "getandroidapilevel")


if _is_android:

def list_network_interfaces() -> Sequence[str]:
"""Lists all the network interfaces of the system."""
# rmnet and r_rmnet interfaces on Android seem to cause a crash with
# netifaces.ifaddresses() so we pretend they do not exist
return [iface for iface in _interfaces() if "rmnet" not in iface]
else:
list_network_interfaces = _interfaces


def find_interfaces_with_address(
address: str,
Expand All @@ -44,7 +60,7 @@ def find_interfaces_with_address(
family = AF_INET

candidates: list[tuple[str, Union[IPv4Network, IPv6Network]]] = []
for interface in interfaces():
for interface in list_network_interfaces():
specs = ifaddresses(interface).get(family) or []
ip_addresses_in_network = (
(spec.get("addr"), spec.get("netmask")) for spec in specs
Expand Down Expand Up @@ -79,7 +95,7 @@ def find_interfaces_in_network(
family = AF_INET

candidates: list[tuple[str, str, Optional[str]]] = []
for interface in interfaces():
for interface in list_network_interfaces():
specs = ifaddresses(interface).get(family) or []
ip_addresses_in_network = (
(spec.get("addr") or "", spec.get("netmask"))
Expand Down Expand Up @@ -130,7 +146,7 @@ def get_address_of_network_interface(value: str, family: int = AF_INET) -> str:
def get_all_ipv4_addresses() -> Sequence[str]:
"""Returns all IPv4 addresses of the current machine."""
result = []
for iface in interfaces():
for iface in list_network_interfaces():
addresses = ifaddresses(iface)
if AF_INET in addresses:
result.append(addresses[AF_INET][0]["addr"])
Expand Down Expand Up @@ -169,7 +185,7 @@ def get_link_layer_address_mapping() -> dict[str, str]:
We assume that one interface may have only one link-layer address.
"""
result = {}
for iface in interfaces():
for iface in list_network_interfaces():
addresses = ifaddresses(iface)
if AF_LINK in addresses:
result[iface] = canonicalize_mac_address(addresses[AF_LINK][0]["addr"])
Expand All @@ -190,6 +206,10 @@ def resolve_network_interface_or_address(value: str) -> str:
Returns:
the IPv4 address of the interface.
Raises:
ValueError: if the value seems to be a network interface name but it has
no IPv4 address
"""
try:
return str(ip_address(value))
Expand Down
5 changes: 3 additions & 2 deletions src/flockwave/networking/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from enum import Enum
from functools import partial
from ipaddress import ip_address
from netifaces import AF_INET, AF_LINK, ifaddresses, interfaces
from netifaces import AF_INET, AF_LINK, ifaddresses
from typing import (
Callable,
Iterable,
Expand All @@ -12,6 +12,7 @@
Sequence,
)

from .interfaces import list_network_interfaces
from .utils import aclosing
from .wired import is_carrier_detected, is_maybe_wired_or_wireless
from .wireless import get_connected_access_point_name, is_likely_wireless
Expand Down Expand Up @@ -166,7 +167,7 @@ def _find_relevant_interfaces(
its IPv4 addresses (or an empty list if the interface has no IPv4
address)
"""
for interface in interfaces():
for interface in list_network_interfaces():
addresses = ifaddresses(interface)
ipv4_addresses = addresses.get(AF_INET)
if not ipv4_addresses:
Expand Down
6 changes: 4 additions & 2 deletions src/flockwave/networking/sockets.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
from contextlib import closing
from errno import EADDRINUSE
from ipaddress import ip_address, ip_network
from netifaces import AF_INET, gateways, ifaddresses, interfaces
from netifaces import AF_INET, gateways, ifaddresses
from typing import Any, Optional

from .interfaces import list_network_interfaces

__all__ = (
"can_bind_to_tcp_address",
"can_bind_to_udp_address",
Expand Down Expand Up @@ -187,7 +189,7 @@ def get_socket_address(
remote_host = None

if remote_host:
for interface in interfaces():
for interface in list_network_interfaces():
# We are currently interested only in IPv4 addresses
specs = ifaddresses(interface).get(AF_INET)
if not specs:
Expand Down

0 comments on commit 9429e74

Please sign in to comment.