Fix UDS addr corruption sans-autobind (macOS)
`MsgpackUDSStream.get_stream_addrs()` matches the
`(peername, sockname)` pair by type to find the listener's
fs-path, but the `(str, str)` arm unconditionally takes
`peername`: on platforms without linux's
`SO_PASSCRED`-triggered autobind (macOS!) the accept side's
`getpeername()` is `''`, so every accepted conn gets garbage
`Path('')` laddr/raddr structs.
Proven on linux by disabling `SO_PASSCRED` (no autobind ->
same `''` shape as darwin): the `uds_transport_actor_tree.py`
example reports `listener sock file: .` pre-fix and the real
registry sockpath post-fix.
- pick the non-empty name in the `(str, str)` arm: `peername`
on the connect side, `sockname` on the accept side; raise
`ValueError` on an (unexpected) empty pair.
- document the linux-autobind origin of the `bytes` arms
which the original impl noted as "unclear".
- `start_listener()`: create the bindspace dir with
`parents=True, exist_ok=True` (nested custom `filedir`s +
racing actors).
- example docstring: peer-pid comes via `SO_PEERCRED` on
linux but `LOCAL_PEERPID` on macOS.
May not be the (only) macOS crasher for GH #473 — it is
non-fatal on the linux sim — but with stderr surfacing now
in place the next macOS CI run pins any remaining layer.
Prompt-IO: ai/prompt-io/claude/20260702T155006Z_65bf9df5_prompt_io.md
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
wkt/uds_macos_473
parent
7ff4e0a3bf
commit
cec2f9b896
|
|
@ -6,7 +6,8 @@ subactor inherits the preference.
|
|||
|
||||
Every channel address is a filesystem socket path (no TCP port
|
||||
in sight!) and, as a kernel-provided bonus, the peer's pid is
|
||||
exchanged for free via `SO_PEERCRED`.
|
||||
exchanged for free via `SO_PEERCRED` on linux,
|
||||
`LOCAL_PEERPID` on macOS.
|
||||
|
||||
'''
|
||||
import os
|
||||
|
|
@ -42,7 +43,7 @@ async def main() -> None:
|
|||
# (named for the root registrar) this channel rode in
|
||||
# on, NOT a per-child path; the child-specific identity
|
||||
# we get for free is the kernel-reported peer pid (via
|
||||
# `SO_PEERCRED`).
|
||||
# `SO_PEERCRED` on linux, `LOCAL_PEERPID` on macOS).
|
||||
print(
|
||||
f'portal chan tpt proto: {raddr.proto_key!r}\n'
|
||||
f'listener sock file: {raddr.sockpath}\n'
|
||||
|
|
|
|||
|
|
@ -301,7 +301,16 @@ async def start_listener(
|
|||
f'>{{\n'
|
||||
f'|_{bs!r}\n'
|
||||
)
|
||||
bs.mkdir()
|
||||
bs.mkdir(
|
||||
# ensure the full ancestor tree for any nested
|
||||
# (custom `filedir`) bindspace; the default
|
||||
# `get_rt_dir()` space is pre-created but a custom
|
||||
# one may have missing parents.
|
||||
parents=True,
|
||||
# avoid `FileExistsError` from racing actors, same
|
||||
# guard as in `get_rt_dir()`.
|
||||
exist_ok=True,
|
||||
)
|
||||
|
||||
with _reraise_as_connerr(
|
||||
src_excs=(
|
||||
|
|
@ -554,11 +563,18 @@ class MsgpackUDSStream(MsgpackTransport):
|
|||
]:
|
||||
sock: trio.socket.socket = stream.socket
|
||||
|
||||
# NOTE XXX, it's unclear why one or the other ends up being
|
||||
# `bytes` versus the socket-file-path, i presume it's
|
||||
# something to do with who is the server (called `.listen()`)?
|
||||
# maybe could be better implemented using another info-query
|
||||
# on the socket like,
|
||||
# NOTE, the `bytes` case is a linux-only artifact: setting
|
||||
# `SO_PASSCRED` (see `open_unix_socket_w_passcred()`)
|
||||
# causes the kernel to *autobind* the un-named client
|
||||
# sock to an abstract-namespace addr which python
|
||||
# delivers as `bytes`; the listener-bound end is always
|
||||
# the fs-path `str`. On platforms WITHOUT autobind
|
||||
# (macOS et al) the un-bound end instead reports as an
|
||||
# empty `str` so BOTH names arrive as `str`s and the
|
||||
# real fs-path is whichever is non-empty: `peername` on
|
||||
# the connect side, `sockname` on the accept side.
|
||||
#
|
||||
# for socket-api deats see,
|
||||
# https://beej.us/guide/bgnet/html/split-wide/system-calls-or-bust.html#gethostnamewho-am-i
|
||||
sockname: str|bytes = sock.getsockname()
|
||||
# https://beej.us/guide/bgnet/html/split-wide/system-calls-or-bust.html#getpeernamewho-are-you
|
||||
|
|
@ -570,8 +586,24 @@ class MsgpackUDSStream(MsgpackTransport):
|
|||
case (bytes(), str()):
|
||||
sock_path: Path = Path(sockname)
|
||||
|
||||
case (str(), str()): # XXX, likely macOS
|
||||
sock_path: Path = Path(peername)
|
||||
# XXX, no-autobind case (macOS): the un-bound end
|
||||
# is `''`, NOT a `bytes` abstract-ns addr; taking
|
||||
# `peername` unconditionally (as prior impl did)
|
||||
# delivers garbage `Path('')` addrs on the accept
|
||||
# side!
|
||||
case (str(), str()):
|
||||
bound_name: str = (
|
||||
peername
|
||||
or
|
||||
sockname
|
||||
)
|
||||
if not bound_name:
|
||||
raise ValueError(
|
||||
f'Empty UDS (peername, sockname) pair ??\n'
|
||||
f'peername: {peername!r}\n'
|
||||
f'sockname: {sockname!r}\n'
|
||||
)
|
||||
sock_path: Path = Path(bound_name)
|
||||
|
||||
case _:
|
||||
raise TypeError(
|
||||
|
|
|
|||
Loading…
Reference in New Issue