unix: retire LOCAL_CONNWAIT

This socket option was added in 6a2989fd54 together with LOCAL_CREDS.
Both options originate from NetBSD.  The LOCAL_CREDS seems to be used by
some software and is covered by our test suite.

The main problem with LOCAL_CONNWAIT is that it doesn't work as
documented. A basic test shows that connect(2) indeed blocks, but
accept(2) on the other side does not wake it up.  Indeed, I don't see what
code in the accept(2) path would go into the peer socket of a unix/stream
listener's child and would make wakeup(&so->so_timeo).  I tried the test
even on a FreeBSD 6.4-RELEASE and it produced the same results as on
CURRENT.

The other thing that puzzles me is why that option would be useful even if
it worked? Because on unix/stream you can send(2) immediately after
connect(2) and that would put data on the peer receive buffer even before
listener had done accept(2). In other words, one side can do connect(2)
then send(2), only after the remote side would make accept(2) and the
remote would see the data sent before the accept(2).  Again this
undocumented feature of unix(4) is present on all versions from FreeBSD 6
to CURRENT.

Reviewed by:		markj
Differential Revision:	https://reviews.freebsd.org/D43708
This commit is contained in:
Gleb Smirnoff 2024-02-08 09:00:23 -08:00
parent 3ad0f9a584
commit 0bd8eb3e08
4 changed files with 6 additions and 37 deletions

View file

@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd June 24, 2022
.Dd February 1, 2022
.Dt UNIX 4
.Os
.Sh NAME
@ -332,14 +332,6 @@ The
and
.Dv LOCAL_CREDS_PERSISTENT
options are mutually exclusive.
.It Dv LOCAL_CONNWAIT
Used with
.Dv SOCK_STREAM
sockets, this option causes the
.Xr connect 2
function to block until
.Xr accept 2
has been called on the listening socket.
.It Dv LOCAL_PEERCRED
Requested via
.Xr getsockopt 2

View file

@ -291,8 +291,7 @@ static int unp_connect(struct socket *, struct sockaddr *,
struct thread *);
static int unp_connectat(int, struct socket *, struct sockaddr *,
struct thread *, bool);
typedef enum { PRU_CONNECT, PRU_CONNECT2 } conn2_how;
static void unp_connect2(struct socket *so, struct socket *so2, conn2_how);
static void unp_connect2(struct socket *so, struct socket *so2);
static void unp_disconnect(struct unpcb *unp, struct unpcb *unp2);
static void unp_dispose(struct socket *so);
static void unp_shutdown(struct unpcb *);
@ -704,7 +703,7 @@ uipc_connect2(struct socket *so1, struct socket *so2)
unp2 = so2->so_pcb;
KASSERT(unp2 != NULL, ("uipc_connect2: unp2 == NULL"));
unp_pcb_lock_pair(unp, unp2);
unp_connect2(so1, so2, PRU_CONNECT2);
unp_connect2(so1, so2);
unp_pcb_unlock_pair(unp, unp2);
return (0);
@ -1784,12 +1783,6 @@ uipc_ctloutput(struct socket *so, struct sockopt *sopt)
error = sooptcopyout(sopt, &optval, sizeof(optval));
break;
case LOCAL_CONNWAIT:
/* Unlocked read. */
optval = unp->unp_flags & UNP_CONNWAIT ? 1 : 0;
error = sooptcopyout(sopt, &optval, sizeof(optval));
break;
default:
error = EOPNOTSUPP;
break;
@ -1800,7 +1793,6 @@ uipc_ctloutput(struct socket *so, struct sockopt *sopt)
switch (sopt->sopt_name) {
case LOCAL_CREDS:
case LOCAL_CREDS_PERSISTENT:
case LOCAL_CONNWAIT:
error = sooptcopyin(sopt, &optval, sizeof(optval),
sizeof(optval));
if (error)
@ -1829,10 +1821,6 @@ uipc_ctloutput(struct socket *so, struct sockopt *sopt)
OPTSET(UNP_WANTCRED_ALWAYS, UNP_WANTCRED_ONESHOT);
break;
case LOCAL_CONNWAIT:
OPTSET(UNP_CONNWAIT, 0);
break;
default:
break;
}
@ -2006,7 +1994,7 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam,
KASSERT(unp2 != NULL && so2 != NULL && unp2->unp_socket == so2 &&
sotounpcb(so2) == unp2,
("%s: unp2 %p so2 %p", __func__, unp2, so2));
unp_connect2(so, so2, PRU_CONNECT);
unp_connect2(so, so2);
KASSERT((unp->unp_flags & UNP_CONNECTING) != 0,
("%s: unp %p has UNP_CONNECTING clear", __func__, unp));
unp->unp_flags &= ~UNP_CONNECTING;
@ -2057,7 +2045,7 @@ unp_copy_peercred(struct thread *td, struct unpcb *client_unp,
}
static void
unp_connect2(struct socket *so, struct socket *so2, conn2_how req)
unp_connect2(struct socket *so, struct socket *so2)
{
struct unpcb *unp;
struct unpcb *unp2;
@ -2089,11 +2077,7 @@ unp_connect2(struct socket *so, struct socket *so2, conn2_how req)
KASSERT(unp2->unp_conn == NULL,
("%s: socket %p is already connected", __func__, unp2));
unp2->unp_conn = unp;
if (req == PRU_CONNECT &&
((unp->unp_flags | unp2->unp_flags) & UNP_CONNWAIT))
soisconnecting(so);
else
soisconnected(so);
soisconnected(so);
soisconnected(so2);
break;
@ -3493,10 +3477,6 @@ db_print_unpflags(int unp_flags)
db_printf("%sUNP_WANTCRED_ONESHOT", comma ? ", " : "");
comma = 1;
}
if (unp_flags & UNP_CONNWAIT) {
db_printf("%sUNP_CONNWAIT", comma ? ", " : "");
comma = 1;
}
if (unp_flags & UNP_CONNECTING) {
db_printf("%sUNP_CONNECTING", comma ? ", " : "");
comma = 1;

View file

@ -65,7 +65,6 @@ struct sockaddr_un {
#define LOCAL_PEERCRED 1 /* retrieve peer credentials */
#define LOCAL_CREDS 2 /* pass credentials to receiver */
#define LOCAL_CREDS_PERSISTENT 3 /* pass credentials to receiver */
#define LOCAL_CONNWAIT 4 /* connects block until accepted */
/* Start of reserved space for third-party socket options. */
#define LOCAL_VENDOR SO_VENDOR

View file

@ -107,8 +107,6 @@ struct unpcb {
#define UNP_HAVEPC 0x001
#define UNP_WANTCRED_ALWAYS 0x002 /* credentials wanted always */
#define UNP_WANTCRED_ONESHOT 0x004 /* credentials wanted once */
#define UNP_CONNWAIT 0x008 /* connect blocks until accepted */
#define UNP_WANTCRED_MASK (UNP_WANTCRED_ONESHOT | UNP_WANTCRED_ALWAYS)
/*