Support UDS on macos (for realz)
Though it was a good (vibed) try by @dnks, the previous "fix" was not actually adding unix socket support but merely sidestepping a crash due to `get_peer_info()`'s impl never going to work on MacOS (and it was never intended to). This patch instead solves the underlying issue by implementing a new `get_peer_pid()` helper which does in fact retrieve the peer's PID in a more generic/cross-platform way (:fingers_crossed:); much thanks to the linked SO answer for this solution! Impl deats, - add `get_peer_pid()` and call it from `MsgpackUDSStream.get_stream_addrs()` when we detect a non-'linux' platform, OW use the original soln: `get_stream_addrs()`. - add a new case for the `match (peername, sockname)` with a `case (str(), str()):` which seems to at least work on macos. - drop all the `LOCAL_PEERCRED` dynamic import branching since it was never needed and was never going to work.ns_aware
parent
d8a3969048
commit
521fb97fe9
|
|
@ -24,10 +24,12 @@ from contextlib import (
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import socket as stdlib_socket
|
||||||
from socket import (
|
from socket import (
|
||||||
AF_UNIX,
|
AF_UNIX,
|
||||||
SOCK_STREAM,
|
SOCK_STREAM,
|
||||||
SOL_SOCKET,
|
SOL_SOCKET,
|
||||||
|
error as socket_error,
|
||||||
)
|
)
|
||||||
import struct
|
import struct
|
||||||
from typing import (
|
from typing import (
|
||||||
|
|
@ -70,19 +72,19 @@ if sys.platform == 'linux':
|
||||||
SO_PEERCRED,
|
SO_PEERCRED,
|
||||||
)
|
)
|
||||||
|
|
||||||
# NOTE, macOS uses `LOCAL_PEERCRED` instead of `SO_PEERCRED` and
|
|
||||||
# doesn't need `SO_PASSCRED` (credential passing is always enabled).
|
|
||||||
# XXX See code in <sys/un.h>: `#define LOCAL_PEERCRED 0x001`
|
|
||||||
#
|
|
||||||
elif sys.platform == 'darwin': # macOS
|
|
||||||
LOCAL_PEERCRED: int = 0x0001
|
|
||||||
SO_PEERCRED:int|None = LOCAL_PEERCRED # Alias for compatibility
|
|
||||||
SO_PASSCRED: int|None = None # Not needed/available on macOS
|
|
||||||
else:
|
else:
|
||||||
# Other Unix platforms - may need additional handling
|
# Other (Unix) platforms - though further testing is required and
|
||||||
|
# others may need additional special handling?
|
||||||
SO_PASSCRED = None
|
SO_PASSCRED = None
|
||||||
SO_PEERCRED = None
|
SO_PEERCRED = None
|
||||||
|
|
||||||
|
# NOTE, macOS uses `LOCAL_PEERCRED` instead of `SO_PEERCRED` and
|
||||||
|
# doesn't need `SO_PASSCRED` (credential passing is always enabled).
|
||||||
|
# See code in <sys/un.h>: `#define LOCAL_PEERCRED 0x001`
|
||||||
|
#
|
||||||
|
# XXX INSTEAD we use the (hopefully) more generic
|
||||||
|
# `get_peer_pid()` below for other OSes.
|
||||||
|
|
||||||
|
|
||||||
log = get_logger()
|
log = get_logger()
|
||||||
|
|
||||||
|
|
@ -186,7 +188,11 @@ class UDSAddress(
|
||||||
err_on_no_runtime=False,
|
err_on_no_runtime=False,
|
||||||
)
|
)
|
||||||
if actor:
|
if actor:
|
||||||
sockname: str = '::'.join(actor.uid) + f'@{pid}'
|
sockname: str = f'{actor.aid.name}@{pid}'
|
||||||
|
# XXX, orig version which broke both macOS (file-name
|
||||||
|
# length) and `multiaddrs` ('::' invalid separator).
|
||||||
|
# sockname: str = '::'.join(actor.uid) + f'@{pid}'
|
||||||
|
#
|
||||||
# ?^TODO, for `multiaddr`'s parser we can't use the `::`
|
# ?^TODO, for `multiaddr`'s parser we can't use the `::`
|
||||||
# above^, SO maybe a `.` or something else here?
|
# above^, SO maybe a `.` or something else here?
|
||||||
# sockname: str = '.'.join(actor.uid) + f'@{pid}'
|
# sockname: str = '.'.join(actor.uid) + f'@{pid}'
|
||||||
|
|
@ -347,6 +353,26 @@ async def open_unix_socket_w_passcred(
|
||||||
return trio.SocketStream(sock)
|
return trio.SocketStream(sock)
|
||||||
|
|
||||||
|
|
||||||
|
def get_peer_pid(sock) -> int|None:
|
||||||
|
'''
|
||||||
|
Gets the PID of the process connected to the other end of a Unix
|
||||||
|
domain socket on macOS, or `None` if that fails.
|
||||||
|
|
||||||
|
NOTE, should work on MacOS (and others?).
|
||||||
|
|
||||||
|
'''
|
||||||
|
# try to get the peer PID
|
||||||
|
# https://stackoverflow.com/a/67971484
|
||||||
|
try:
|
||||||
|
pid: int = sock.getsockopt(0, 2)
|
||||||
|
return pid
|
||||||
|
except socket_error as e:
|
||||||
|
log.exception(
|
||||||
|
f"Failed to get peer PID: {e}"
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_peer_info(
|
def get_peer_info(
|
||||||
sock: trio.socket.socket,
|
sock: trio.socket.socket,
|
||||||
) -> tuple[
|
) -> tuple[
|
||||||
|
|
@ -358,8 +384,7 @@ def get_peer_info(
|
||||||
Deliver the connecting peer's "credentials"-info as defined in
|
Deliver the connecting peer's "credentials"-info as defined in
|
||||||
a platform-specific way.
|
a platform-specific way.
|
||||||
|
|
||||||
On Linux, uses SO_PEERCRED.
|
Linux-ONLY, uses SO_PEERCRED.
|
||||||
On macOS, uses LOCAL_PEERCRED.
|
|
||||||
|
|
||||||
For more deats see,
|
For more deats see,
|
||||||
- `man accept`,
|
- `man accept`,
|
||||||
|
|
@ -480,14 +505,32 @@ class MsgpackUDSStream(MsgpackTransport):
|
||||||
match (peername, sockname):
|
match (peername, sockname):
|
||||||
case (str(), bytes()):
|
case (str(), bytes()):
|
||||||
sock_path: Path = Path(peername)
|
sock_path: Path = Path(peername)
|
||||||
|
|
||||||
case (bytes(), str()):
|
case (bytes(), str()):
|
||||||
sock_path: Path = Path(sockname)
|
sock_path: Path = Path(sockname)
|
||||||
|
|
||||||
|
case (str(), str()): # XXX, likely macOS
|
||||||
|
sock_path: Path = Path(peername)
|
||||||
|
|
||||||
|
case _:
|
||||||
|
raise TypeError(
|
||||||
|
f'Failed to match (peername, sockname) types?\n'
|
||||||
|
f'peername: {peername!r}\n'
|
||||||
|
f'sockname: {sockname!r}\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
if sys.platform == 'linux':
|
||||||
(
|
(
|
||||||
peer_pid,
|
peer_pid,
|
||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
) = get_peer_info(sock)
|
) = get_peer_info(sock)
|
||||||
|
|
||||||
|
# NOTE known to at least works on,
|
||||||
|
# - macos
|
||||||
|
else:
|
||||||
|
peer_pid: int = get_peer_pid(sock)
|
||||||
|
|
||||||
filedir, filename = unwrap_sockpath(sock_path)
|
filedir, filename = unwrap_sockpath(sock_path)
|
||||||
laddr = UDSAddress(
|
laddr = UDSAddress(
|
||||||
filedir=filedir,
|
filedir=filedir,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue