Changeset View
Changeset View
Standalone View
Standalone View
head/sys/kern/uipc_syscalls.c
Show First 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | |||||
#include <compat/freebsd32/freebsd32_util.h> | #include <compat/freebsd32/freebsd32_util.h> | ||||
#endif | #endif | ||||
#include <net/vnet.h> | #include <net/vnet.h> | ||||
#include <security/audit/audit.h> | #include <security/audit/audit.h> | ||||
#include <security/mac/mac_framework.h> | #include <security/mac/mac_framework.h> | ||||
/* | |||||
* Flags for accept1() and kern_accept4(), in addition to SOCK_CLOEXEC | |||||
* and SOCK_NONBLOCK. | |||||
*/ | |||||
#define ACCEPT4_INHERIT 0x1 | |||||
#define ACCEPT4_COMPAT 0x2 | |||||
static int sendit(struct thread *td, int s, struct msghdr *mp, int flags); | static int sendit(struct thread *td, int s, struct msghdr *mp, int flags); | ||||
static int recvit(struct thread *td, int s, struct msghdr *mp, void *namelenp); | static int recvit(struct thread *td, int s, struct msghdr *mp, void *namelenp); | ||||
static int accept1(struct thread *td, int s, struct sockaddr *uname, | static int accept1(struct thread *td, int s, struct sockaddr *uname, | ||||
socklen_t *anamelen, int flags); | socklen_t *anamelen, int flags); | ||||
static int getsockname1(struct thread *td, struct getsockname_args *uap, | static int getsockname1(struct thread *td, struct getsockname_args *uap, | ||||
int compat); | int compat); | ||||
static int getpeername1(struct thread *td, struct getpeername_args *uap, | static int getpeername1(struct thread *td, struct getpeername_args *uap, | ||||
▲ Show 20 Lines • Show All 259 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 = EWOULDBLOCK; | error = EINVAL; | ||||
goto noconnection; | goto noconnection; | ||||
} | } | ||||
while (TAILQ_EMPTY(&head->so_comp) && head->so_error == 0) { | |||||
if (head->so_rcv.sb_state & SBS_CANTRCVMORE) { | error = solisten_dequeue(head, &so, flags); | ||||
head->so_error = ECONNABORTED; | if (error != 0) | ||||
break; | |||||
} | |||||
error = msleep(&head->so_timeo, &accept_mtx, PSOCK | PCATCH, | |||||
"accept", 0); | |||||
if (error != 0) { | |||||
ACCEPT_UNLOCK(); | |||||
goto noconnection; | goto noconnection; | ||||
} | |||||
} | |||||
if (head->so_error) { | |||||
error = head->so_error; | |||||
head->so_error = 0; | |||||
ACCEPT_UNLOCK(); | |||||
goto noconnection; | |||||
} | |||||
so = TAILQ_FIRST(&head->so_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 | |||||
* reference count. Otherwise, if the protocol calls sofree(), | |||||
* the socket will be released due to a zero refcount. | |||||
*/ | |||||
SOCK_LOCK(so); /* soref() and so_state update */ | |||||
soref(so); /* file descriptor reference */ | |||||
TAILQ_REMOVE(&head->so_comp, so, so_list); | |||||
head->so_qlen--; | |||||
if (flags & ACCEPT4_INHERIT) | |||||
so->so_state |= (head->so_state & SS_NBIO); | |||||
else | |||||
so->so_state |= (flags & SOCK_NONBLOCK) ? SS_NBIO : 0; | |||||
so->so_qstate &= ~SQ_COMP; | |||||
so->so_head = NULL; | |||||
SOCK_UNLOCK(so); | |||||
ACCEPT_UNLOCK(); | |||||
/* 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 |