Files
AnyPS5/docs/dev/debt/libSceNet.md
T
milescovielloandClaude Opus 5.5 65d56b3147 fix(libSceNet): dissolve a datagram association on connect to AF_UNSPEC
sceNetConnect() on a connected datagram socket rejected an address
whose family is AF_UNSPEC (a null address) with EINVAL before touching
the socket, so the socket stayed connected: sceNetGetpeername() still
reported the old peer and datagrams from any other sender were dropped
by the host.

FreeBSD 11.4 disconnects a connected datagram socket first and only then
looks at the address. sys/kern/uipc_socket.c, soconnectat():

	 * If protocol is connection-based, can only connect once.
	 * Otherwise, if connected, try to disconnect first.  This allows
	 * user to disconnect by connecting to, e.g., a null address.
	 */
	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
	    ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
	    (error = sodisconnect(so)))) {

udp_disconnect() (sys/netinet/udp_usrreq.c) clears the peer and keeps
the local port. connect(2): "Datagram sockets may dissolve the
association by connecting to an invalid address, such as a null
address." libkernel's connect gets the same change in #4498.

A connected datagram socket given an address whose family byte is 0 is
now disconnected on the host first (AF_UNSPEC on Linux, a zeroed
address of the socket's family on Windows), and the call then fails
with EINVAL as before. Linux also drops an ephemeral local port on that
disconnect, so the port is bound again on the wildcard address, which
is what FreeBSD leaves. A host failure during the disconnect is
returned as the call's error. Stream sockets keep the previous path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 02:58:42 +00:00

5.6 KiB

libSceNet technical debt

Unknown function info

Functional

  • sceNetConnect to AF_UNSPEC (libSceNet) dissolves a datagram association as FreeBSD 11.4's udp_disconnect() does, which resets the local address to the wildcard address and keeps the port. On Linux a socket bound to an explicit port keeps its local address as well (127.0.0.1:<port> stays 127.0.0.1:<port>), because a bound socket cannot be bound again; one bound to port 0 is bound again to the wildcard address with the port it had
  • sceNetSetsockopt (libSceNet) sets SO_RCVTIMEO and SO_SNDTIMEO as the host socket's timeouts. On Windows a receive or send on a stream socket that times out fails with ETIMEDOUT, where FreeBSD returns EAGAIN or the partial count: Winsock leaves the connection in an indeterminate state after a timeout and reports no partial count (SOL_SOCKET options), so FreeBSD's behaviour needs the timeout waited for without the host option. A receive on a datagram socket that times out fails with EAGAIN
  • sceNetGetsockopt (libSceNet) reads SO_ERROR from the host socket. Winsock does not clear a socket's pending error when it is read, so on Windows the library reports a pending error once and shows it again only after a new sceNetConnect; a second failure with the same code on the same socket without a sceNetConnect in between would be hidden.
  • sceNetSendmsg and sceNetRecvmsg (libSceNet) copy the scatter/gather list through one host buffer and accept only the flags sceNetSend/sceNetRecv accept. Sending control data throws; a receive never returns control data (msg_controllen 0), since no socket option that queues it is supported
  • sceNetResolverAbort and sceNetResolverStartNtoaMultipleRecords (libSceNet) follow shadPS4 (net.cpp, net_resolver.cpp); the (int rid, int flags) signature of the abort also matches SharpProspero. Unverified on hardware. Lookups run synchronously over the host resolver, which cannot be interrupted: an abort while a lookup runs on another thread returns at once, and that lookup fails with EINTR without writing its output only when the host call returns; the abort flags are then ignored, as shadPS4 does for a running lookup. With nothing running, abort flag 1 (NTOA preservation) or 2 (ATON preservation) makes the next sceNetResolverStartNtoa* or sceNetResolverStartAton call on that resolver fail with EINTR, reported by sceNetResolverGetError, after its arguments are checked. Unlike shadPS4, which ignores them, other abort flag bits throw, and sceNetResolverStartNtoaMultipleRecords throws for any flag, including async (1) and 0x10000 (IP address literals disabled), as sceNetResolverStartNtoaMultipleRecordsEx does
  • sceNetResolverStartNtoa6 (libSceNet) resolves a host name to its first IPv6 address through the host resolver (getaddrinfo with AF_INET6) and writes the 16-byte address; the (rid, hostname, addr, timeout, retry, flags) signature follows sceNetResolverStartNtoa. A name with no IPv6 address fails with RESOLVER_ENODNS (0x804101E1) like a failed lookup; whether the console returns IPv4-mapped addresses instead is not verified. Timeout and retry are ignored as in sceNetResolverStartNtoa, and any nonzero flags throw because their meaning for this call is not known. Unverified on hardware.