Skip to content

Part 6 - p2p: replace upnpclient with async-upnp-client for NAT port mapping#970

Open
ping-ke wants to merge 4 commits intoupgrade/py313-baselinefrom
upgrade/p2p-nat
Open

Part 6 - p2p: replace upnpclient with async-upnp-client for NAT port mapping#970
ping-ke wants to merge 4 commits intoupgrade/py313-baselinefrom
upgrade/p2p-nat

Conversation

@ping-ke
Copy link
Contributor

@ping-ke ping-ke commented Mar 15, 2026

Summary

upnpclient uses synchronous/blocking I/O and netifaces for interface discovery; neither is well-maintained on Python 3.13.

Rewrite UPnPService in nat.py to use async-upnp-client:

  • Use async_search() for UPnP IGD device discovery
  • Use AiohttpSessionRequester + UpnpFactory for async HTTP requests
  • Remove ThreadPoolExecutor blocking path and netifaces dependency
  • Expose discover() coroutine (previously add_nat_portmap()) that
    returns the mapped external IP string
  • Update p2p_server.py call site accordingly

Test plan

  • Node starts and attempts UPnP discovery without errors
  • NAT mapping is established when a compatible router is present
  • Graceful handling when no UPnP device is found (returns None)

upnpclient uses synchronous I/O and netifaces for interface discovery,
both incompatible or unmaintained under Python 3.13.

Switch to async-upnp-client which provides asyncio-native UPnP/IGD
support. Rewrite UPnPService.discover() to use async_search() for
device discovery and AiohttpSessionRequester for requests, removing
the blocking ThreadPoolExecutor path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ping-ke ping-ke changed the title replace upnpclient with async-upnp-client for NAT port mapping p2p: replace upnpclient with async-upnp-client for NAT port mapping Mar 15, 2026
@ping-ke ping-ke changed the title p2p: replace upnpclient with async-upnp-client for NAT port mapping Part 6 - p2p: replace upnpclient with async-upnp-client for NAT port mapping Mar 15, 2026
@ping-ke ping-ke marked this pull request as draft March 17, 2026 06:43
ping-ke added 2 commits March 19, 2026 10:06
- Fix AttributeError: replace undefined self.external_port/self.internal_port/self.protocol with self.port
- Fix _discover timeout: wrap async_search with asyncio.wait_for instead of waiting after it completes
- Fix _run: guard _add_port_mapping with self._service check to avoid AttributeError
- Fix _delete_port_mapping: delete both TCP and UDP mappings to match AddPortMapping
- Remove dead code: _refresh_task and _running fields that were never used
@ping-ke ping-ke marked this pull request as ready for review March 19, 2026 02:33
@ping-ke ping-ke requested review from qizhou, qzhodl and syntrust March 19, 2026 02:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant