sockrecvfrom() polled once and then read in a loop for as long as the
read failed with EAGAIN. Over TLS a socket is readable when only a part
of a record has come, and the read fails with EAGAIN until the rest
does: a client sending half a record and then nothing kept a thread
taking all of a CPU, and the read never timed out. On EAGAIN the socket
is now polled again, the read repeated at once only for EINTR.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On Linux a proxy listening on a Unix socket relayed only the first
bytes of an answer: sockmap() read with recvfrom() into the client's
address, which for a Unix stream socket Linux fills with an empty
AF_UNIX one, and then sent with sendto() to that address, which a
connected Unix stream socket refuses. A TCP connection has no use for
addresses: sockmap() now sends and receives with NULL ones, and
connect-back sends its command with socksend() and reads the answer
with sockrecvfrom() without an address, which a NULL sin now allows.
An abstract socket name (-iunix:@NAME) was bound with the whole size of
struct sockaddr_un, padded with zeros, so a client naming it by its
bytes, as most do, reached another name. SASIZE() now gives an abstract
address its exact size; getsockname() calls that took SASIZE() of the
old contents as the buffer size take the buffer's size instead.
tcppm refused port 0 for a unix: target, though the manual gives
"tcppm 8080 unix:/var/run/app.sock 0" as the example: the port of a
Unix socket target is ignored, so 0 is allowed.
On a reload the new service bound the path anew and the old one,
closing after it, removed the file, the new service's by then, leaving
nothing to connect to. A service now notes the file it bound (device
and inode) and removes the path on closing only if it is still that
file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On receive, the struct sockaddr is zeroed and does not have an address
family until recvfrom fills it in. SASIZE assumes that if there is no
address family, it is INET. This means that for IPv6 UDP sockets, the
sockaddr is truncated and the reply is forwarded to the wrong address.
Instead, use sizeof(PROXYSOCKADDRTYPE).