Skip to content

Discovery resends its search and takes only IPv4; the idle limit spares a connecting socket; descriptions compare as routers store them (2.0.4) - #16

Merged
MorningLightMountain713 merged 6 commits into
RunOnFlux:mainfrom
MorningLightMountain713:fix/discovery-resend
Oct 19, 2026

Conversation

@MorningLightMountain713

Copy link
Copy Markdown

Discovery sends its search again until a router answers and takes only an IPv4 router; a kept connection's idle limit no longer cuts off a connection that is still connecting; and descriptions compare as routers store them.

Discovery

The M-SEARCH goes out again 250, 750, 1750 and 3750 ms after the first, until a gateway answers or the search ends. UDP loses datagrams, and some routers drop searches for a second or more at a time: behind one OPNsense, a single search went unanswered 24 times in 100, three searches 500 ms apart (GSSDP's schedule) 4 times, and this schedule never. pupnp sends each search twice and GSSDP three times for the same reason. The discovery timeout defaults to 5000 ms, which the last resend fits in.

Discovery takes only an answer whose location is an IPv4 address. Some routers (a D-Link DIR-X3260 and a Cisco XSR150DX in the fleet) answer an IPv4 search twice, with an IPv6 location first; 2.0.3 took it, could not resolve the host's IPv4 address from it, and every mapping failed.

Kept connections

2.0.3 gave the agent its 3 s idle limit as the agent's timeout, which Node applies to every socket from creation, connecting included. A router slow to accept — miniupnpd under load drops SYNs once its backlog of five is full, and the kernel's retries land at 1, 3 and 7 s — had requests cut off at 3 s, reported by axios as its own 10 s timeout. The agent now has no socket timeout; a socket gets the idle limit only once it is in the pool.

Descriptions

FRITZ!Box rewrites a description's punctuation: "Flux_App_web" comes back "Flux.App.web", "FluxOS Reserved" as "FluxOS.Reserved" (every one of 1,521 Flux mappings on the fleet's FRITZ!Boxes). canonicalDescription, exported, turns every run of characters other than letters and digits into one underscore. A string description filter on getMappings, and the description check on a re-sent createMapping that gets 718, compare that way. A RegExp filter is applied as given.

Tests

  • npm test: 892 passing, on Node 24 and on Node 20.8. Each new branch was broken on its own and turns its test red; the connect-timeout test is red against 2.0.3's agent.
  • npm run flux-test:igd2: green against IGD v2 and IGD v1.
  • Read-only on real routers: discovery 10/10 on the D-Link and Cisco (both 0/10 on 2.0.3), on the OPNsense that drops searches, and on a pfSense, an Archer A6 and a FRITZ!Box; the OPNsense whose listings 2.0.3 cut off listed 6/6.

🤖 Generated with Claude Code

… takes only an IPv4 location, and waits 5 s by default

After the first M-SEARCH the same search is sent again 250, 750, 1750
and 3750 ms later, until a gateway answers, the search ends or the
instance is closed. UDP loses datagrams, and some routers drop searches
for a second or more at a time; the gaps double, as DHCP's retransmissions
do, so the later copies reach a router that was silent for the first.
pupnp sends each search twice and GSSDP three times for the same reason.

Discovery takes only an answer whose location is an IPv4 address. Some
routers answer an IPv4 search twice, with an IPv6 location first, and both
the mappings and the host's address (its route to the router) are IPv4.

The discovery timeout defaults to 5000 ms, which the last resend fits in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r while a connection connects

The agent's `timeout` option is set on every socket from creation, so the
3 s idle limit for kept connections ran while a new connection was still
connecting, before the request's own 10 s timeout took over. A router slow
to accept - miniupnpd under load drops SYNs once its backlog of five is
full, and the kernel's retries land at 1, 3 and 7 s - had requests cut off
at 3 s, reported by axios as its own 10 s timeout. The agent now has no
socket timeout; a "free" listener, after the agent's own, gives a socket
the idle limit only once it is in the pool.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ion)

FRITZ!Box keeps every mapping description with its punctuation rewritten:
"Flux_App_web" comes back as "Flux.App.web", "FluxOS Reserved" as
"FluxOS.Reserved". canonicalDescription turns every run of characters other
than letters and digits into one underscore, so each form compares equal.
getMappings matches a string description filter that way, and a re-sent
createMapping that gets 718 compares the held mapping's description that
way. A RegExp filter is applied as given. canonicalDescription is exported
for callers comparing stored descriptions themselves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MorningLightMountain713
MorningLightMountain713 merged commit 944a5ef into RunOnFlux:main Oct 19, 2026
5 checks passed
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