WIP: fix(runtime): support control bridge Unix sockets on macOS #456

Draft
mooki wants to merge 2 commits from mooki/Longshot:mac/control-sockets into main
Member

What this is for: anyone running the game's control bridge (HOS_CONTROL) on a Mac, and the game-free check that
drives it. host/control.c uses Linux-only socket calls (SOCK_CLOEXEC, SOCK_NONBLOCK, accept4, SO_PEERCRED), so it
does not compile on macOS. This PR gives the bridge's Unix socket a macOS path, part of the macOS port (#420).
What is measured: on an Apple M4 Max with macOS 26.7.1, tests/test_control.py fails on main (the compile) and
passes here, two interleaved runs each, and passes for arm64 and for x86_64 under Rosetta (38 PASS lines each). The
non-Apple text of host/control.c is byte for byte main's. And the whole suite is compared by test name with main.
Not measured: Windows and Linux runs, macOS 14.4, an Intel Mac, a client of another user, a game run.

Why

host/control.c's transport is a Unix socket on Linux, written with Linux's socket flags, accept4 and SO_PEERCRED.
None exists on macOS, and macOS also differs in what a full listen queue and a closed peer look like.

What changed

  • host/posix/darwin_control_sockets.c and .h (new): the socket calls on macOS, with public APIs only (socket,
    accept, fcntl, getpeereid):
    • each descriptor is made non-blocking and close-on-exec with fcntl, checked, and closed on failure;
    • an accepted client whose kernel-reported UID is not this user's, or cannot be read, is refused;
    • a stale socket is told from a live one with a full queue: macOS refuses a stream connect with ECONNREFUSED in both
      cases, so a datagram probe (EPROTOTYPE on a live stream socket) decides, without joining its queue. An unknown
      answer leaves the file alone;
    • the listen queue is SOMAXCONN, so a burst of clients gets the existing busy reply; eight active clients stay the
      limit;
    • after a read's end of file, a zero-byte send without SIGPIPE tells a half-close from a peer gone, so replies to a
      half-closed client are still sent.
  • host/control.c: small #if defined(__APPLE__) branches at those calls, and sun_len with the exact address
    length. The path-length check, the private folder checks and mode 0600 are unchanged. Removing the Apple branches gives
    main's file byte for byte.
  • tests/test_control.py: on macOS, it also builds and runs tests/control_darwin_test.c: path bounds (103 and 104
    bytes), a live socket kept and a stale one replaced, a full live queue not taken for stale, the UID refusal, the
    descriptor flags, an exec that must not inherit them, and EPIPE without SIGPIPE. --arch arm64 or --arch x86_64
    builds both fixtures for that target and runs them through arch. tests/control_test.c is unchanged.
  • tests/test_oot_state_tap.py (added on main by #58) builds host/control.c into its own fixture: on macOS it now
    links darwin_control_sockets.c as well, as test_control.py does. Its Windows and Linux commands are unchanged.
  • docs/control.md: the macOS transport and its tests.
  • Unchanged: Windows and Linux, host/hos_relaunch.c, host/discord_rpc.c, nx2/build.py (the build-flags PR
    compiles every host/posix/darwin_*.c on macOS, this file included) and third_party/.

Rebase onto 5e072fc8. main's #58 changed the same lines of tests/test_control.py and docs/control.md:

  • test_control.py: both argument sets are kept (--source-root from #58, --arch from this PR). The macOS build takes
    -I <source root>/host and the bridge's sources from --source-root too. The Windows and Linux build is #58's,
    unchanged.
  • docs/control.md: both paragraphs are kept.

Flags and settings

No runtime switch. HOS_CONTROL stays off unless set. The test driver gains one option:

Flag What it does Default now Recommendation Helps on Doesn't help on Untested on
tests/test_control.py --arch arm64 / x86_64 Builds both control fixtures for that Apple target and runs them through arch (Rosetta for x86_64) The compiler's own target Run both routes when changing the transport macOS Windows and Linux: not registered there macOS 14.4, an Intel Mac

Measurements

main: 5e072fc8c2adadba5ea610148be1c47800ba0cca (2026-11-14)
this PR: mac/control-sockets @ f1f1843db3c687b6b1e4017ef525690b324fd887
Hardware: Apple M4 Max, 16 cores, 64 GiB, macOS 26.7.1 (25G241); Apple clang 21.0.0. No GPU.
Scene: none. Game-free checks.
Method: tests/test_control.py, tests/test_longshot_ctl.py and tests/test_oot_state_tap.py through tests/run_all.py
on main and on this PR, interleaved, two runs each. tests/test_control.py --cc clang --arch arm64, then
--arch x86_64. host/control.c with its Apple branches removed, compared with main's. The whole suite on this PR,
compared by test name with a main run on the same Mac.
How to reproduce: python -I -B tests/test_control.py --cc clang --arch arm64 (and --arch x86_64), with a short
TMPDIR.

main @ 5e072fc8 this PR @ f1f1843d
tests/test_control.py (run 1 / run 2) FAIL / FAIL: host/control.c:2014, SOCK_CLOEXEC undeclared pass / pass
tests/test_longshot_ctl.py pass / pass pass / pass
tests/test_oot_state_tap.py FAIL / FAIL: the fixture's vsnprintf macro, then control.c's socket calls FAIL / FAIL: the fixture's vsnprintf macro only
test_control.py --arch arm64 / --arch x86_64 exit 0, 38 PASS lines / exit 0, the same 38 lines
host/control.c without its Apple branches byte for byte main's
main @ 5e072fc8:
/Users/mooki/code/longshot-wt/suite-5e072fc8/host/control.c:2014:57: error: use of undeclared identifier 'SOCK_CLOEXEC'
1 passed, 2 failed, 0 skipped in 5 s (linux, 6 at once)

this PR @ f1f1843d, --arch arm64 and --arch x86_64, each:
PASS: macOS 104-byte path refused before opening or replacing anything
PASS: macOS a full live listen queue is not unlinked as stale
PASS: macOS 103-byte path with sun_len; live socket kept, stale socket replaced, mode 0600
PASS: macOS a queued burst reaches eight clients and four busy replies
PASS: macOS kernel peer UID mismatch closes the accepted socket; unknown credentials fail closed
PASS: macOS listener and accepted descriptors are nonblocking and close-on-exec; empty accept/read return EAGAIN
PASS: macOS exec closes listener, accepted and probe sockets; an unmarked descriptor survives
PASS: macOS half-close keeps replies possible; full closure is noticed without POLLIN
PASS: macOS closed peer returns EPIPE without SIGPIPE and the transport closes the connection
exit=0

UNCHANGED_NON_APPLE host/control.c bytes=114443 sha256=c43d94520ea9e2b7fda2b4d07cb0b3ecb9e5e5d80ad0e5d652080e600ef6060d
PASS non-Apple text equals main

Testing

Tested: the above, and the whole suite, tests/run_all.py, 6 at once, on the same Mac:

main @ 5e072fc8:     525 passed, 19 failed, 17 skipped in 177 s (linux, 6 at once)
this PR @ f1f1843d:  525 passed, 19 failed, 17 skipped in 362 s (linux, 6 at once)
  • By test name nothing changed, and the same 19 checks fail on both. But tests/test_control.py failed here for
    another reason than on main:
    every case passed, the macOS ones included, and then its quit case hit the
    fixture's start-up race and ran into the 180 s limit (TimeoutExpired: … 'quit'). The Mac's load was about 30 at
    the time. The race is in tests/control_test.c, not in the bridge: its parent connects once the socket's file
    exists, before the bridge listens, and its forked bridge then serves on. It is the next PR's fix
    (mac/control-quit). That forked bridge was found still running after the suite, with its listening socket, no
    client and the suite's pipes, sampled and ended. test_control.py passed in the four other runs of this head (two
    through run_all.py, one per architecture), and in two at its first commit, 3e335a41, whose test files are the same.

  • The other 18 failures are main's on this Mac, fixed by the port's other PRs or stale on main:
    test_appimage_package_retry, test_collect_wide, test_framegen_resources, test_game_layout,
    test_low_memory_notice, test_mem_gate, test_mem_gate_children, test_mirror_trim, test_module_ids,
    test_oot_state_tap, test_pad_layout, test_pcache_header_read, test_pipeline_cache_file,
    test_pipeline_cache_save, test_pipeline_play_cache, test_prof_symbols, test_program_cache_cleanup,
    test_program_cache_one_variant.

  • Crash reports: three from MTLCompilerService during the run; no game-free check uses Metal [inference: other
    work on this Mac].

  • tests/test_oot_state_tap.py with the runner PR as well: on a scratch tree of this PR plus that PR's fixture repair
    (not a branch), it passes on this Mac.

Not tested:

  • Windows and Linux. Their source is byte for byte main's, and their test commands are #58's.
  • macOS 14.4, an Intel Mac, a client of another user (the UID case compares a real kernel UID with a deliberately
    different one), and a game run.
  • Close-on-exec is set after the socket is made, with fcntl: it is not atomic. Nothing on macOS execs while the
    bridge runs today: host/hos_relaunch.c reads /proc/self/cmdline and returns at lines 79-82 before its execve. A
    macOS relaunch must close inherited descriptors (for example POSIX_SPAWN_CLOEXEC_DEFAULT) or stop the bridge first.
    The renderer's child launch already closes them (posix_spawn_file_actions_addclosefrom_np, gpu/vk/vk_menu.cpp:2115).

Needs other testers:

  • Windows (llvm-mingw): tests/test_control.py and the whole suite. Expect the named pipe's cases and the same results as
    main (request to open).
  • Linux: the same, with the Unix socket's cases (request to open).
  • macOS 14.4 or an Intel Mac: tests/test_control.py --arch <its arch>, expecting the same 38 PASS lines (request to
    open).

Screenshots

Nothing on screen.

Risk and rollback

  • macOS's end-of-file and listen-queue behaviour differs from Linux's; the new cases pin what this Mac does, and the
    oldest supported macOS should run them.
  • The larger listen queue does not raise the limit of eight clients.
  • The bridge stays off unless HOS_CONTROL is set. Rollback: revert the PR; Windows and Linux are the same either way.

Reviewer notes

  • Start with host/posix/darwin_control_sockets.c, then control.c's Apple branches, then tests/control_darwin_test.c.
    Written from Apple's SDK headers and the socket(2), fcntl(2), accept(2), listen(2), connect(2),
    getpeereid(3), poll(2) and send(2) pages.
  • f1f1843d is new since the first version (cef1193a): #58's test_oot_state_tap.py builds control.c and met this
    PR's helper.
  • host/discord_rpc.c is a socket client of its own and not part of this PR.
  • With this PR test_control.py builds on macOS, and its quit case can then hang under load (above), as it can on
    Linux [inference: not run there]. The control-quit PR, stacked on this one, fixes that fixture; best merged right
    after it.
  • Review both commits, 3e335a41 and f1f1843d: the whole branch is this PR's own (it depends on no other PR).

Issues

See #420.

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main. (Branched from 5e072fc8; #58's conflicts resolved as above.)
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above). Every
    failure also fails on main, but test_control.py's fails here at the fixture's quit race (under Testing), which
    mac/control-quit fixes.
  • Tested in the game, or what wasn't is named under Testing. (No game run; named under Testing.)
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). The test
    requests are still to open.
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. (For a fix: the test fails on main and passes here, two interleaved runs each.)
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

If applicable

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • A game-free test added for the fix, failing on main and passing here.
  • A check under tests/ that reads changed source updated in this PR, not weakened.
  • Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. Not built there; the non-Apple text is
    main's byte for byte.
  • Docs updated.
**What this is for:** anyone running the game's control bridge (`HOS_CONTROL`) on a Mac, and the game-free check that drives it. `host/control.c` uses Linux-only socket calls (`SOCK_CLOEXEC`, `SOCK_NONBLOCK`, `accept4`, `SO_PEERCRED`), so it does not compile on macOS. This PR gives the bridge's Unix socket a macOS path, part of the macOS port (#420). **What is measured:** on an Apple M4 Max with macOS 26.7.1, `tests/test_control.py` fails on `main` (the compile) and passes here, two interleaved runs each, and passes for arm64 and for x86_64 under Rosetta (38 PASS lines each). The non-Apple text of `host/control.c` is byte for byte `main`'s. And the whole suite is compared by test name with `main`. **Not measured:** Windows and Linux runs, macOS 14.4, an Intel Mac, a client of another user, a game run. ## Why `host/control.c`'s transport is a Unix socket on Linux, written with Linux's socket flags, `accept4` and `SO_PEERCRED`. None exists on macOS, and macOS also differs in what a full listen queue and a closed peer look like. ## What changed - **`host/posix/darwin_control_sockets.c` and `.h` (new):** the socket calls on macOS, with public APIs only (`socket`, `accept`, `fcntl`, `getpeereid`): - each descriptor is made non-blocking and close-on-exec with `fcntl`, checked, and closed on failure; - an accepted client whose kernel-reported UID is not this user's, or cannot be read, is refused; - a stale socket is told from a live one with a full queue: macOS refuses a stream connect with `ECONNREFUSED` in both cases, so a datagram probe (`EPROTOTYPE` on a live stream socket) decides, without joining its queue. An unknown answer leaves the file alone; - the listen queue is `SOMAXCONN`, so a burst of clients gets the existing busy reply; eight active clients stay the limit; - after a read's end of file, a zero-byte send without `SIGPIPE` tells a half-close from a peer gone, so replies to a half-closed client are still sent. - **`host/control.c`:** small `#if defined(__APPLE__)` branches at those calls, and `sun_len` with the exact address length. The path-length check, the private folder checks and mode 0600 are unchanged. Removing the Apple branches gives `main`'s file byte for byte. - **`tests/test_control.py`:** on macOS, it also builds and runs `tests/control_darwin_test.c`: path bounds (103 and 104 bytes), a live socket kept and a stale one replaced, a full live queue not taken for stale, the UID refusal, the descriptor flags, an exec that must not inherit them, and `EPIPE` without `SIGPIPE`. `--arch arm64` or `--arch x86_64` builds both fixtures for that target and runs them through `arch`. `tests/control_test.c` is unchanged. - **`tests/test_oot_state_tap.py`** (added on `main` by #58) builds `host/control.c` into its own fixture: on macOS it now links `darwin_control_sockets.c` as well, as `test_control.py` does. Its Windows and Linux commands are unchanged. - **`docs/control.md`:** the macOS transport and its tests. - **Unchanged:** Windows and Linux, `host/hos_relaunch.c`, `host/discord_rpc.c`, `nx2/build.py` (the build-flags PR compiles every `host/posix/darwin_*.c` on macOS, this file included) and `third_party/`. **Rebase onto `5e072fc8`.** `main`'s #58 changed the same lines of `tests/test_control.py` and `docs/control.md`: - `test_control.py`: both argument sets are kept (`--source-root` from #58, `--arch` from this PR). The macOS build takes `-I <source root>/host` and the bridge's sources from `--source-root` too. The Windows and Linux build is #58's, unchanged. - `docs/control.md`: both paragraphs are kept. ## Flags and settings No runtime switch. `HOS_CONTROL` stays off unless set. The test driver gains one option: | Flag | What it does | Default now | Recommendation | Helps on | Doesn't help on | Untested on | |---|---|---|---|---|---|---| | `tests/test_control.py --arch arm64` / `x86_64` | Builds both control fixtures for that Apple target and runs them through `arch` (Rosetta for x86_64) | The compiler's own target | Run both routes when changing the transport | macOS | Windows and Linux: not registered there | macOS 14.4, an Intel Mac | ## Measurements main: `5e072fc8c2adadba5ea610148be1c47800ba0cca` (2026-11-14) this PR: `mac/control-sockets` @ `f1f1843db3c687b6b1e4017ef525690b324fd887` Hardware: Apple M4 Max, 16 cores, 64 GiB, macOS 26.7.1 (25G241); Apple clang 21.0.0. No GPU. Scene: none. Game-free checks. Method: `tests/test_control.py`, `tests/test_longshot_ctl.py` and `tests/test_oot_state_tap.py` through `tests/run_all.py` on `main` and on this PR, interleaved, two runs each. `tests/test_control.py --cc clang --arch arm64`, then `--arch x86_64`. `host/control.c` with its Apple branches removed, compared with `main`'s. The whole suite on this PR, compared by test name with a `main` run on the same Mac. How to reproduce: `python -I -B tests/test_control.py --cc clang --arch arm64` (and `--arch x86_64`), with a short `TMPDIR`. | | main @ 5e072fc8 | this PR @ f1f1843d | |---|---|---| | `tests/test_control.py` (run 1 / run 2) | FAIL / FAIL: `host/control.c:2014`, `SOCK_CLOEXEC` undeclared | pass / pass | | `tests/test_longshot_ctl.py` | pass / pass | pass / pass | | `tests/test_oot_state_tap.py` | FAIL / FAIL: the fixture's `vsnprintf` macro, then `control.c`'s socket calls | FAIL / FAIL: the fixture's `vsnprintf` macro only | | `test_control.py --arch arm64` / `--arch x86_64` | | exit 0, 38 PASS lines / exit 0, the same 38 lines | | `host/control.c` without its Apple branches | | byte for byte `main`'s | ``` main @ 5e072fc8: /Users/mooki/code/longshot-wt/suite-5e072fc8/host/control.c:2014:57: error: use of undeclared identifier 'SOCK_CLOEXEC' 1 passed, 2 failed, 0 skipped in 5 s (linux, 6 at once) this PR @ f1f1843d, --arch arm64 and --arch x86_64, each: PASS: macOS 104-byte path refused before opening or replacing anything PASS: macOS a full live listen queue is not unlinked as stale PASS: macOS 103-byte path with sun_len; live socket kept, stale socket replaced, mode 0600 PASS: macOS a queued burst reaches eight clients and four busy replies PASS: macOS kernel peer UID mismatch closes the accepted socket; unknown credentials fail closed PASS: macOS listener and accepted descriptors are nonblocking and close-on-exec; empty accept/read return EAGAIN PASS: macOS exec closes listener, accepted and probe sockets; an unmarked descriptor survives PASS: macOS half-close keeps replies possible; full closure is noticed without POLLIN PASS: macOS closed peer returns EPIPE without SIGPIPE and the transport closes the connection exit=0 UNCHANGED_NON_APPLE host/control.c bytes=114443 sha256=c43d94520ea9e2b7fda2b4d07cb0b3ecb9e5e5d80ad0e5d652080e600ef6060d PASS non-Apple text equals main ``` ## Testing **Tested:** the above, and the whole suite, `tests/run_all.py`, 6 at once, on the same Mac: ``` main @ 5e072fc8: 525 passed, 19 failed, 17 skipped in 177 s (linux, 6 at once) this PR @ f1f1843d: 525 passed, 19 failed, 17 skipped in 362 s (linux, 6 at once) ``` - **By test name nothing changed, and the same 19 checks fail on both. But `tests/test_control.py` failed here for another reason than on `main`:** every case passed, the macOS ones included, and then its `quit` case hit the fixture's start-up race and ran into the 180 s limit (`TimeoutExpired: … 'quit'`). The Mac's load was about 30 at the time. The race is in `tests/control_test.c`, not in the bridge: its parent connects once the socket's file exists, before the bridge listens, and its forked bridge then serves on. It is the next PR's fix (`mac/control-quit`). That forked bridge was found still running after the suite, with its listening socket, no client and the suite's pipes, sampled and ended. `test_control.py` passed in the four other runs of this head (two through `run_all.py`, one per architecture), and in two at its first commit, `3e335a41`, whose test files are the same. - The other 18 failures are `main`'s on this Mac, fixed by the port's other PRs or stale on `main`: `test_appimage_package_retry`, `test_collect_wide`, `test_framegen_resources`, `test_game_layout`, `test_low_memory_notice`, `test_mem_gate`, `test_mem_gate_children`, `test_mirror_trim`, `test_module_ids`, `test_oot_state_tap`, `test_pad_layout`, `test_pcache_header_read`, `test_pipeline_cache_file`, `test_pipeline_cache_save`, `test_pipeline_play_cache`, `test_prof_symbols`, `test_program_cache_cleanup`, `test_program_cache_one_variant`. - **Crash reports:** three from `MTLCompilerService` during the run; no game-free check uses Metal [inference: other work on this Mac]. - **`tests/test_oot_state_tap.py` with the runner PR as well:** on a scratch tree of this PR plus that PR's fixture repair (not a branch), it passes on this Mac. **Not tested:** - **Windows and Linux.** Their source is byte for byte `main`'s, and their test commands are #58's. - **macOS 14.4, an Intel Mac, a client of another user** (the UID case compares a real kernel UID with a deliberately different one), and a game run. - **Close-on-exec is set after the socket is made**, with `fcntl`: it is not atomic. Nothing on macOS execs while the bridge runs today: `host/hos_relaunch.c` reads `/proc/self/cmdline` and returns at lines 79-82 before its `execve`. A macOS relaunch must close inherited descriptors (for example `POSIX_SPAWN_CLOEXEC_DEFAULT`) or stop the bridge first. The renderer's child launch already closes them (`posix_spawn_file_actions_addclosefrom_np`, `gpu/vk/vk_menu.cpp:2115`). **Needs other testers:** - Windows (llvm-mingw): `tests/test_control.py` and the whole suite. Expect the named pipe's cases and the same results as `main` (request to open). - Linux: the same, with the Unix socket's cases (request to open). - macOS 14.4 or an Intel Mac: `tests/test_control.py --arch <its arch>`, expecting the same 38 PASS lines (request to open). ## Screenshots Nothing on screen. ## Risk and rollback - macOS's end-of-file and listen-queue behaviour differs from Linux's; the new cases pin what this Mac does, and the oldest supported macOS should run them. - The larger listen queue does not raise the limit of eight clients. - The bridge stays off unless `HOS_CONTROL` is set. Rollback: revert the PR; Windows and Linux are the same either way. ## Reviewer notes - Start with `host/posix/darwin_control_sockets.c`, then `control.c`'s Apple branches, then `tests/control_darwin_test.c`. Written from Apple's SDK headers and the `socket(2)`, `fcntl(2)`, `accept(2)`, `listen(2)`, `connect(2)`, `getpeereid(3)`, `poll(2)` and `send(2)` pages. - `f1f1843d` is new since the first version (`cef1193a`): #58's `test_oot_state_tap.py` builds `control.c` and met this PR's helper. - `host/discord_rpc.c` is a socket client of its own and not part of this PR. - With this PR `test_control.py` builds on macOS, and its quit case can then hang under load (above), as it can on Linux [inference: not run there]. The control-quit PR, stacked on this one, fixes that fixture; best merged right after it. - Review both commits, `3e335a41` and `f1f1843d`: the whole branch is this PR's own (it depends on no other PR). ## Issues See #420. ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [x] Rebased on current `main`. (Branched from 5e072fc8; #58's conflicts resolved as above.) - [ ] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). Every failure also fails on `main`, but `test_control.py`'s fails here at the fixture's quit race (under Testing), which `mac/control-quit` fixes. - [x] Tested in the game, or what wasn't is named under Testing. (No game run; named under Testing.) - [ ] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). The test requests are still to open. - [x] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. (For a `fix`: the test fails on `main` and passes here, two interleaved runs each.) - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### If applicable - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] A game-free test added for the fix, failing on `main` and passing here. - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. - [ ] Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. Not built there; the non-Apple text is `main`'s byte for byte. - [x] Docs updated.
Use public Darwin socket, fcntl and getpeereid calls behind Apple-only
branches. Keep the real sockaddr_un path bound, set sun_len, and retain
private-directory and mode checks. Fail closed on peer verification.

Distinguish full disconnects from half-closes without SIGPIPE. Keep full
live listen queues safe from stale-socket removal and allow queued client
bursts to reach the existing busy reply. Leave Linux and Windows source
paths unchanged.

Extend the real game-free control fixture for both Apple clang targets,
including descriptor flags and an exec child. Document the non-atomic
fcntl window and the separate future macOS process-lifecycle requirement.

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <[email protected]>
Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
test(control): link the bridge's macOS socket helpers into test_oot_state_tap's fixture
All checks were successful
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 4s
PR description / Description follows the template (pull_request_target) Successful in 6s
CI / Workflow lint (actionlint) (pull_request) Successful in 7s
Third-party parts / As their notes say (pull_request) Successful in 12s
Website / Website on Cloudflare (pull_request_target) Has been skipped
f1f1843db3
Main's tests/test_oot_state_tap.py (sampled-state streaming, #58) builds
host/control.c into its own fixture. On macOS, control.c now calls the
Unix socket helpers in host/posix/darwin_control_sockets.c, so the
fixture adds that file there, as tests/test_control.py does. The
Windows and Linux compile commands are unchanged.

With the runner PR's repair of the fixture's vsnprintf macro, the check
passes on macOS; without it, it still stops at that macro.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
All checks were successful
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 4s
PR description / Description follows the template (pull_request_target) Successful in 6s
CI / Workflow lint (actionlint) (pull_request) Successful in 7s
Third-party parts / As their notes say (pull_request) Successful in 12s
Website / Website on Cloudflare (pull_request_target) Has been skipped
This pull request has changes conflicting with the target branch.
  • docs/control.md
View command line instructions

Manual merge helper

Use this merge commit message when completing the merge manually.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u 'mac/control-sockets:mooki-mac/control-sockets'
git switch 'mooki-mac/control-sockets'
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Longshot!456
No description provided.