From 2d6b3922a6d614e4611ef3af9d2dac9f8b017ed9 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Thu, 3 Apr 2025 22:24:24 -0400 Subject: [PATCH] Unwrap `UDSAddress` as `tuple[str, str]`, i.e. sin pid Since in hindsight the real analog of a net-proto's "bindspace" (normally its routing layer's addresses-port-set) is more akin to the "location in the file-system" for a UDS socket file (aka the file's parent directory) determines whether or not the "port" (aka it's file-name) collides with any other. So the `._filedir: Path` is like the allocated "address" and, the `._filename: Path|str` is basically the "port", at least in my mind.. Bp Thinking about fs dirs like a "host address" means you can get essentially the same benefits/behaviour of say an (ip) addresses-port-space but using the (current process-namespace's) filesys-tree. Note that for UDS sockets in particular the network-namespace is what would normally isolate so called "abstract sockets" (i.e. UDS sockets that do NOT use file-paths by setting `struct sockaddr_un.sun_path = 'abstract', see `man unix`); using directories is even easier and definitely more explicit/readable/immediately-obvious as a human-user. As such this reworks all the necessary `UDSAddress` meths, - `.unwrap()` now returns a `tuple(str(._filedir, str(._filename))`, - `wrap_address()` now matches UDS on a 2nd tuple `str()` element, - `.get_root()` no longer passes `maybe_pid`. AND adjusts `MsgpackUDSStream` to, - use the new `unwrap_sockpath()` on the `socket.get[sock/peer]name()` output before passing directly as `UDSAddress.__init__(filedir, filename)` instead of via `.from_addr()`. - also pass `maybe_pid`s to init since no longer included in the unwrapped-type form. --- tractor/_addr.py | 64 ++++++++++++++++++++++++++------------------- tractor/ipc/_uds.py | 31 +++++++++++++--------- 2 files changed, 56 insertions(+), 39 deletions(-) diff --git a/tractor/_addr.py b/tractor/_addr.py index e7b92461..eaf4c202 100644 --- a/tractor/_addr.py +++ b/tractor/_addr.py @@ -313,10 +313,18 @@ class UDSAddress(Address): # root actor to create a registry address. maybe_pid: int|None = None, ): - fdir = self._filedir = Path(filedir or self.def_bindspace).absolute() - fpath = self._filepath = Path(filename) + fdir = self._filedir = Path( + filedir + or + self.def_bindspace + ).absolute() + fpath = self._filename = Path(filename) fp: Path = fdir / fpath - assert fp.is_absolute() + assert ( + fp.is_absolute() + and + fp == self.sockpath + ) # to track which "side" is the peer process by reading socket # credentials-info. @@ -324,7 +332,7 @@ class UDSAddress(Address): @property def sockpath(self) -> Path: - return self._filedir / self._filepath + return self._filedir / self._filename @property def is_valid(self) -> bool: @@ -347,19 +355,20 @@ class UDSAddress(Address): def from_addr( cls, addr: ( - tuple[Path|str|None, int] - |Path|str + tuple[Path|str, Path|str]|Path|str ), ) -> UDSAddress: match addr: case tuple()|list(): - sockpath: Path = Path(addr[0]) - filedir, filename = unwrap_sockpath(sockpath) - pid: int = addr[1] + filedir = Path(addr[0]) + filename = Path(addr[1]) + # sockpath: Path = Path(addr[0]) + # filedir, filename = unwrap_sockpath(sockpath) + # pid: int = addr[1] return UDSAddress( filedir=filedir, filename=filename, - maybe_pid=pid, + # maybe_pid=pid, ) # NOTE, in case we ever decide to just `.unwrap()` # to a `Path|str`? @@ -377,8 +386,8 @@ class UDSAddress(Address): # XXX NOTE, since this gets passed DIRECTLY to # `.ipc._uds.open_unix_socket_w_passcred()` return ( - str(self.sockpath), - self._pid, + str(self._filedir), + str(self._filename), ) @classmethod @@ -409,18 +418,18 @@ class UDSAddress(Address): @classmethod def get_root(cls) -> Address: - def_uds_filepath: Path = 'registry@1616.sock' + def_uds_filename: Path = 'registry@1616.sock' return UDSAddress( filedir=None, - filename=def_uds_filepath, - maybe_pid=1616, + filename=def_uds_filename, + # maybe_pid=1616, ) def __repr__(self) -> str: return ( f'{type(self).__name__}' f'[' - f'({self.sockpath}, {self._pid})' + f'({self._filedir}, {self._filename})' f']' ) @@ -430,7 +439,7 @@ class UDSAddress(Address): f'Can not compare {type(other)} with {type(self)}' ) - return self._filepath == other._filepath + return self.sockpath == other.sockpath # async def open_listener(self, **kwargs) -> SocketListener: async def open_listener( @@ -520,14 +529,6 @@ def wrap_address( # if 'sock' in addr[0]: # import pdbp; pdbp.set_trace() match addr: - # TODO! BUT THIS WILL MATCH FOR TCP !... - # -[ ] so prolly go back to what guille had orig XD - # a plain ol' `str`? - # case (( - # str()|Path(), - # int(), - # )): - # cls = UDSAddress # classic network socket-address as tuple/list case ( @@ -537,6 +538,14 @@ def wrap_address( ): cls = TCPAddress + case ( + # (str()|Path(), str()|Path()), + # ^TODO? uhh why doesn't this work!? + + (_, filename) + ) if type(filename) is str: + cls = UDSAddress + # likely an unset UDS or TCP reg address as defaulted in # `_state._runtime_vars['_root_mailbox']` # @@ -552,8 +561,9 @@ def wrap_address( case _: # import pdbp; pdbp.set_trace() raise TypeError( - f'Can not wrap address {type(addr)}\n' - f'{addr!r}\n' + f'Can not wrap unwrapped-address ??\n' + f'type(addr): {type(addr)!r}\n' + f'addr: {addr!r}\n' ) return cls.from_addr(addr) diff --git a/tractor/ipc/_uds.py b/tractor/ipc/_uds.py index 9b0a4bff..3d24447b 100644 --- a/tractor/ipc/_uds.py +++ b/tractor/ipc/_uds.py @@ -38,7 +38,10 @@ from trio._highlevel_open_unix_stream import ( from tractor.msg import MsgCodec from tractor.log import get_logger -from tractor._addr import UDSAddress +from tractor._addr import ( + UDSAddress, + unwrap_sockpath, +) from tractor.ipc._transport import MsgpackTransport @@ -194,16 +197,20 @@ class MsgpackUDSStream(MsgpackTransport): case (bytes(), str()): sock_path: Path = Path(sockname) ( - pid, - uid, - gid, + peer_pid, + _, + _, ) = get_peer_info(sock) - laddr = UDSAddress.from_addr(( - sock_path, - os.getpid(), - )) - raddr = UDSAddress.from_addr(( - sock_path, - pid - )) + + filedir, filename = unwrap_sockpath(sock_path) + laddr = UDSAddress( + filedir=filedir, + filename=filename, + maybe_pid=os.getpid(), + ) + raddr = UDSAddress( + filedir=filedir, + filename=filename, + maybe_pid=peer_pid + ) return (laddr, raddr)