UPnP: filter non-WAN device announcements before fetching description (#622) - #623
Merged
mrjimenez merged 1 commit intoMay 15, 2026
Conversation
…amule-project#622) The SSDP discovery callback handles UPNP_DISCOVERY_ADVERTISEMENT_ALIVE by downloading description.xml first and only then checking the parsed deviceType. On a typical home LAN -- with smart speakers, media renderers, mesh APs, ESP32 IoT devices, etc. all multicasting their own NOTIFY ALIVE announcements -- amule ends up fetching XML from endpoints it has no use for. Two consequences in the wild (amule-project#622): * "Error retrieving device description" log lines for every device that returns a transient socket error, malformed URL, or weird Content-Type. Stoatwblr's report shows squeezeboxserver and a Zyxel mesh WAP both triggering it. * libupnp's internal ThreadPool queue fills under bursts of announcements ("ThreadPoolAdd too many jobs: 100"), because the callback is the slow consumer. Filter NOTIFY ALIVE by NT (DeviceType in the UpnpDiscovery struct) before going near the network. The whitelist is the IGW family plus upnp:rootdevice (which is opaque from SSDP -- still needs the XML to classify): - upnp:rootdevice - urn:schemas-upnp-org:device:InternetGatewayDevice:* - urn:schemas-upnp-org:device:WANDevice:* - urn:schemas-upnp-org:device:WANConnectionDevice:* - urn:schemas-upnp-org:device:LANDevice:* - urn:schemas-upnp-org:service:Layer3Forwarding:* - urn:schemas-upnp-org:service:WANCommonInterfaceConfig:* - urn:schemas-upnp-org:service:WANIPConnection:* - urn:schemas-upnp-org:service:WANPPPConnection:* Prefix-matched so future :2/:3 UPnP revisions don't need code changes. UPNP_DISCOVERY_SEARCH_RESULT processing is untouched -- we explicitly asked, we still handle whatever comes back. Verified locally on macOS arm64: monolithic amule rebuilds clean. Reported by Stoatwblr.
Closed
mrjimenez
pushed a commit
that referenced
this pull request
May 15, 2026
The SSDP discovery + service-walk paths log a handful of lines at
AddDebugLogLineC (critical -- always visible to the user), which on
busy home LANs fills stdout with messages the user can't act on:
- "Error retrieving device description from <url>: ..." -- transient
HTTP fetch failures from random LAN devices that announce via
SSDP but block HTTP from amule's subnet (mesh APs, multi-vlan
setups, IoT devices going offline)
- "Uninteresting service detected: '...'" -- emitted as amule walks
a downloaded description.xml; one line per service it doesn't
consume. Useful for debugging, noise for users
- "error(UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE): ..." -- BYEBYE event
parse error, expected during LAN churn
- "Error getting SCPD Document from ..." / subscribe-error path --
routine, amule already retries
Demote those to AddDebugLogLineN. They stay accessible with
DebugLogTypes=UPnP enabled, but no longer surface to stdout for
users running the default log level. Keep user-actionable errors
(AddPortMapping/DeletePortMapping failures, "WAN Service not
detected" at port-map time) and success notifications (IGW
detected, SCPD retrieved, subscribed) at critical level so the
"is UPnP working?" UX is unchanged.
Reported by Stoatwblr in #622 -- a Zyxel mesh WAP that announces
SSDP rootdevice from a subnet whose HTTP is unreachable to amule
generated a steady stream of "Error retrieving device description"
lines. PR #623 already drops the per-leaf-service-NT noise; this
finishes the cleanup for the rootdevice case that #623 deliberately
lets through (rootdevice can't be classified without the XML).
Verified locally on macOS arm64: monolithic amule rebuilds clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The SSDP discovery callback in
CUPnPControlPoint::CallbackhandlesUPNP_DISCOVERY_ADVERTISEMENT_ALIVEby downloading the device'sdescription.xmlfirst and only then checking the parseddeviceTypefor IGW (line 1234). On a typical home LAN — smart speakers, media renderers, mesh APs, ESP32 IoT devices all multicasting their own NOTIFY ALIVE announcements — amule fetches XML from endpoints it has no use for. Two consequences reported in #622:ThreadPoolAdd too many jobs: 100), because amule's callback is the slow consumer.Fix
Filter
UPNP_DISCOVERY_ADVERTISEMENT_ALIVEbyNT(DeviceTypein theUpnpDiscoverystruct) before going near the network. The whitelist is the IGW family plusupnp:rootdevice(which is opaque from SSDP alone — the XML still has to be fetched to classify it):upnp:rootdeviceurn:schemas-upnp-org:device:InternetGatewayDevice:*urn:schemas-upnp-org:device:WANDevice:*urn:schemas-upnp-org:device:WANConnectionDevice:*urn:schemas-upnp-org:device:LANDevice:*urn:schemas-upnp-org:service:Layer3Forwarding:*urn:schemas-upnp-org:service:WANCommonInterfaceConfig:*urn:schemas-upnp-org:service:WANIPConnection:*urn:schemas-upnp-org:service:WANPPPConnection:*Prefix-matched (case-insensitive) so future
:2/:3UPnP revisions don't need code changes. The new helperUPnP::IsWANRelatedDeviceTypelives next to the existing constants block.UPNP_DISCOVERY_SEARCH_RESULTprocessing is untouched — we explicitly issued an M-SEARCH forupnp:rootdeviceand need to handle whatever the matching devices respond with.Why not just demote the log
Two reasons we don't simply demote
AddDebugLogLineCtoAddDebugLogLineN:ThreadPool too many jobssaturation is fixed only by returning from the callback faster, which requires not doing the download.Validation
amulerebuilds clean.upnp:rootdeviceannouncements still fall through to the existing path so amule continues to detect and port-map against real routers.Follow-up worth flagging
src/UPnPBase.cpphas ~30#if UPNP_VERSION >= 10800blocks carrying compatibility with libupnp 1.6.x. libupnp 1.8 shipped in April 2017 and every non-ESM distro has been on 1.8+ for years (Debian Buster shipped 1.8.4; Ubuntu 20.04+ on 1.14; Homebrew on 1.18). A separate cleanup PR collapsing those branches would simplify the file substantially — kept out of this PR to stay focused.Closes #622.