Repository navigation
Restore mDNS service registration for telnet and HTTP - #1906
Merged
Merged
Conversation
Since bdring#1750 the Mdns::add/remove calls in TelnetServer and WebUI_Server sat under #ifdef HAVE_DNS, which nothing defines, so _telnet._tcp and _http._tcp were never advertised. Unguard them, leaving only the captive-portal DNSServer under HAVE_DNS, and add a no-op posix Mdns so the native simulator still links. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
The changes correctly restore service discovery across supported targets without affecting the captive portal guard.
0 open findings
What changed in this PR
Restores mDNS advertisements for FluidNC’s HTTP and telnet services while preserving POSIX simulator compatibility.
Changes:
- Registers and removes HTTP and telnet mDNS services unconditionally.
- Adds no-op POSIX mDNS implementations for native builds.
| File | Description |
|---|---|
FluidNC/src/WebUI/WebUIServer.cpp |
Restores HTTP service advertisement. |
FluidNC/src/WebUI/TelnetServer.cpp |
Restores telnet service advertisement. |
FluidNC/posix/Mdns.cpp |
Provides POSIX mDNS stubs. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
MitchBradley
added a commit
that referenced
this pull request
Oct 10, 2026
#1906 made WebUIServer and TelnetServer register mDNS services unconditionally and added a no-op posix/Mdns.cpp so native builds still link. env:wasm takes only selected posix/ files, so it needs this one too, or WebUIServer's Mdns::add/remove are undefined at link time. (On a base before #1906 the file doesn't exist yet and the filter line matches nothing.) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MitchBradley
added a commit
that referenced
this pull request
Oct 12, 2026
#1906 made WebUIServer and TelnetServer register mDNS services unconditionally and added a no-op posix/Mdns.cpp so native builds still link. env:wasm takes only selected posix/ files, so it needs this one too, or WebUIServer's Mdns::add/remove are undefined at link time. (On a base before #1906 the file doesn't exist yet and the filter line matches nothing.) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MitchBradley
added a commit
that referenced
this pull request
Oct 12, 2026
* wasm: run FluidNC's own web server inside the wasm module The wasm build now includes the real WebUI/ web server -- HTTP routes, WSChannel and WebDAV on unmodified ESPAsyncWebServer -- so a browser can use it exactly as it uses a controller. A web page cannot listen on a socket, so the sockets come from JS instead: - BrowserAsyncTCP/: the AsyncTCP API that ESPAsyncWebServer builds on, over numbered virtual connections that JS opens, feeds and closes with fluidnc_vconn_open/send/close; output returns through self.fluidncOnVconnData/Close. All callbacks run on one async_tcp thread, as on lwIP's task on ESP32. - VirtualNet.cpp: the network module -- always up, at 192.168.0.1 (the access-point address) and <$Hostname>.local -- providing ESP800/ESP111 and the $I and ESP420 network lines. - env:wasm uses Arduino-Emulator, like the posix envs. Library builds are switched to emcc too (previously only project sources were), FS is exported to JS, and wasm/IPAddress.h defers to Arduino-Emulator's. - ESPAsyncWebServer's chunked in-flight pacing is off for this env: with instant acks it stalls responses whose source is briefly empty, which truncated /command replies such as [ESP400] (upstream fix proposed in ESP32Async/ESPAsyncWebServer#488). - The postMessage WebUI bridge this replaces is removed: ShimChannel.cpp, wasm_fs_bridge.cpp and FwInfo.cpp. - vconn_smoke_test.mjs: a headless Node test of HTTP, upload and WebSocket over virtual connections. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * wasm demo: a virtual network from the page to FluidNC's web server A page can't listen on a socket, so these carry a WebUI's traffic to the web server inside the wasm module over its virtual connections. A WebUI loaded from FluidNC then talks ordinary HTTP and WebSocket, unmodified. - vnet-sw.js: a Service Worker (scope device/) that relays every same-origin request from the device frame -- /, /command, /files, /upload, /sd/... -- to the demo page and streams the response back. It decodes gzip (browsers don't decode a Response a worker builds), adds the COEP header the isolated page requires of a nested document, injects the WebSocket stand-in into HTML, and keeps redirects inside its scope. - vnet-ws-shim.js: replaces window.WebSocket in the device frame, since Service Workers can't see WebSockets. It treats the device's names and the page's own host (on any port) as the device, keeps same-device links and window.open inside the frame, and reports in-page URL changes. - vnet-host.js: on the demo page, the HTTP/1.1 and WebSocket client over fluidnc_vconn_*, with a cookie jar (browsers drop Set-Cookie from worker-built responses), and helpers for device names and URLs. Its createClient() core has no DOM dependencies. - vnet_client_test.mjs: drives that client against the wasm server in Node -- gzip, cookies, chunked replies, uploads, the WebUI install sequence, and a WebSocket session. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * wasm demo: run WebUIs the way a controller does The demo now behaves like a board on the network. A WebUI runs only by browsing to FluidNC, which serves it -- or its built-in file manager -- from LocalFS; the demo needs no WebUI-specific code. - An address bar preset to fluidnc.local, with Back/Forward/Reload: paths work as on a board (/?forcefallback=yes, /files?path=/, /command?plain=...), only <$Hostname>.local and the device's IP resolve, and other names, https: and other ports fail as a browser would report it. ?browse=<address> opens the demo at an address, and a navigation that escapes the device frame is sent back into it. - Install WebUI: fetches a project's latest GitHub release (through webui-proxy, which now returns the release's index.html.gz unchanged and which serve.py now also implements for local use) or a local build, and uploads it to LocalFS as index.html.gz through FluidNC's /files route, removing any old index.html/index.html.gz. As after an upload to a board, the user browses to FluidNC to run it. - The Upload/Download panel goes through FluidNC too: /files and /upload for uploads, their JSON for listings, WebDAV /flash and /sd for downloads. - Files and NVS settings persist across reloads in IndexedDB (one saving tab, coordinated with Web Locks), seeded from seed-localfs/ and seed-sd/, with a button to reset to the built-in copies. This supersedes #1900, whose persistence and seeding are included here; its WebUI bridge features are replaced by the above. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * wasm demo: address review findings - vnet-sw.js: never route a frame's requests to another tab's FluidNC. The frame-to-page mapping is lost when the browser stops the idle worker; it used to fall back to any demo page. It now recovers by asking the frame for its page's token (vnet-ws-shim.js answers) and the pages which one owns it, and without an answer guesses only when a single demo page is open -- otherwise the request fails with 503. - vnet-host.js: a Content-Length or chunked body cut short by the server closing is now an error, not a short success; only close-delimited bodies end at close. A WebSocket closed while connect() is still waiting for the server no longer opens an upgrade afterwards. - index.html: the WebUI installer checks each delete and fails if an old index.html survives, since FluidNC would keep serving it. - IPAddress.h: comment named the old env:wasm_webui. - vnet_unit_test.mjs: tests for the above against a fake module and fake browser clients (they fail on the previous code); the integration test also checks the delete replies. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * wasm demo: path-scoped cookie jar; network-order loopback address - vnet-host.js: the cookie jar now follows RFC 6265 path rules instead of keeping one cookie per name. A cookie belongs to its Path (or the directory of the request that set it), is sent only on requests at or under that path, most specific first, and Max-Age=0 or a past Expires removes it. FluidNC's sessionId is set for "/", and the HTTP/UIDir WebUIs of #1885 set a uiSession cookie for "/ui/<name>/" that must reach only that WebUI; sending one UI's uiSession everywhere defeated that isolation. - BrowserAsyncTCP: keep the client and local addresses in network byte order, as lwIP does and IPAddress(uint32_t) expects; the log showed requests "from 1.0.0.127". - vnet_unit_test.mjs: cookie-path tests (they fail on the previous jar). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * env:wasm: link the no-op posix mDNS #1906 made WebUIServer and TelnetServer register mDNS services unconditionally and added a no-op posix/Mdns.cpp so native builds still link. env:wasm takes only selected posix/ files, so it needs this one too, or WebUIServer's Mdns::add/remove are undefined at link time. (On a base before #1906 the file doesn't exist yet and the filter line matches nothing.) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * wasm demo: give the device frame the device's own URLs; log traffic The Service Worker served the device frame under device/, and the prefix showed: a WebUI at /ui/webui2/ saw /device/ui/webui2/ as its own path. WebUI 2's HTTP/UIDir support derives its base from location.pathname, so it fell back to root-UI behavior and saved its preferences to LocalFS. Navigations to a bare "/" also escaped the scope to the demo page. The worker now covers the whole site and routes each request by who made it: frame navigations and requests from nested windows go to FluidNC with exactly their paths; the demo page, its workers and top-level tabs use the network. The device frame therefore sees the same URLs as on a controller -- /, /ui/<name>/, /#/dashboard and the reload helper pages all behave as they would on a board. The frame guard and Location rewriting are gone, the old device/-scoped registration is removed, and the demo must be served from the root of its origin. The virtual network's traffic is now logged to the DevTools console: a line per HTTP exchange (method, path, status, bytes each way, time; the demo page's own requests marked "(demo)") and per WebSocket open/close with message and byte counts. FluidNCVnet.logFrames = true adds each WebSocket message; FluidNCVnet.log = false silences it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Demo: style the controls and frame borders The demo's buttons, drop-downs and address bar get a larger sans-serif font, padding and rounded corners: blue action buttons, grey navigation buttons, and a red outline on Reset, whose explanation moves into its tooltip. The terminal and WebUI frames get a heavier border. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * wasm demo: install a WebUI to /ui/<name>/ as well as LocalFS "Install WebUI to" chooses LocalFS index.html.gz, as before, or /ui/<name> (HTTP/UIDir), with a name defaulting to the project's (figui, webui2, webui3) or the local file's. The latter installs through FluidNC's HTTP interface as a browser on the LAN would: a WebDAV DELETE of any old index.html, which would be served in preference, then PUT /ui/<name>/index.html.gz, which creates the directory. The name localfs is FluidNC's for the LocalFS root, so it installs there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.
Since 3eccd9c ("Portability", #1750), FluidNC no longer advertises its telnet or HTTP services over mDNS. The hostname still resolves (
<hostname>.local), but browsing for_telnet._tcp/_http._tcpfinds nothing. This affects v4.1.0 and v4.1.1.Cause
#1750 put the
Mdns::add/Mdns::removecalls inTelnetServerandWebUI_Serverunder#ifdef HAVE_DNSalong with the captive-portalDNSServer. Nothing definesHAVE_DNS, so the calls are never compiled. (The guardedWMB Mdns::remove(...)would not compile even if it were defined.)Change
TelnetServer.cpp: remove the guard aroundMdns::add/Mdns::remove; includeDriver/fluidnc_mdns.h.WebUIServer.cpp: moveMdns::add("_http", ...)out of the captive-portal block; remove the guard and the strayWMBfromMdns::remove.posix/Mdns.cpp: add a no-opMdnsfor the native simulator. Portability #1750 movedWebUI/Mdns.cpptoesp32/andrp2040/without adding a posix version, but the posix envs still buildWebUI/. Without this file, unguarding the calls would break themacos/linuxlink, which is presumably why they were guarded.The captive portal stays under
HAVE_DNSas before.Testing
wifi,rp2040_wifiandmacos._telnet._tcpand_http._tcpare advertised again and discoverable.