sockets: repair wakeup of accept(2) by shutdown(2)

That was lost in transition from one-for-all soshutdown() to protocol
specific methods.  Only protocols that listen(2) were affected.  This is
not a documented or specified feature, but some software relies on it.  At
least the FreeSWITCH telephony software uses this behavior on
PF_INET/SOCK_STREAM.

Fixes:  5bba272807
This commit is contained in:
Gleb Smirnoff 2024-02-15 10:48:44 -08:00
parent 2c5ff9118c
commit abe8379b4f
3 changed files with 18 additions and 21 deletions

View file

@ -1669,7 +1669,14 @@ uipc_shutdown(struct socket *so, enum shutdown_how how)
int error;
SOCK_LOCK(so);
if ((so->so_state &
if (SOLISTENING(so)) {
if (how != SHUT_WR) {
so->so_error = ECONNABORTED;
solisten_wakeup(so); /* unlocks so */
} else
SOCK_UNLOCK(so);
return (ENOTCONN);
} else if ((so->so_state &
(SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) {
/*
* POSIX mandates us to just return ENOTCONN when shutdown(2) is
@ -1691,14 +1698,6 @@ uipc_shutdown(struct socket *so, enum shutdown_how how)
}
} else
error = 0;
if (SOLISTENING(so)) {
if (how != SHUT_WR) {
so->so_error = ECONNABORTED;
solisten_wakeup(so); /* unlocks so */
} else
SOCK_UNLOCK(so);
return (0);
}
SOCK_UNLOCK(so);
switch (how) {

View file

@ -794,18 +794,17 @@ sctp_shutdown(struct socket *so, enum shutdown_how how)
return (EOPNOTSUPP);
SOCK_LOCK(so);
if ((so->so_state &
(SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) {
SOCK_UNLOCK(so);
return (ENOTCONN);
}
if (SOLISTENING(so)) {
if (how != SHUT_WR) {
so->so_error = ECONNABORTED;
solisten_wakeup(so); /* unlocks so */
} else
SOCK_UNLOCK(so);
return (0);
return (ENOTCONN);
} else if ((so->so_state &
(SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) {
SOCK_UNLOCK(so);
return (ENOTCONN);
}
SOCK_UNLOCK(so);

View file

@ -807,18 +807,17 @@ tcp_usr_shutdown(struct socket *so, enum shutdown_how how)
int error = 0;
SOCK_LOCK(so);
if ((so->so_state &
(SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) {
SOCK_UNLOCK(so);
return (ENOTCONN);
}
if (SOLISTENING(so)) {
if (how != SHUT_WR) {
so->so_error = ECONNABORTED;
solisten_wakeup(so); /* unlocks so */
} else
SOCK_UNLOCK(so);
return (0);
return (ENOTCONN);
} else if ((so->so_state &
(SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) {
SOCK_UNLOCK(so);
return (ENOTCONN);
}
SOCK_UNLOCK(so);