Add `Address.rebind_from_sockname` opt-out
Gate `Endpoint.start_listener()`s `getsockname()`-vs-`.addr` reconciliation on a new per-addr-type `ClassVar[bool]`, set `True` on both `TCPAddress` and `UDSAddress` so existing behaviour is bit-for-bit unchanged. That reconciliation exists ONLY to learn a kernel-assigned port from a `port=0` tcp bind (its own comment says so). The incoming `tipc` backend (gh #378) has no late-binding analogue AND its `getsockname()` answers a `TIPC_ADDR_ID` port-id rather than the name-seq it published — rebinding from that would swap a dialable service name for an un-dialable, un-reconstructable port id. So opting out is semantically right rather than a hack. (this patch was generated in some part by `claude-code` using `claude-opus-5` (`anthropic`))wkt/pr493_review
parent
d4737e957f
commit
cca3a70de4
|
|
@ -82,6 +82,16 @@ UnwrappedAddress = (
|
|||
class Address(Protocol):
|
||||
proto_key: ClassVar[str]
|
||||
unwrapped_type: ClassVar[UnwrappedAddress]
|
||||
# whether `.ipc._server.Endpoint.start_listener()` should
|
||||
# reconcile a bound `.addr` against its listener's
|
||||
# `socket.getsockname()`.
|
||||
#
|
||||
# XXX NOTE, that reconciliation exists ONLY to learn the
|
||||
# kernel-*assigned* port from a `port=0` tcp bind; a backend
|
||||
# whose `getsockname()` reports a categorically different thing
|
||||
# than what was `.bind()`ed must opt out with `False`, else the
|
||||
# ep's addr gets clobbered by an un-dialable one.
|
||||
rebind_from_sockname: ClassVar[bool]
|
||||
|
||||
# TODO, i feel like an `.is_bound()` is a better thing to
|
||||
# support?
|
||||
|
|
|
|||
|
|
@ -661,7 +661,16 @@ class Endpoint(Struct):
|
|||
|
||||
# NOTE, for handling the resolved non-0 port for
|
||||
# TCP/UDP network sockets.
|
||||
#
|
||||
# XXX, gated on the addr-type's opt-in since for some
|
||||
# backends `getsockname()` does NOT answer "the addr you
|
||||
# bound"; `tipc` reports a `TIPC_ADDR_ID` port-id instead
|
||||
# of the published name-seq, so rebinding from it would
|
||||
# replace a dialable service-name with an un-dialable
|
||||
# (and un-reconstructable) port-id.
|
||||
if (
|
||||
self.addr.rebind_from_sockname
|
||||
and
|
||||
(unwrapped := lstnr.socket.getsockname())
|
||||
!=
|
||||
self.addr.unwrap()
|
||||
|
|
|
|||
|
|
@ -65,6 +65,10 @@ class TCPAddress(
|
|||
unwrapped_type: ClassVar[type] = tuple[str, int]
|
||||
def_bindspace: ClassVar[str] = '127.0.0.1'
|
||||
|
||||
# XXX, REQUIRED here since a `port=0` bind means the kernel
|
||||
# picks and `getsockname()` is the only way we learn it.
|
||||
rebind_from_sockname: ClassVar[bool] = True
|
||||
|
||||
# ?TODO, actually validate ipv4/6 with stdlib's `ipaddress`
|
||||
@property
|
||||
def is_valid(self) -> bool:
|
||||
|
|
|
|||
|
|
@ -117,6 +117,12 @@ class UDSAddress(
|
|||
unwrapped_type: ClassVar[type] = tuple[str, int]
|
||||
def_bindspace: ClassVar[Path] = get_rt_dir()
|
||||
|
||||
# NOTE, `getsockname()` answers the sock-file path as a `str`
|
||||
# which never `==` our 2-tuple `.unwrap()`, so the round-trip
|
||||
# always fires; it's a no-op modulo `.maybe_pid` and is kept
|
||||
# `True` to preserve pre-existing behaviour exactly.
|
||||
rebind_from_sockname: ClassVar[bool] = True
|
||||
|
||||
@property
|
||||
def bindspace(self) -> Path:
|
||||
'''
|
||||
|
|
|
|||
Loading…
Reference in New Issue