svn commit: r294541 - in head/sys: conf kern
Gleb Smirnoff
glebius at FreeBSD.org
Fri Jan 22 02:23:19 UTC 2016
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 at 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 ***
More information about the svn-src-all
mailing list