mirror of
https://github.com/jmcorgan/fips.git
synced 2026-10-30 07:37:36 +00:00
macOS never grants Bluetooth to a root launchd daemon: CoreBluetooth answers it Unauthorized whatever the privacy settings say, so the packaged daemon could not use the CoreBluetooth backend at all. When CoreBluetooth refuses the daemon, it listens on ble-agent.sock beside the control socket (/var/run/fips, group fips), and a per-user LaunchAgent runs `fips-ble-agent --ble-agent` in the login session, lending its radio to the daemon over a small framed protocol (io_macos/agent*.rs). Each agent connection that says a valid hello is installed as the radio, replacing the previous one, so the transport is unchanged; a lost agent is a radio switched off. A connection has five seconds to say hello. The agent re-resolves the socket path on every reconnect, so one started before the daemon created its runtime directory does not settle on a fallback path. The agent connects only once its radio is up, and its hello carries the PSM CoreBluetooth published, read afresh for every connection. Before the radio is up `listen` reports only the requested fallback, so a hello sent then told the daemon PSM 133 while the listener was on another, and kept telling it so across reconnects and Bluetooth toggles. fips-ble-agent is a hard link to fips, so Activity Monitor tells the two processes apart. The agent logs to ~/Library/Logs/fips/ble-agent.log, rolled like the daemon's log, rather than to a shared path in /tmp another account could plant a file or symlink in. Install, upgrade and uninstall stop and start the agent in every GUI session, so none keeps running a replaced binary. The agent ends on the stop signal the process holds from the start, so a bootout does not wait out launchd's timeout. The daemon/agent pair is tested end to end over a real Unix socket and MockBleIo on every host: listener PSM, advertising, adverts, dialled and inbound channels both ways, refusal, a lost agent, a connection that never says hello, and an agent whose radio comes up after it starts.