]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/sys_socket.c
xnu-517.9.5.tar.gz
[apple/xnu.git] / bsd / kern / sys_socket.c
index f4637871d4ead74b0d4fb90ab275773edc09f95d..973f4870f39d947ab8e6f5e44f1d3a79be3addef 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -57,6 +57,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/file.h>
+#include <sys/event.h>
 #include <sys/protosw.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
 #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));
+
+int soo_kqfilter __P((struct file *fp, struct knote *kn, struct proc *p));
 
 struct fileops socketops =
-    { soo_read, soo_write, soo_ioctl, soo_select, soo_close };
+    { soo_read, soo_write, soo_ioctl, soo_select, soo_close, soo_kqfilter };
 
 /* 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,55 @@ 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); */
+       if (so == NULL || so == (struct socket*)-1) goto done;
 
        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 +394,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;
@@ -378,13 +415,17 @@ soo_close(fp, p)
        struct proc *p;
 {
        int error = 0;
+       struct socket *sp;
 
-       if (fp->f_data) {
-            thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
-            error = soclose((struct socket *)fp->f_data);
-            thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
-       }
+       sp = (struct socket *)fp->f_data;
+       fp->f_data = NULL;
+
+       thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
+
+       if (sp)
+            error = soclose(sp);
+
+       thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
 
-       fp->f_data = 0;
        return (error);
 }