]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/sys_socket.c
xnu-344.49.tar.gz
[apple/xnu.git] / bsd / kern / sys_socket.c
index f4637871d4ead74b0d4fb90ab275773edc09f95d..a215a42bcee0924722e4448ddd15a9a0da4897f7 100644 (file)
@@ -1,21 +1,24 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
  * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
 #include <net/route.h>
 
 int soo_read __P((struct file *fp, struct uio *uio, 
-               struct ucred *cred));
+               struct ucred *cred, int flags, struct proc *p));
 int soo_write __P((struct file *fp, struct uio *uio, 
-               struct ucred *cred));
+               struct ucred *cred, int flags, struct proc *p));
 int soo_close __P((struct file *fp, struct proc *p));
 
-int soo_select __P((struct file *fp, int which, struct proc *p));
+int soo_select __P((struct file *fp, int which, void * wql, struct proc *p));
 
 struct fileops socketops =
     { soo_read, soo_write, soo_ioctl, soo_select, soo_close };
 
 /* ARGSUSED */
 int
-soo_read(fp, uio, cred)
+soo_read(fp, uio, cred, flags, p)
        struct file *fp;
        struct uio *uio;
        struct ucred *cred;
+       int flags;
+       struct proc *p;
 {
-       struct socket *so = (struct socket *)fp->f_data;
+       struct socket *so;
        struct kextcb *kp;
        int stat;
        int (*fsoreceive) __P((struct socket *so, 
@@ -95,7 +100,15 @@ soo_read(fp, uio, cred)
                               struct uio *uio, struct mbuf **mp0,
                               struct mbuf **controlp, int *flagsp));
 
+
        thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
+
+        if ((so = (struct socket *)fp->f_data) == NULL) {
+                /* This is not a valid open file descriptor */
+                thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
+                return (EBADF);
+        }
+
        fsoreceive = so->so_proto->pr_usrreqs->pru_soreceive;
        if (fsoreceive != soreceive)
        {       kp = sotokextcb(so);
@@ -115,12 +128,14 @@ soo_read(fp, uio, cred)
 
 /* ARGSUSED */
 int
-soo_write(fp, uio, cred)
+soo_write(fp, uio, cred, flags, p)
        struct file *fp;
        struct uio *uio;
        struct ucred *cred;
+       int flags;
+       struct proc *p;
 {
-       struct socket *so = (struct socket *)fp->f_data;
+       struct socket *so;
        int     (*fsosend) __P((struct socket *so, struct sockaddr *addr,
                                struct uio *uio, struct mbuf *top,
                                struct mbuf *control, int flags));
@@ -128,6 +143,13 @@ soo_write(fp, uio, cred)
        int           stat;
 
        thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
+
+        if ((so = (struct socket *)fp->f_data) == NULL) {
+                /* This is not a valid open file descriptor */
+                thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
+                return (EBADF);
+        }
+
        fsosend = so->so_proto->pr_usrreqs->pru_sosend;
        if (fsosend != sosend)
        {       kp = sotokextcb(so);
@@ -141,7 +163,12 @@ soo_write(fp, uio, cred)
 
        stat = (*fsosend)(so, 0, uio, 0, 0, 0);
        thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
-       return stat;
+
+        /* Generation of SIGPIPE can be controlled per socket */
+        if (stat == EPIPE && uio->uio_procp && !(so->so_flags & SOF_NOSIGPIPE))
+            psignal(uio->uio_procp, SIGPIPE);
+
+        return stat;
 }
 
 int
@@ -151,19 +178,24 @@ soo_ioctl(fp, cmd, data, p)
        register caddr_t data;
        struct proc *p;
 {
-       register struct socket *so = (struct socket *)fp->f_data;
-
+       register struct socket *so;
        struct sockopt sopt;
        struct kextcb *kp;
        int    error = 0;
-       kp = sotokextcb(so);
-       sopt.sopt_level = cmd;
-       sopt.sopt_name = (int)data;
-       sopt.sopt_p = p;
-
 
        thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
 
+       if ((so = (struct socket *)fp->f_data) == NULL) {
+               /* This is not a valid open file descriptor */
+               thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
+               return (EBADF);
+       }
+
+        kp = sotokextcb(so);
+        sopt.sopt_level = cmd;
+        sopt.sopt_name = (int)data;
+        sopt.sopt_p = p;
+
        while (kp)
        {       if (kp->e_soif && kp->e_soif->sf_socontrol)
                        (*kp->e_soif->sf_socontrol)(so, &sopt, kp);
@@ -238,6 +270,7 @@ soo_ioctl(fp, cmd, data, p)
             fp->f_flag |= FNONBLOCK;
             so->so_state |= SS_NBIO;
             so->so_options |= SO_DONTTRUNC | SO_WANTMORE;
+          so->so_flags |= SOF_NOSIGPIPE;
 
             if (cloned_so && so != cloned_so) {
                  /* Flags options */
@@ -303,55 +336,54 @@ soo_ioctl(fp, cmd, data, p)
 }
 
 int
-soo_select(fp, which, p)
+soo_select(fp, which, wql, p)
        struct file *fp;
        int which;
+       void * wql;
        struct proc *p;
 {
        register struct socket *so = (struct socket *)fp->f_data;
        register int s = splnet();
        int retnum=0;
 
-/*     thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); */
 
        switch (which) {
 
        case FREAD:
-               so->so_rcv.sb_sel.si_flags |= SI_SBSEL;
+               so->so_rcv.sb_flags |= SB_SEL;
                if (soreadable(so)) {
                        splx(s);
                        retnum = 1;
-                       so->so_rcv.sb_sel.si_flags &= ~SI_SBSEL;
+                       so->so_rcv.sb_flags &= ~SB_SEL;
                        goto done;
                }
-               selrecord(p, &so->so_rcv.sb_sel);
+               selrecord(p, &so->so_rcv.sb_sel, wql);
                break;
 
        case FWRITE:
-               so->so_snd.sb_sel.si_flags |= SI_SBSEL;
+               so->so_snd.sb_flags |= SB_SEL;
                if (sowriteable(so)) {
                        splx(s);
                        retnum = 1;
-                       so->so_snd.sb_sel.si_flags &= ~SI_SBSEL;
+                       so->so_snd.sb_flags &= ~SB_SEL;
                        goto done;
                }
-               selrecord(p, &so->so_snd.sb_sel);
+               selrecord(p, &so->so_snd.sb_sel, wql);
                break;
 
        case 0:
-               so->so_rcv.sb_sel.si_flags |= SI_SBSEL;
+               so->so_rcv.sb_flags |= SB_SEL;
                if (so->so_oobmark || (so->so_state & SS_RCVATMARK)) {
                        splx(s);
                        retnum = 1;
-                       so->so_rcv.sb_sel.si_flags &= ~SI_SBSEL;
+                       so->so_rcv.sb_flags &= ~SB_SEL;
                        goto done;
                }
-               selrecord(p, &so->so_rcv.sb_sel);
+               selrecord(p, &so->so_rcv.sb_sel, wql);
                break;
        }
        splx(s);
 done:
-/*     thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); */
        return (retnum);
 }
 
@@ -361,8 +393,12 @@ soo_stat(so, ub)
        register struct socket *so;
        register struct stat *ub;
 {
-     int stat;
+       int stat;
 
+       /*
+        * DANGER: by the time we get the network funnel the socket 
+        * may have been closed
+        */
        thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
        bzero((caddr_t)ub, sizeof (*ub));
        ub->st_mode = S_IFSOCK;
@@ -379,11 +415,12 @@ soo_close(fp, p)
 {
        int error = 0;
 
-       if (fp->f_data) {
-            thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
+       thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
+
+       if (fp->f_data)
             error = soclose((struct socket *)fp->f_data);
-            thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
-       }
+
+       thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
 
        fp->f_data = 0;
        return (error);