← index #1078PR #18801
Duplicate · high · value 3.246
QUERY · ISSUE

requests: guard against getaddrinfo() hang when WiFi not connected

openby paul-matthewsopened 2026-02-09updated 2026-02-10

Summary

The request() function in requests/__init__.py calls socket.getaddrinfo() (line 81) without verifying network connectivity. On platforms where getaddrinfo() blocks indefinitely when the WiFi interface is active but not connected (see micropython/micropython#18797), this causes the device to freeze with no way to recover except a hard reset.

The timeout parameter passed to requests.get() has no effect because socket.settimeout() is applied to the socket object (line 93) — which is created after getaddrinfo() returns. So the hang occurs before any timeout takes effect.

Suggested fix

Add a connectivity check before getaddrinfo():

    # Guard: getaddrinfo() blocks indefinitely on RP2040/RP2350 when the
    # CYW43 WiFi interface is active but has no IP address.
    try:
        import network
        _wlan = network.WLAN(network.STA_IF)
        if not _wlan.isconnected():
            raise OSError(-1, "WiFi not connected")
    except ImportError:
        pass  # Non-WiFi platform, skip guard

    ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)

This is wrapped in try/except ImportError so it's safe on non-WiFi platforms (ESP32 Ethernet, Unix port, etc.).

Also consider

A default socket timeout (e.g., 30s) applied before getaddrinfo() would provide defense-in-depth, though it wouldn't help here since settimeout() only affects socket operations, not DNS resolution.

Environment

  • Board: Raspberry Pi Pico 2 W (RP2350 + CYW43)
  • MicroPython: v1.26.1
  • Upstream issue: micropython/micropython#18797
1 comment
dpgeorge · 2026-02-10

This needs to be fixed properly in socket.getaddrinfo() so it doesn't block indefinitely.

CANDIDATE · PULL REQUEST

extmod/modlwip: Fix getaddrinfo blocking indefinitely without network.

openby paul-matthewsopened 2026-02-10updated 2026-03-04
extmod

Summary

socket.getaddrinfo() blocks indefinitely on lwIP-based ports (confirmed on rp2/CYW43) when WiFi was previously connected then disconnected. This adds two fixes to the ERR_INPROGRESS case in lwip_getaddrinfo():

  • Early-fail check: Before polling, verify at least one netif is up, has link, and has a valid IP. If not, fail immediately with -2 (consistent with lwip_getaddrinfo_cb failure). This catches WiFi-inactive, active-but-never-connected, and disconnected-after-connection scenarios.
  • Safety-net timeout (20s): Guards against any other scenario where lwIP's internal DNS timeout doesn't fire.

Root Cause

Two factors combine to cause the indefinite hang:

  1. Cached DNS servers: After WiFi disconnect, DNS server addresses from the previous DHCP lease remain cached in lwIP. dns_gethostbyname() enqueues a query (returning ERR_INPROGRESS) even though no network path exists.

  2. Soft timer self-disables: On the rp2 port, the lwIP soft timer switches to ONE_SHOT mode when no netif has LINK_UP (ports/rp2/mpnetworkport.c:150-161). Without the periodic timer, dns_tmr() never fires, so lwIP's built-in DNS retry/timeout mechanism is dead. The polling loop spins forever.

The early-fail check must verify three conditions (not just IP):

  • netif_is_up() — interface administratively up
  • netif_is_link_up() — physical link up (WiFi associated)
  • !ip4_addr_isany_val() — valid IP (DHCP complete)

After disconnect, LINK_UP is cleared but the DHCP IP address lingers, so checking IP alone is insufficient.

Test Results

Tested on Raspberry Pi Pico 2 W (RP2350 + CYW43439), MicroPython v1.26.1:

# WiFi State Expected Result
1 IP literal, WiFi off Resolves (ERR_OK path) [(2,1,0,'',('10.0.0.1',80))] in 0ms
2 Connected DNS resolves 142.251.30.103 in 23ms
3 Was connected, then disconnect() OSError(-2) immediate OSError(-2) in 0ms
4 active(True), never connected OSError(-2) immediate OSError(-2) in 1ms
5 active(False) OSError(-2) immediate OSError(-2) in 1ms

All 5/5 pass. Without the fix, tests 3 and 4 hang indefinitely.

Notes

  • The fix is in extmod/modlwip.c which is shared across all lwIP ports (rp2, esp32, etc.)
  • IP literal resolution and cached DNS results take the ERR_OK path and bypass this code entirely
  • The -2 status value is consistent with the existing lwip_getaddrinfo_cb() failure convention

Fixes #18797

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied