Date: Fri, 22 Jan 2016 02:23:18 +0000 (UTC) From: Gleb Smirnoff <glebius@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r294541 - in head/sys: conf kern Message-ID: <201601220223.u0M2NIYK077482@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: glebius Date: Fri Jan 22 02:23:18 2016 New Revision: 294541 URL: https://svnweb.freebsd.org/changeset/base/294541 Log: - Separate sendfile(2) implementation from uipc_syscalls.c into separate file. Claim my copyright. - Provide more comments, better function and structure names. - Sort out unneeded includes from resulting two files. No functional changes. Added: head/sys/kern/kern_sendfile.c - copied, changed from r294536, head/sys/kern/uipc_syscalls.c Modified: head/sys/conf/files head/sys/kern/uipc_syscalls.c Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Fri Jan 22 02:07:48 2016 (r294540) +++ head/sys/conf/files Fri Jan 22 02:23:18 2016 (r294541) @@ -3213,6 +3213,7 @@ kern/kern_rmlock.c standard kern/kern_rwlock.c standard kern/kern_sdt.c optional kdtrace_hooks kern/kern_sema.c standard +kern/kern_sendfile.c standard kern/kern_sharedpage.c standard kern/kern_shutdown.c standard kern/kern_sig.c standard Copied and modified: head/sys/kern/kern_sendfile.c (from r294536, head/sys/kern/uipc_syscalls.c) ============================================================================== --- head/sys/kern/uipc_syscalls.c Thu Jan 21 22:53:12 2016 (r294536, copy source) +++ head/sys/kern/kern_sendfile.c Fri Jan 22 02:23:18 2016 (r294541) @@ -1,8 +1,5 @@ /*- - * Copyright (c) 1982, 1986, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * sendfile(2) and related extensions: + * Copyright (c) 2013-2015 Gleb Smirnoff <glebius@FreeBSD.org> * Copyright (c) 1998, David Greenman. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,55 +25,33 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * @(#)uipc_syscalls.c 8.4 (Berkeley) 2/21/94 */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include "opt_capsicum.h" -#include "opt_inet.h" -#include "opt_inet6.h" #include "opt_compat.h" -#include "opt_ktrace.h" #include <sys/param.h> #include <sys/systm.h> #include <sys/capsicum.h> -#include <sys/condvar.h> #include <sys/kernel.h> #include <sys/lock.h> #include <sys/mutex.h> #include <sys/sysproto.h> #include <sys/malloc.h> -#include <sys/filedesc.h> -#include <sys/event.h> #include <sys/proc.h> -#include <sys/fcntl.h> -#include <sys/file.h> -#include <sys/filio.h> -#include <sys/jail.h> #include <sys/mman.h> #include <sys/mount.h> #include <sys/mbuf.h> #include <sys/protosw.h> #include <sys/rwlock.h> #include <sys/sf_buf.h> -#include <sys/sysent.h> #include <sys/socket.h> #include <sys/socketvar.h> -#include <sys/signalvar.h> #include <sys/syscallsubr.h> #include <sys/sysctl.h> -#include <sys/uio.h> #include <sys/vnode.h> -#ifdef KTRACE -#include <sys/ktrace.h> -#endif -#ifdef COMPAT_FREEBSD32 -#include <compat/freebsd32/freebsd32_util.h> -#endif #include <net/vnet.h> @@ -84,1736 +59,68 @@ __FBSDID("$FreeBSD$"); #include <security/mac/mac_framework.h> #include <vm/vm.h> -#include <vm/vm_param.h> #include <vm/vm_object.h> -#include <vm/vm_page.h> #include <vm/vm_pager.h> -#include <vm/vm_kern.h> -#include <vm/vm_extern.h> -#include <vm/uma.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 recvit(struct thread *td, int s, struct msghdr *mp, void *namelenp); - -static int accept1(struct thread *td, int s, struct sockaddr *uname, - socklen_t *anamelen, int flags); -static int do_sendfile(struct thread *td, struct sendfile_args *uap, - int compat); -static int getsockname1(struct thread *td, struct getsockname_args *uap, - int compat); -static int getpeername1(struct thread *td, struct getpeername_args *uap, - int compat); - -counter_u64_t sfstat[sizeof(struct sfstat) / sizeof(uint64_t)]; - -static void -sfstat_init(const void *unused) -{ - - COUNTER_ARRAY_ALLOC(sfstat, sizeof(struct sfstat) / sizeof(uint64_t), - M_WAITOK); -} -SYSINIT(sfstat, SI_SUB_MBUF, SI_ORDER_FIRST, sfstat_init, NULL); - -static int -sfstat_sysctl(SYSCTL_HANDLER_ARGS) -{ - struct sfstat s; - - COUNTER_ARRAY_COPY(sfstat, &s, sizeof(s) / sizeof(uint64_t)); - if (req->newptr) - COUNTER_ARRAY_ZERO(sfstat, sizeof(s) / sizeof(uint64_t)); - return (SYSCTL_OUT(req, &s, sizeof(s))); -} -SYSCTL_PROC(_kern_ipc, OID_AUTO, sfstat, CTLTYPE_OPAQUE | CTLFLAG_RW, - NULL, 0, sfstat_sysctl, "I", "sendfile statistics"); - -/* - * Convert a user file descriptor to a kernel file entry and check if required - * capability rights are present. - * A reference on the file entry is held upon returning. - */ -int -getsock_cap(struct thread *td, int fd, cap_rights_t *rightsp, - struct file **fpp, u_int *fflagp) -{ - struct file *fp; - int error; - - error = fget_unlocked(td->td_proc->p_fd, fd, rightsp, &fp, NULL); - if (error != 0) - return (error); - if (fp->f_type != DTYPE_SOCKET) { - fdrop(fp, td); - return (ENOTSOCK); - } - if (fflagp != NULL) - *fflagp = fp->f_flag; - *fpp = fp; - return (0); -} - -/* - * System call interface to the socket abstraction. - */ -#if defined(COMPAT_43) -#define COMPAT_OLDSOCK -#endif - -int -sys_socket(td, uap) - struct thread *td; - struct socket_args /* { - int domain; - int type; - int protocol; - } */ *uap; -{ - struct socket *so; - struct file *fp; - int fd, error, type, oflag, fflag; - - AUDIT_ARG_SOCKET(uap->domain, uap->type, uap->protocol); - - type = uap->type; - oflag = 0; - fflag = 0; - if ((type & SOCK_CLOEXEC) != 0) { - type &= ~SOCK_CLOEXEC; - oflag |= O_CLOEXEC; - } - if ((type & SOCK_NONBLOCK) != 0) { - type &= ~SOCK_NONBLOCK; - fflag |= FNONBLOCK; - } - -#ifdef MAC - error = mac_socket_check_create(td->td_ucred, uap->domain, type, - uap->protocol); - if (error != 0) - return (error); -#endif - error = falloc(td, &fp, &fd, oflag); - if (error != 0) - return (error); - /* An extra reference on `fp' has been held for us by falloc(). */ - error = socreate(uap->domain, &so, type, uap->protocol, - td->td_ucred, td); - if (error != 0) { - fdclose(td, fp, fd); - } else { - finit(fp, FREAD | FWRITE | fflag, DTYPE_SOCKET, so, &socketops); - if ((fflag & FNONBLOCK) != 0) - (void) fo_ioctl(fp, FIONBIO, &fflag, td->td_ucred, td); - td->td_retval[0] = fd; - } - fdrop(fp, td); - return (error); -} - -/* ARGSUSED */ -int -sys_bind(td, uap) - struct thread *td; - struct bind_args /* { - int s; - caddr_t name; - int namelen; - } */ *uap; -{ - struct sockaddr *sa; - int error; - - error = getsockaddr(&sa, uap->name, uap->namelen); - if (error == 0) { - error = kern_bindat(td, AT_FDCWD, uap->s, sa); - free(sa, M_SONAME); - } - return (error); -} - -int -kern_bindat(struct thread *td, int dirfd, int fd, struct sockaddr *sa) -{ - struct socket *so; - struct file *fp; - cap_rights_t rights; - int error; - - AUDIT_ARG_FD(fd); - AUDIT_ARG_SOCKADDR(td, dirfd, sa); - error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_BIND), - &fp, NULL); - if (error != 0) - return (error); - so = fp->f_data; -#ifdef KTRACE - if (KTRPOINT(td, KTR_STRUCT)) - ktrsockaddr(sa); -#endif -#ifdef MAC - error = mac_socket_check_bind(td->td_ucred, so, sa); - if (error == 0) { -#endif - if (dirfd == AT_FDCWD) - error = sobind(so, sa, td); - else - error = sobindat(dirfd, so, sa, td); -#ifdef MAC - } -#endif - fdrop(fp, td); - return (error); -} - -/* ARGSUSED */ -int -sys_bindat(td, uap) - struct thread *td; - struct bindat_args /* { - int fd; - int s; - caddr_t name; - int namelen; - } */ *uap; -{ - struct sockaddr *sa; - int error; - - error = getsockaddr(&sa, uap->name, uap->namelen); - if (error == 0) { - error = kern_bindat(td, uap->fd, uap->s, sa); - free(sa, M_SONAME); - } - return (error); -} - -/* ARGSUSED */ -int -sys_listen(td, uap) - struct thread *td; - struct listen_args /* { - int s; - int backlog; - } */ *uap; -{ - struct socket *so; - struct file *fp; - cap_rights_t rights; - int error; - - AUDIT_ARG_FD(uap->s); - error = getsock_cap(td, uap->s, cap_rights_init(&rights, CAP_LISTEN), - &fp, NULL); - if (error == 0) { - so = fp->f_data; -#ifdef MAC - error = mac_socket_check_listen(td->td_ucred, so); - if (error == 0) -#endif - error = solisten(so, uap->backlog, td); - fdrop(fp, td); - } - return(error); -} /* - * accept1() - */ -static int -accept1(td, s, uname, anamelen, flags) - struct thread *td; - int s; - struct sockaddr *uname; - socklen_t *anamelen; - int flags; -{ - struct sockaddr *name; - socklen_t namelen; - struct file *fp; - int error; - - if (uname == NULL) - return (kern_accept4(td, s, NULL, NULL, flags, NULL)); - - error = copyin(anamelen, &namelen, sizeof (namelen)); - if (error != 0) - return (error); - - error = kern_accept4(td, s, &name, &namelen, flags, &fp); - - if (error != 0) - return (error); - - if (error == 0 && uname != NULL) { -#ifdef COMPAT_OLDSOCK - if (flags & ACCEPT4_COMPAT) - ((struct osockaddr *)name)->sa_family = - name->sa_family; -#endif - error = copyout(name, uname, namelen); - } - if (error == 0) - error = copyout(&namelen, anamelen, - sizeof(namelen)); - if (error != 0) - fdclose(td, fp, td->td_retval[0]); - fdrop(fp, td); - free(name, M_SONAME); - return (error); -} - -int -kern_accept(struct thread *td, int s, struct sockaddr **name, - socklen_t *namelen, struct file **fp) -{ - return (kern_accept4(td, s, name, namelen, ACCEPT4_INHERIT, fp)); -} - -int -kern_accept4(struct thread *td, int s, struct sockaddr **name, - socklen_t *namelen, int flags, struct file **fp) -{ - struct file *headfp, *nfp = NULL; - struct sockaddr *sa = NULL; - struct socket *head, *so; - cap_rights_t rights; - u_int fflag; - pid_t pgid; - int error, fd, tmp; - - if (name != NULL) - *name = NULL; - - AUDIT_ARG_FD(s); - error = getsock_cap(td, s, cap_rights_init(&rights, CAP_ACCEPT), - &headfp, &fflag); - if (error != 0) - return (error); - head = headfp->f_data; - if ((head->so_options & SO_ACCEPTCONN) == 0) { - error = EINVAL; - goto done; - } -#ifdef MAC - error = mac_socket_check_accept(td->td_ucred, head); - if (error != 0) - goto done; -#endif - error = falloc(td, &nfp, &fd, (flags & SOCK_CLOEXEC) ? O_CLOEXEC : 0); - if (error != 0) - goto done; - ACCEPT_LOCK(); - if ((head->so_state & SS_NBIO) && TAILQ_EMPTY(&head->so_comp)) { - ACCEPT_UNLOCK(); - error = EWOULDBLOCK; - goto noconnection; - } - while (TAILQ_EMPTY(&head->so_comp) && head->so_error == 0) { - if (head->so_rcv.sb_state & SBS_CANTRCVMORE) { - head->so_error = ECONNABORTED; - break; - } - error = msleep(&head->so_timeo, &accept_mtx, PSOCK | PCATCH, - "accept", 0); - if (error != 0) { - ACCEPT_UNLOCK(); - 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(). */ - td->td_retval[0] = fd; - - /* connection has been removed from the listen queue */ - KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0); - - if (flags & ACCEPT4_INHERIT) { - pgid = fgetown(&head->so_sigio); - if (pgid != 0) - fsetown(pgid, &so->so_sigio); - } else { - fflag &= ~(FNONBLOCK | FASYNC); - if (flags & SOCK_NONBLOCK) - fflag |= FNONBLOCK; - } - - finit(nfp, fflag, DTYPE_SOCKET, so, &socketops); - /* Sync socket nonblocking/async state with file flags */ - tmp = fflag & FNONBLOCK; - (void) fo_ioctl(nfp, FIONBIO, &tmp, td->td_ucred, td); - tmp = fflag & FASYNC; - (void) fo_ioctl(nfp, FIOASYNC, &tmp, td->td_ucred, td); - sa = 0; - error = soaccept(so, &sa); - if (error != 0) - goto noconnection; - if (sa == NULL) { - if (name) - *namelen = 0; - goto done; - } - AUDIT_ARG_SOCKADDR(td, AT_FDCWD, sa); - if (name) { - /* check sa_len before it is destroyed */ - if (*namelen > sa->sa_len) - *namelen = sa->sa_len; -#ifdef KTRACE - if (KTRPOINT(td, KTR_STRUCT)) - ktrsockaddr(sa); -#endif - *name = sa; - sa = NULL; - } -noconnection: - free(sa, M_SONAME); - - /* - * close the new descriptor, assuming someone hasn't ripped it - * out from under us. - */ - if (error != 0) - fdclose(td, nfp, fd); - - /* - * Release explicitly held references before returning. We return - * a reference on nfp to the caller on success if they request it. - */ -done: - if (fp != NULL) { - if (error == 0) { - *fp = nfp; - nfp = NULL; - } else - *fp = NULL; - } - if (nfp != NULL) - fdrop(nfp, td); - fdrop(headfp, td); - return (error); -} - -int -sys_accept(td, uap) - struct thread *td; - struct accept_args *uap; -{ - - return (accept1(td, uap->s, uap->name, uap->anamelen, ACCEPT4_INHERIT)); -} - -int -sys_accept4(td, uap) - struct thread *td; - struct accept4_args *uap; -{ - - if (uap->flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) - return (EINVAL); - - return (accept1(td, uap->s, uap->name, uap->anamelen, uap->flags)); -} - -#ifdef COMPAT_OLDSOCK -int -oaccept(td, uap) - struct thread *td; - struct accept_args *uap; -{ - - return (accept1(td, uap->s, uap->name, uap->anamelen, - ACCEPT4_INHERIT | ACCEPT4_COMPAT)); -} -#endif /* COMPAT_OLDSOCK */ - -/* ARGSUSED */ -int -sys_connect(td, uap) - struct thread *td; - struct connect_args /* { - int s; - caddr_t name; - int namelen; - } */ *uap; -{ - struct sockaddr *sa; - int error; - - error = getsockaddr(&sa, uap->name, uap->namelen); - if (error == 0) { - error = kern_connectat(td, AT_FDCWD, uap->s, sa); - free(sa, M_SONAME); - } - return (error); -} - -int -kern_connectat(struct thread *td, int dirfd, int fd, struct sockaddr *sa) -{ - struct socket *so; - struct file *fp; - cap_rights_t rights; - int error, interrupted = 0; - - AUDIT_ARG_FD(fd); - AUDIT_ARG_SOCKADDR(td, dirfd, sa); - error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_CONNECT), - &fp, NULL); - if (error != 0) - return (error); - so = fp->f_data; - if (so->so_state & SS_ISCONNECTING) { - error = EALREADY; - goto done1; - } -#ifdef KTRACE - if (KTRPOINT(td, KTR_STRUCT)) - ktrsockaddr(sa); -#endif -#ifdef MAC - error = mac_socket_check_connect(td->td_ucred, so, sa); - if (error != 0) - goto bad; -#endif - if (dirfd == AT_FDCWD) - error = soconnect(so, sa, td); - else - error = soconnectat(dirfd, so, sa, td); - if (error != 0) - goto bad; - if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { - error = EINPROGRESS; - goto done1; - } - SOCK_LOCK(so); - while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { - error = msleep(&so->so_timeo, SOCK_MTX(so), PSOCK | PCATCH, - "connec", 0); - if (error != 0) { - if (error == EINTR || error == ERESTART) - interrupted = 1; - break; - } - } - if (error == 0) { - error = so->so_error; - so->so_error = 0; - } - SOCK_UNLOCK(so); -bad: - if (!interrupted) - so->so_state &= ~SS_ISCONNECTING; - if (error == ERESTART) - error = EINTR; -done1: - fdrop(fp, td); - return (error); -} - -/* ARGSUSED */ -int -sys_connectat(td, uap) - struct thread *td; - struct connectat_args /* { - int fd; - int s; - caddr_t name; - int namelen; - } */ *uap; -{ - struct sockaddr *sa; - int error; - - error = getsockaddr(&sa, uap->name, uap->namelen); - if (error == 0) { - error = kern_connectat(td, uap->fd, uap->s, sa); - free(sa, M_SONAME); - } - return (error); -} - -int -kern_socketpair(struct thread *td, int domain, int type, int protocol, - int *rsv) -{ - struct file *fp1, *fp2; - struct socket *so1, *so2; - int fd, error, oflag, fflag; - - AUDIT_ARG_SOCKET(domain, type, protocol); - - oflag = 0; - fflag = 0; - if ((type & SOCK_CLOEXEC) != 0) { - type &= ~SOCK_CLOEXEC; - oflag |= O_CLOEXEC; - } - if ((type & SOCK_NONBLOCK) != 0) { - type &= ~SOCK_NONBLOCK; - fflag |= FNONBLOCK; - } -#ifdef MAC - /* We might want to have a separate check for socket pairs. */ - error = mac_socket_check_create(td->td_ucred, domain, type, - protocol); - if (error != 0) - return (error); -#endif - error = socreate(domain, &so1, type, protocol, td->td_ucred, td); - if (error != 0) - return (error); - error = socreate(domain, &so2, type, protocol, td->td_ucred, td); - if (error != 0) - goto free1; - /* On success extra reference to `fp1' and 'fp2' is set by falloc. */ - error = falloc(td, &fp1, &fd, oflag); - if (error != 0) - goto free2; - rsv[0] = fd; - fp1->f_data = so1; /* so1 already has ref count */ - error = falloc(td, &fp2, &fd, oflag); - if (error != 0) - goto free3; - fp2->f_data = so2; /* so2 already has ref count */ - rsv[1] = fd; - error = soconnect2(so1, so2); - if (error != 0) - goto free4; - if (type == SOCK_DGRAM) { - /* - * Datagram socket connection is asymmetric. - */ - error = soconnect2(so2, so1); - if (error != 0) - goto free4; - } - finit(fp1, FREAD | FWRITE | fflag, DTYPE_SOCKET, fp1->f_data, - &socketops); - finit(fp2, FREAD | FWRITE | fflag, DTYPE_SOCKET, fp2->f_data, - &socketops); - if ((fflag & FNONBLOCK) != 0) { - (void) fo_ioctl(fp1, FIONBIO, &fflag, td->td_ucred, td); - (void) fo_ioctl(fp2, FIONBIO, &fflag, td->td_ucred, td); - } - fdrop(fp1, td); - fdrop(fp2, td); - return (0); -free4: - fdclose(td, fp2, rsv[1]); - fdrop(fp2, td); -free3: - fdclose(td, fp1, rsv[0]); - fdrop(fp1, td); -free2: - if (so2 != NULL) - (void)soclose(so2); -free1: - if (so1 != NULL) - (void)soclose(so1); - return (error); -} - -int -sys_socketpair(struct thread *td, struct socketpair_args *uap) -{ - int error, sv[2]; - - error = kern_socketpair(td, uap->domain, uap->type, - uap->protocol, sv); - if (error != 0) - return (error); - error = copyout(sv, uap->rsv, 2 * sizeof(int)); - if (error != 0) { - (void)kern_close(td, sv[0]); - (void)kern_close(td, sv[1]); - } - return (error); -} - -static int -sendit(td, s, mp, flags) - struct thread *td; - int s; - struct msghdr *mp; - int flags; -{ - struct mbuf *control; - struct sockaddr *to; - int error; - -#ifdef CAPABILITY_MODE - if (IN_CAPABILITY_MODE(td) && (mp->msg_name != NULL)) - return (ECAPMODE); -#endif - - if (mp->msg_name != NULL) { - error = getsockaddr(&to, mp->msg_name, mp->msg_namelen); - if (error != 0) { - to = NULL; - goto bad; - } - mp->msg_name = to; - } else { - to = NULL; - } - - if (mp->msg_control) { - if (mp->msg_controllen < sizeof(struct cmsghdr) -#ifdef COMPAT_OLDSOCK - && mp->msg_flags != MSG_COMPAT -#endif - ) { - error = EINVAL; - goto bad; - } - error = sockargs(&control, mp->msg_control, - mp->msg_controllen, MT_CONTROL); - if (error != 0) - goto bad; -#ifdef COMPAT_OLDSOCK - if (mp->msg_flags == MSG_COMPAT) { - struct cmsghdr *cm; - - M_PREPEND(control, sizeof(*cm), M_WAITOK); - cm = mtod(control, struct cmsghdr *); - cm->cmsg_len = control->m_len; - cm->cmsg_level = SOL_SOCKET; - cm->cmsg_type = SCM_RIGHTS; - } -#endif - } else { - control = NULL; - } - - error = kern_sendit(td, s, mp, flags, control, UIO_USERSPACE); - -bad: - free(to, M_SONAME); - return (error); -} - -int -kern_sendit(td, s, mp, flags, control, segflg) - struct thread *td; - int s; - struct msghdr *mp; - int flags; - struct mbuf *control; - enum uio_seg segflg; -{ - struct file *fp; - struct uio auio; - struct iovec *iov; - struct socket *so; - cap_rights_t rights; -#ifdef KTRACE - struct uio *ktruio = NULL; -#endif - ssize_t len; - int i, error; - - AUDIT_ARG_FD(s); - cap_rights_init(&rights, CAP_SEND); - if (mp->msg_name != NULL) { - AUDIT_ARG_SOCKADDR(td, AT_FDCWD, mp->msg_name); - cap_rights_set(&rights, CAP_CONNECT); - } - error = getsock_cap(td, s, &rights, &fp, NULL); - if (error != 0) - return (error); - so = (struct socket *)fp->f_data; - -#ifdef KTRACE - if (mp->msg_name != NULL && KTRPOINT(td, KTR_STRUCT)) - ktrsockaddr(mp->msg_name); -#endif -#ifdef MAC - if (mp->msg_name != NULL) { - error = mac_socket_check_connect(td->td_ucred, so, - mp->msg_name); - if (error != 0) - goto bad; - } - error = mac_socket_check_send(td->td_ucred, so); - if (error != 0) - goto bad; -#endif - - auio.uio_iov = mp->msg_iov; - auio.uio_iovcnt = mp->msg_iovlen; - auio.uio_segflg = segflg; - auio.uio_rw = UIO_WRITE; - auio.uio_td = td; - auio.uio_offset = 0; /* XXX */ - auio.uio_resid = 0; - iov = mp->msg_iov; - for (i = 0; i < mp->msg_iovlen; i++, iov++) { - if ((auio.uio_resid += iov->iov_len) < 0) { - error = EINVAL; - goto bad; - } - } -#ifdef KTRACE - if (KTRPOINT(td, KTR_GENIO)) - ktruio = cloneuio(&auio); -#endif - len = auio.uio_resid; - error = sosend(so, mp->msg_name, &auio, 0, control, flags, td); - if (error != 0) { - if (auio.uio_resid != len && (error == ERESTART || - error == EINTR || error == EWOULDBLOCK)) - error = 0; - /* Generation of SIGPIPE can be controlled per socket */ - if (error == EPIPE && !(so->so_options & SO_NOSIGPIPE) && - !(flags & MSG_NOSIGNAL)) { - PROC_LOCK(td->td_proc); - tdsignal(td, SIGPIPE); - PROC_UNLOCK(td->td_proc); - } - } - if (error == 0) - td->td_retval[0] = len - auio.uio_resid; -#ifdef KTRACE - if (ktruio != NULL) { - ktruio->uio_resid = td->td_retval[0]; - ktrgenio(s, UIO_WRITE, ktruio, error); - } -#endif -bad: - fdrop(fp, td); - return (error); -} - -int -sys_sendto(td, uap) - struct thread *td; - struct sendto_args /* { - int s; - caddr_t buf; - size_t len; - int flags; - caddr_t to; - int tolen; - } */ *uap; -{ - struct msghdr msg; - struct iovec aiov; - - msg.msg_name = uap->to; - msg.msg_namelen = uap->tolen; - msg.msg_iov = &aiov; - msg.msg_iovlen = 1; - msg.msg_control = 0; -#ifdef COMPAT_OLDSOCK - msg.msg_flags = 0; -#endif - aiov.iov_base = uap->buf; - aiov.iov_len = uap->len; - return (sendit(td, uap->s, &msg, uap->flags)); -} - -#ifdef COMPAT_OLDSOCK -int -osend(td, uap) - struct thread *td; - struct osend_args /* { - int s; - caddr_t buf; - int len; - int flags; - } */ *uap; -{ - struct msghdr msg; - struct iovec aiov; - - msg.msg_name = 0; - msg.msg_namelen = 0; - msg.msg_iov = &aiov; - msg.msg_iovlen = 1; - aiov.iov_base = uap->buf; - aiov.iov_len = uap->len; - msg.msg_control = 0; - msg.msg_flags = 0; - return (sendit(td, uap->s, &msg, uap->flags)); -} - -int -osendmsg(td, uap) - struct thread *td; - struct osendmsg_args /* { - int s; - caddr_t msg; - int flags; - } */ *uap; -{ - struct msghdr msg; - struct iovec *iov; - int error; - - error = copyin(uap->msg, &msg, sizeof (struct omsghdr)); - if (error != 0) - return (error); - error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); - if (error != 0) - return (error); - msg.msg_iov = iov; - msg.msg_flags = MSG_COMPAT; - error = sendit(td, uap->s, &msg, uap->flags); - free(iov, M_IOV); - return (error); -} -#endif - -int -sys_sendmsg(td, uap) *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201601220223.u0M2NIYK077482>