Repeater: discover and subscribe to the regions of neighboring repeaters - #3086
Draft
agessaman wants to merge 4 commits into
Draft
Repeater: discover and subscribe to the regions of neighboring repeaters#3086agessaman wants to merge 4 commits into
agessaman wants to merge 4 commits into
Conversation
Adds the client side of the existing anon-regions request, which until now only had a server side (handleAnonRegionsReq), and uses it two ways: - `discover.regions` asks each heard neighbor in turn which regions it floods, printing results to serial as they arrive. `discover.regions list` reports the last run for remote CLI users. - `regions.subscribe <pubkey>` nominates a repeater to take regions from. The node fetches its regions on change, 2 minutes after boot, and every 72 hours after that, adding any region it doesn't already have as a flood-allowed child of the wildcard. An unanswered fetch is retried after a minute for the first few attempts, then every 12 hours. Subscribing is additive: a region already on this node keeps its flags and its place in the hierarchy, so a region the operator has denied stays denied, and nothing is ever removed. Private ($) regions are skipped, as their transport keys are not derived from the name. Only one request is in flight at a time. The queried node is matched in searchPeersByHash after the ACL clients, so that querying a node which is also a client cannot swallow that client's own traffic. Also fixes two pre-existing issues this feature depends on: - handleAnonRegionsReq() could build a reply larger than createDatagram() accepts, so a node with a large region map answered nothing at all. - discovery_mod_timestamp was saved but never serialized, so it reset to zero on every reboot.
The reply is capped at 134 chars, so a pass over several neighbours with long region lists silently showed only the first few. Count what doesn't fit and append '+N more', so a short list isn't mistaken for the whole pass. The serial output is unchanged, and still shows every result.
Three ways an incomplete result was presented as a whole one: - 'discover.regions' built each entry in a 64 byte buffer, so a neighbour with more than ~54 chars of region names was cut short with no marker, in the serial log as well as the list. The serial log now prints the whole reply, and an entry that does not fit the list is counted in the '+N more' total rather than stored truncated. - importNamesFrom() stops when the region table is full, and saveRegions() can fail; both were reported as a successful fetch, which cleared the failure count and stood down for 72 hours. A full table is now flagged in the reply, and an unsaved import keeps retrying: the regions are in RAM, where a later fetch counts them as 'known' and would never retry the save on its own. - An automatic fetch could land in the middle of an interactive 'region load', whose temp map then overwrote the imported regions after they had been reported and saved. Fetches now stand aside while a load is active.
Bring the new code in line with the surrounding style, which comments
lightly. Drops the function-header blocks, keeping the short notes that
record something non-obvious: the peer match ordering, the cipher block
padding, and the reply size limit.
Also collapses the duplicated no-reply/reply branches in
advanceRegionDiscover(), and hoists the repeated prefix out of the
'regions.subscribe' status reply. No behaviour change.
Includes the ambiguous-prefix check for 'regions.subscribe {prefix}',
which previously took whichever neighbour matched first.
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.
Addresses #2852.
A repeater can already answer the question "which regions do you flood?"—
handleAnonRegionsReqhas been in the tree for a while—but only companions ever ask it. This adds the repeater side and two commands built on it, so an operator can see what their neighbors flood and keep a node in step with one of them.discover.regionsdiscover.regions listregions.subscribe <pubkey>regions.subscribe/now/offSubscribing is additive. A region already on the node keeps its flags and its place in the hierarchy—a region the operator has denied stays denied—and nothing is ever removed. New names are added flood-allowed under the wildcard. Private (
$) regions are skipped, since their transport keys aren't derived from the name. The fetch repeats every 72 h (2 min after boot, immediately on change), retrying after 1 min for the first 5 attempts and every 12 h after that.The merge itself lives in
RegionMap::importNamesFrom()so it's reusable by the room server and sensor, which also hold aRegionMap.Also fixes two pre-existing bugs this feature depends on—happy to split these into their own PR if preferred:
handleAnonRegionsReq()could build a reply larger thancreateDatagram()accepts (>159 chars of names), so a node with a large region map answered nothing at all. The exporter is now budgeted from the transport limit.discovery_mod_timestampwas written and saved but never serialized inNodePrefs::structure(), so it reset to zero on every reboot —region savewas affected the same way.Testing: subscribed and merge verified on hardware (2 regions added, 6 already known, existing regions untouched). Builds clean for ESP32-S3 repeater, nRF52 repeater, and room server. Costs ~3.5 KB flash and ~230 bytes RAM.