Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/uipc_syscalls.c
Show First 20 Lines • Show All 344 Lines • ▼ Show 20 Lines | #ifdef MAC | ||||
error = mac_socket_check_accept(td->td_ucred, head); | error = mac_socket_check_accept(td->td_ucred, head); | ||||
if (error != 0) | if (error != 0) | ||||
goto done; | goto done; | ||||
#endif | #endif | ||||
error = falloc_caps(td, &nfp, &fd, | error = falloc_caps(td, &nfp, &fd, | ||||
(flags & SOCK_CLOEXEC) ? O_CLOEXEC : 0, &fcaps); | (flags & SOCK_CLOEXEC) ? O_CLOEXEC : 0, &fcaps); | ||||
if (error != 0) | if (error != 0) | ||||
goto done; | goto done; | ||||
ACCEPT_LOCK(); | SOCK_LOCK(head); | ||||
if ((head->so_state & SS_NBIO) && TAILQ_EMPTY(&head->so_comp)) { | if (!SOLISTENING(head)) { | ||||
ACCEPT_UNLOCK(); | SOCK_UNLOCK(head); | ||||
error = EINVAL; | |||||
goto noconnection; | |||||
} | |||||
if ((head->so_state & SS_NBIO) && TAILQ_EMPTY(&head->sol_comp)) { | |||||
SOLISTEN_UNLOCK(head); | |||||
error = EWOULDBLOCK; | error = EWOULDBLOCK; | ||||
goto noconnection; | goto noconnection; | ||||
} | } | ||||
while (TAILQ_EMPTY(&head->so_comp) && head->so_error == 0) { | while (TAILQ_EMPTY(&head->sol_comp) && head->so_error == 0) { | ||||
if (head->so_rcv.sb_state & SBS_CANTRCVMORE) { | error = msleep(&head->sol_comp, &head->so_lock, PSOCK | PCATCH, | ||||
head->so_error = ECONNABORTED; | |||||
break; | |||||
} | |||||
error = msleep(&head->so_timeo, &accept_mtx, PSOCK | PCATCH, | |||||
"accept", 0); | "accept", 0); | ||||
if (error != 0) { | if (error != 0) { | ||||
ACCEPT_UNLOCK(); | SOLISTEN_UNLOCK(head); | ||||
goto noconnection; | goto noconnection; | ||||
} | } | ||||
} | } | ||||
if (head->so_error) { | if (head->so_error) { | ||||
error = head->so_error; | error = head->so_error; | ||||
head->so_error = 0; | head->so_error = 0; | ||||
ACCEPT_UNLOCK(); | SOLISTEN_UNLOCK(head); | ||||
goto noconnection; | goto noconnection; | ||||
} | } | ||||
so = TAILQ_FIRST(&head->so_comp); | so = TAILQ_FIRST(&head->sol_comp); | ||||
KASSERT(!(so->so_qstate & SQ_INCOMP), ("accept1: so SQ_INCOMP")); | |||||
KASSERT(so->so_qstate & SQ_COMP, ("accept1: so not SQ_COMP")); | |||||
/* | /* | ||||
* Before changing the flags on the socket, we have to bump the | * Before changing the flags on the socket, we have to bump the | ||||
* reference count. Otherwise, if the protocol calls sofree(), | * reference count. Otherwise, if the protocol calls sofree(), | ||||
* the socket will be released due to a zero refcount. | * the socket will be released due to a zero refcount. | ||||
*/ | */ | ||||
SOCK_LOCK(so); /* soref() and so_state update */ | SOCK_LOCK(so); | ||||
KASSERT(so->so_qstate == SQ_COMP, | |||||
("%s: so %p not SQ_COMP", __func__, so)); | |||||
soref(so); /* file descriptor reference */ | soref(so); /* file descriptor reference */ | ||||
TAILQ_REMOVE(&head->sol_comp, so, so_list); | |||||
TAILQ_REMOVE(&head->so_comp, so, so_list); | head->sol_qlen--; | ||||
head->so_qlen--; | |||||
if (flags & ACCEPT4_INHERIT) | if (flags & ACCEPT4_INHERIT) | ||||
so->so_state |= (head->so_state & SS_NBIO); | so->so_state |= (head->so_state & SS_NBIO); | ||||
else | else | ||||
so->so_state |= (flags & SOCK_NONBLOCK) ? SS_NBIO : 0; | so->so_state |= (flags & SOCK_NONBLOCK) ? SS_NBIO : 0; | ||||
so->so_qstate &= ~SQ_COMP; | so->so_qstate = SQ_NONE; | ||||
so->so_head = NULL; | so->so_listen = NULL; | ||||
SOCK_UNLOCK(so); | SOCK_UNLOCK(so); | ||||
ACCEPT_UNLOCK(); | sorele(head); | ||||
/* An extra reference on `nfp' has been held for us by falloc(). */ | /* An extra reference on `nfp' has been held for us by falloc(). */ | ||||
td->td_retval[0] = fd; | td->td_retval[0] = fd; | ||||
/* connection has been removed from the listen queue */ | /* Connection has been removed from the listen queue. */ | ||||
KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0); | KNOTE_UNLOCKED(&head->so_rdsel.si_note, 0); | ||||
if (flags & ACCEPT4_INHERIT) { | if (flags & ACCEPT4_INHERIT) { | ||||
pgid = fgetown(&head->so_sigio); | pgid = fgetown(&head->so_sigio); | ||||
if (pgid != 0) | if (pgid != 0) | ||||
fsetown(pgid, &so->so_sigio); | fsetown(pgid, &so->so_sigio); | ||||
} else { | } else { | ||||
fflag &= ~(FNONBLOCK | FASYNC); | fflag &= ~(FNONBLOCK | FASYNC); | ||||
if (flags & SOCK_NONBLOCK) | if (flags & SOCK_NONBLOCK) | ||||
fflag |= FNONBLOCK; | fflag |= FNONBLOCK; | ||||
} | } | ||||
finit(nfp, fflag, DTYPE_SOCKET, so, &socketops); | finit(nfp, fflag, DTYPE_SOCKET, so, &socketops); | ||||
/* Sync socket nonblocking/async state with file flags */ | /* Sync socket nonblocking/async state with file flags */ | ||||
tmp = fflag & FNONBLOCK; | tmp = fflag & FNONBLOCK; | ||||
(void) fo_ioctl(nfp, FIONBIO, &tmp, td->td_ucred, td); | (void) fo_ioctl(nfp, FIONBIO, &tmp, td->td_ucred, td); | ||||
tmp = fflag & FASYNC; | tmp = fflag & FASYNC; | ||||
(void) fo_ioctl(nfp, FIOASYNC, &tmp, td->td_ucred, td); | (void) fo_ioctl(nfp, FIOASYNC, &tmp, td->td_ucred, td); | ||||
sa = NULL; | |||||
error = soaccept(so, &sa); | error = soaccept(so, &sa); | ||||
if (error != 0) | if (error != 0) | ||||
goto noconnection; | goto noconnection; | ||||
if (sa == NULL) { | if (sa == NULL) { | ||||
if (name) | if (name) | ||||
*namelen = 0; | *namelen = 0; | ||||
goto done; | goto done; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 121 Lines • ▼ Show 20 Lines | #endif | ||||
if (error != 0) | if (error != 0) | ||||
goto bad; | goto bad; | ||||
if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { | if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { | ||||
error = EINPROGRESS; | error = EINPROGRESS; | ||||
goto done1; | goto done1; | ||||
} | } | ||||
SOCK_LOCK(so); | SOCK_LOCK(so); | ||||
while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { | while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { | ||||
error = msleep(&so->so_timeo, SOCK_MTX(so), PSOCK | PCATCH, | error = msleep(&so->so_timeo, &so->so_lock, PSOCK | PCATCH, | ||||
"connec", 0); | "connec", 0); | ||||
if (error != 0) { | if (error != 0) { | ||||
if (error == EINTR || error == ERESTART) | if (error == EINTR || error == ERESTART) | ||||
interrupted = 1; | interrupted = 1; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (error == 0) { | if (error == 0) { | ||||
▲ Show 20 Lines • Show All 1,038 Lines • Show Last 20 Lines |