home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / kern / uipc_usrreq.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-17  |  16.7 KB  |  768 lines

  1. /*
  2.  * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  *
  33.  *    @(#)uipc_usrreq.c    7.26 (Berkeley) 6/3/91
  34.  */
  35.  
  36. #include "param.h"
  37. #include "proc.h"
  38. #include "filedesc.h"
  39. #include "domain.h"
  40. #include "protosw.h"
  41. #include "socket.h"
  42. #include "socketvar.h"
  43. #include "unpcb.h"
  44. #include "un.h"
  45. #include "namei.h"
  46. #include "vnode.h"
  47. #include "file.h"
  48. #include "stat.h"
  49. #include "mbuf.h"
  50.  
  51. /*
  52.  * Unix communications domain.
  53.  *
  54.  * TODO:
  55.  *    SEQPACKET, RDM
  56.  *    rethink name space problems
  57.  *    need a proper out-of-band
  58.  */
  59. struct    sockaddr sun_noname = { sizeof(sun_noname), AF_UNIX };
  60. ino_t    unp_ino;            /* prototype for fake inode numbers */
  61.  
  62. /*ARGSUSED*/
  63. uipc_usrreq(so, req, m, nam, control)
  64.     struct socket *so;
  65.     int req;
  66.     struct mbuf *m, *nam, *control;
  67. {
  68.     struct unpcb *unp = sotounpcb(so);
  69.     register struct socket *so2;
  70.     register int error = 0;
  71.     struct proc *p = curproc;    /* XXX */
  72.  
  73.     if (req == PRU_CONTROL)
  74.         return (EOPNOTSUPP);
  75.     if (req != PRU_SEND && control && control->m_len) {
  76.         error = EOPNOTSUPP;
  77.         goto release;
  78.     }
  79.     if (unp == 0 && req != PRU_ATTACH) {
  80.         error = EINVAL;
  81.         goto release;
  82.     }
  83.     switch (req) {
  84.  
  85.     case PRU_ATTACH:
  86.         if (unp) {
  87.             error = EISCONN;
  88.             break;
  89.         }
  90.         error = unp_attach(so);
  91.         break;
  92.  
  93.     case PRU_DETACH:
  94.         unp_detach(unp);
  95.         break;
  96.  
  97.     case PRU_BIND:
  98.         error = unp_bind(unp, nam, p);
  99.         break;
  100.  
  101.     case PRU_LISTEN:
  102.         if (unp->unp_vnode == 0)
  103.             error = EINVAL;
  104.         break;
  105.  
  106.     case PRU_CONNECT:
  107.         error = unp_connect(so, nam, p);
  108.         break;
  109.  
  110.     case PRU_CONNECT2:
  111.         error = unp_connect2(so, (struct socket *)nam);
  112.         break;
  113.  
  114.     case PRU_DISCONNECT:
  115.         unp_disconnect(unp);
  116.         break;
  117.  
  118.     case PRU_ACCEPT:
  119.         /*
  120.          * Pass back name of connected socket,
  121.          * if it was bound and we are still connected
  122.          * (our peer may have closed already!).
  123.          */
  124.         if (unp->unp_conn && unp->unp_conn->unp_addr) {
  125.             nam->m_len = unp->unp_conn->unp_addr->m_len;
  126.             bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
  127.                 mtod(nam, caddr_t), (unsigned)nam->m_len);
  128.         } else {
  129.             nam->m_len = sizeof(sun_noname);
  130.             *(mtod(nam, struct sockaddr *)) = sun_noname;
  131.         }
  132.         break;
  133.  
  134.     case PRU_SHUTDOWN:
  135.         socantsendmore(so);
  136.         unp_shutdown(unp);
  137.         break;
  138.  
  139.     case PRU_RCVD:
  140.         switch (so->so_type) {
  141.  
  142.         case SOCK_DGRAM:
  143.             panic("uipc 1");
  144.             /*NOTREACHED*/
  145.  
  146.         case SOCK_STREAM:
  147. #define    rcv (&so->so_rcv)
  148. #define snd (&so2->so_snd)
  149.             if (unp->unp_conn == 0)
  150.                 break;
  151.             so2 = unp->unp_conn->unp_socket;
  152.             /*
  153.              * Adjust backpressure on sender
  154.              * and wakeup any waiting to write.
  155.              */
  156.             snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;
  157.             unp->unp_mbcnt = rcv->sb_mbcnt;
  158.             snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;
  159.             unp->unp_cc = rcv->sb_cc;
  160.             sowwakeup(so2);
  161. #undef snd
  162. #undef rcv
  163.             break;
  164.  
  165.         default:
  166.             panic("uipc 2");
  167.         }
  168.         break;
  169.  
  170.     case PRU_SEND:
  171.         if (control && (error = unp_internalize(control, p)))
  172.             break;
  173.         switch (so->so_type) {
  174.  
  175.         case SOCK_DGRAM: {
  176.             struct sockaddr *from;
  177.  
  178.             if (nam) {
  179.                 if (unp->unp_conn) {
  180.                     error = EISCONN;
  181.                     break;
  182.                 }
  183.                 error = unp_connect(so, nam, p);
  184.                 if (error)
  185.                     break;
  186.             } else {
  187.                 if (unp->unp_conn == 0) {
  188.                     error = ENOTCONN;
  189.                     break;
  190.                 }
  191.             }
  192.             so2 = unp->unp_conn->unp_socket;
  193.             if (unp->unp_addr)
  194.                 from = mtod(unp->unp_addr, struct sockaddr *);
  195.             else
  196.                 from = &sun_noname;
  197.             if (sbappendaddr(&so2->so_rcv, from, m, control)) {
  198.                 sorwakeup(so2);
  199.                 m = 0;
  200.                 control = 0;
  201.             } else
  202.                 error = ENOBUFS;
  203.             if (nam)
  204.                 unp_disconnect(unp);
  205.             break;
  206.         }
  207.  
  208.         case SOCK_STREAM:
  209. #define    rcv (&so2->so_rcv)
  210. #define    snd (&so->so_snd)
  211.             if (so->so_state & SS_CANTSENDMORE) {
  212.                 error = EPIPE;
  213.                 break;
  214.             }
  215.             if (unp->unp_conn == 0)
  216.                 panic("uipc 3");
  217.             so2 = unp->unp_conn->unp_socket;
  218.             /*
  219.              * Send to paired receive port, and then reduce
  220.              * send buffer hiwater marks to maintain backpressure.
  221.              * Wake up readers.
  222.              */
  223.             if (control) {
  224.                 if (sbappendcontrol(rcv, m, control))
  225.                     control = 0;
  226.             } else
  227.                 sbappend(rcv, m);
  228.             snd->sb_mbmax -=
  229.                 rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;
  230.             unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;
  231.             snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;
  232.             unp->unp_conn->unp_cc = rcv->sb_cc;
  233.             sorwakeup(so2);
  234.             m = 0;
  235. #undef snd
  236. #undef rcv
  237.             break;
  238.  
  239.         default:
  240.             panic("uipc 4");
  241.         }
  242.         break;
  243.  
  244.     case PRU_ABORT:
  245.         unp_drop(unp, ECONNABORTED);
  246.         break;
  247.  
  248.     case PRU_SENSE:
  249.         ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
  250.         if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
  251.             so2 = unp->unp_conn->unp_socket;
  252.             ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
  253.         }
  254.         ((struct stat *) m)->st_dev = NODEV;
  255.         if (unp->unp_ino == 0)
  256.             unp->unp_ino = unp_ino++;
  257.         ((struct stat *) m)->st_ino = unp->unp_ino;
  258.         return (0);
  259.  
  260.     case PRU_RCVOOB:
  261.         return (EOPNOTSUPP);
  262.  
  263.     case PRU_SENDOOB:
  264.         error = EOPNOTSUPP;
  265.         break;
  266.  
  267.     case PRU_SOCKADDR:
  268.         if (unp->unp_addr) {
  269.             nam->m_len = unp->unp_addr->m_len;
  270.             bcopy(mtod(unp->unp_addr, caddr_t),
  271.                 mtod(nam, caddr_t), (unsigned)nam->m_len);
  272.         } else
  273.             nam->m_len = 0;
  274.         break;
  275.  
  276.     case PRU_PEERADDR:
  277.         if (unp->unp_conn && unp->unp_conn->unp_addr) {
  278.             nam->m_len = unp->unp_conn->unp_addr->m_len;
  279.             bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
  280.                 mtod(nam, caddr_t), (unsigned)nam->m_len);
  281.         } else
  282.             nam->m_len = 0;
  283.         break;
  284.  
  285.     case PRU_SLOWTIMO:
  286.         break;
  287.  
  288.     default:
  289.         panic("piusrreq");
  290.     }
  291. release:
  292.     if (control)
  293.         m_freem(control);
  294.     if (m)
  295.         m_freem(m);
  296.     return (error);
  297. }
  298.  
  299. /*
  300.  * Both send and receive buffers are allocated PIPSIZ bytes of buffering
  301.  * for stream sockets, although the total for sender and receiver is
  302.  * actually only PIPSIZ.
  303.  * Datagram sockets really use the sendspace as the maximum datagram size,
  304.  * and don't really want to reserve the sendspace.  Their recvspace should
  305.  * be large enough for at least one max-size datagram plus address.
  306.  */
  307. #define    PIPSIZ    4096
  308. u_long    unpst_sendspace = PIPSIZ;
  309. u_long    unpst_recvspace = PIPSIZ;
  310. u_long    unpdg_sendspace = 2*1024;    /* really max datagram size */
  311. u_long    unpdg_recvspace = 4*1024;
  312.  
  313. int    unp_rights;            /* file descriptors in flight */
  314.  
  315. unp_attach(so)
  316.     struct socket *so;
  317. {
  318.     register struct mbuf *m;
  319.     register struct unpcb *unp;
  320.     int error;
  321.     
  322.     if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
  323.         switch (so->so_type) {
  324.  
  325.         case SOCK_STREAM:
  326.             error = soreserve(so, unpst_sendspace, unpst_recvspace);
  327.             break;
  328.  
  329.         case SOCK_DGRAM:
  330.             error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
  331.             break;
  332.         }
  333.         if (error)
  334.             return (error);
  335.     }
  336.     m = m_getclr(M_DONTWAIT, MT_PCB);
  337.     if (m == NULL)
  338.         return (ENOBUFS);
  339.     unp = mtod(m, struct unpcb *);
  340.     so->so_pcb = (caddr_t)unp;
  341.     unp->unp_socket = so;
  342.     return (0);
  343. }
  344.  
  345. unp_detach(unp)
  346.     register struct unpcb *unp;
  347. {
  348.     
  349.     if (unp->unp_vnode) {
  350.         unp->unp_vnode->v_socket = 0;
  351.         vrele(unp->unp_vnode);
  352.         unp->unp_vnode = 0;
  353.     }
  354.     if (unp->unp_conn)
  355.         unp_disconnect(unp);
  356.     while (unp->unp_refs)
  357.         unp_drop(unp->unp_refs, ECONNRESET);
  358.     soisdisconnected(unp->unp_socket);
  359.     unp->unp_socket->so_pcb = 0;
  360.     m_freem(unp->unp_addr);
  361.     (void) m_free(dtom(unp));
  362.     if (unp_rights)
  363.         unp_gc();
  364. }
  365.  
  366. unp_bind(unp, nam, p)
  367.     struct unpcb *unp;
  368.     struct mbuf *nam;
  369.     struct proc *p;
  370. {
  371.     struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
  372.     register struct vnode *vp;
  373.     register struct nameidata *ndp;
  374.     struct vattr vattr;
  375.     int error;
  376.     struct nameidata nd;
  377.  
  378.     ndp = &nd;
  379.     ndp->ni_dirp = soun->sun_path;
  380.     if (unp->unp_vnode != NULL)
  381.         return (EINVAL);
  382.     if (nam->m_len == MLEN) {
  383.         if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
  384.             return (EINVAL);
  385.     } else
  386.         *(mtod(nam, caddr_t) + nam->m_len) = 0;
  387. /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
  388.     ndp->ni_nameiop = CREATE | FOLLOW | LOCKPARENT;
  389.     ndp->ni_segflg = UIO_SYSSPACE;
  390.     if (error = namei(ndp, p))
  391.         return (error);
  392.     vp = ndp->ni_vp;
  393.     if (vp != NULL) {
  394.         VOP_ABORTOP(ndp);
  395.         if (ndp->ni_dvp == vp)
  396.             vrele(ndp->ni_dvp);
  397.         else
  398.             vput(ndp->ni_dvp);
  399.         vrele(vp);
  400.         return (EADDRINUSE);
  401.     }
  402.     VATTR_NULL(&vattr);
  403.     vattr.va_type = VSOCK;
  404.     vattr.va_mode = 0777;
  405.     if (error = VOP_CREATE(ndp, &vattr, p))
  406.         return (error);
  407.     vp = ndp->ni_vp;
  408.     vp->v_socket = unp->unp_socket;
  409.     unp->unp_vnode = vp;
  410.     unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);
  411.     VOP_UNLOCK(vp);
  412.     return (0);
  413. }
  414.  
  415. unp_connect(so, nam, p)
  416.     struct socket *so;
  417.     struct mbuf *nam;
  418.     struct proc *p;
  419. {
  420.     register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
  421.     register struct vnode *vp;
  422.     register struct socket *so2, *so3;
  423.     register struct nameidata *ndp;
  424.     struct unpcb *unp2, *unp3;
  425.     int error;
  426.     struct nameidata nd;
  427.  
  428.     ndp = &nd;
  429.     ndp->ni_dirp = soun->sun_path;
  430.     if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) {    /* XXX */
  431.         if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
  432.             return (EMSGSIZE);
  433.     } else
  434.         *(mtod(nam, caddr_t) + nam->m_len) = 0;
  435.     ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
  436.     ndp->ni_segflg = UIO_SYSSPACE;
  437.     if (error = namei(ndp, p))
  438.         return (error);
  439.     vp = ndp->ni_vp;
  440.     if (vp->v_type != VSOCK) {
  441.         error = ENOTSOCK;
  442.         goto bad;
  443.     }
  444.     if (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))
  445.         goto bad;
  446.     so2 = vp->v_socket;
  447.     if (so2 == 0) {
  448.         error = ECONNREFUSED;
  449.         goto bad;
  450.     }
  451.     if (so->so_type != so2->so_type) {
  452.         error = EPROTOTYPE;
  453.         goto bad;
  454.     }
  455.     if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
  456.         if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
  457.             (so3 = sonewconn(so2, 0)) == 0) {
  458.             error = ECONNREFUSED;
  459.             goto bad;
  460.         }
  461.         unp2 = sotounpcb(so2);
  462.         unp3 = sotounpcb(so3);
  463.         if (unp2->unp_addr)
  464.             unp3->unp_addr =
  465.                   m_copy(unp2->unp_addr, 0, (int)M_COPYALL);
  466.         so2 = so3;
  467.     }
  468.     error = unp_connect2(so, so2);
  469. bad:
  470.     vput(vp);
  471.     return (error);
  472. }
  473.  
  474. unp_connect2(so, so2)
  475.     register struct socket *so;
  476.     register struct socket *so2;
  477. {
  478.     register struct unpcb *unp = sotounpcb(so);
  479.     register struct unpcb *unp2;
  480.  
  481.     if (so2->so_type != so->so_type)
  482.         return (EPROTOTYPE);
  483.     unp2 = sotounpcb(so2);
  484.     unp->unp_conn = unp2;
  485.     switch (so->so_type) {
  486.  
  487.     case SOCK_DGRAM:
  488.         unp->unp_nextref = unp2->unp_refs;
  489.         unp2->unp_refs = unp;
  490.         soisconnected(so);
  491.         break;
  492.  
  493.     case SOCK_STREAM:
  494.         unp2->unp_conn = unp;
  495.         soisconnected(so);
  496.         soisconnected(so2);
  497.         break;
  498.  
  499.     default:
  500.         panic("unp_connect2");
  501.     }
  502.     return (0);
  503. }
  504.  
  505. unp_disconnect(unp)
  506.     struct unpcb *unp;
  507. {
  508.     register struct unpcb *unp2 = unp->unp_conn;
  509.  
  510.     if (unp2 == 0)
  511.         return;
  512.     unp->unp_conn = 0;
  513.     switch (unp->unp_socket->so_type) {
  514.  
  515.     case SOCK_DGRAM:
  516.         if (unp2->unp_refs == unp)
  517.             unp2->unp_refs = unp->unp_nextref;
  518.         else {
  519.             unp2 = unp2->unp_refs;
  520.             for (;;) {
  521.                 if (unp2 == 0)
  522.                     panic("unp_disconnect");
  523.                 if (unp2->unp_nextref == unp)
  524.                     break;
  525.                 unp2 = unp2->unp_nextref;
  526.             }
  527.             unp2->unp_nextref = unp->unp_nextref;
  528.         }
  529.         unp->unp_nextref = 0;
  530.         unp->unp_socket->so_state &= ~SS_ISCONNECTED;
  531.         break;
  532.  
  533.     case SOCK_STREAM:
  534.         soisdisconnected(unp->unp_socket);
  535.         unp2->unp_conn = 0;
  536.         soisdisconnected(unp2->unp_socket);
  537.         break;
  538.     }
  539. }
  540.  
  541. #ifdef notdef
  542. unp_abort(unp)
  543.     struct unpcb *unp;
  544. {
  545.  
  546.     unp_detach(unp);
  547. }
  548. #endif
  549.  
  550. unp_shutdown(unp)
  551.     struct unpcb *unp;
  552. {
  553.     struct socket *so;
  554.  
  555.     if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn &&
  556.         (so = unp->unp_conn->unp_socket))
  557.         socantrcvmore(so);
  558. }
  559.  
  560. unp_drop(unp, errno)
  561.     struct unpcb *unp;
  562.     int errno;
  563. {
  564.     struct socket *so = unp->unp_socket;
  565.  
  566.     so->so_error = errno;
  567.     unp_disconnect(unp);
  568.     if (so->so_head) {
  569.         so->so_pcb = (caddr_t) 0;
  570.         m_freem(unp->unp_addr);
  571.         (void) m_free(dtom(unp));
  572.         sofree(so);
  573.     }
  574. }
  575.  
  576. #ifdef notdef
  577. unp_drain()
  578. {
  579.  
  580. }
  581. #endif
  582.  
  583. unp_externalize(rights)
  584.     struct mbuf *rights;
  585. {
  586.     struct proc *p = curproc;        /* XXX */
  587.     register int i;
  588.     register struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
  589.     register struct file **rp = (struct file **)(cm + 1);
  590.     register struct file *fp;
  591.     int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int);
  592.     int f;
  593.  
  594.     if (fdavail(p, newfds)) {
  595.         for (i = 0; i < newfds; i++) {
  596.             fp = *rp;
  597.             unp_discard(fp);
  598.             *rp++ = 0;
  599.         }
  600.         return (EMSGSIZE);
  601.     }
  602.     for (i = 0; i < newfds; i++) {
  603.         if (fdalloc(p, 0, &f))
  604.             panic("unp_externalize");
  605.         fp = *rp;
  606.         p->p_fd->fd_ofiles[f] = fp;
  607.         fp->f_msgcount--;
  608.         unp_rights--;
  609.         *(int *)rp++ = f;
  610.     }
  611.     return (0);
  612. }
  613.  
  614. unp_internalize(control, p)
  615.     struct mbuf *control;
  616.     struct proc *p;
  617. {
  618.     struct filedesc *fdp = p->p_fd;
  619.     register struct cmsghdr *cm = mtod(control, struct cmsghdr *);
  620.     register struct file **rp;
  621.     register struct file *fp;
  622.     register int i, fd;
  623.     int oldfds;
  624.  
  625.     if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
  626.         cm->cmsg_len != control->m_len)
  627.         return (EINVAL);
  628.     oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);
  629.     rp = (struct file **)(cm + 1);
  630.     for (i = 0; i < oldfds; i++) {
  631.         fd = *(int *)rp++;
  632.         if ((unsigned)fd >= fdp->fd_nfiles ||
  633.             fdp->fd_ofiles[fd] == NULL)
  634.             return (EBADF);
  635.     }
  636.     rp = (struct file **)(cm + 1);
  637.     for (i = 0; i < oldfds; i++) {
  638.         fp = fdp->fd_ofiles[*(int *)rp];
  639.         *rp++ = fp;
  640.         fp->f_count++;
  641.         fp->f_msgcount++;
  642.         unp_rights++;
  643.     }
  644.     return (0);
  645. }
  646.  
  647. int    unp_defer, unp_gcing;
  648. int    unp_mark();
  649. extern    struct domain unixdomain;
  650.  
  651. unp_gc()
  652. {
  653.     register struct file *fp;
  654.     register struct socket *so;
  655.  
  656.     if (unp_gcing)
  657.         return;
  658.     unp_gcing = 1;
  659. restart:
  660.     unp_defer = 0;
  661.     for (fp = filehead; fp; fp = fp->f_filef)
  662.         fp->f_flag &= ~(FMARK|FDEFER);
  663.     do {
  664.         for (fp = filehead; fp; fp = fp->f_filef) {
  665.             if (fp->f_count == 0)
  666.                 continue;
  667.             if (fp->f_flag & FDEFER) {
  668.                 fp->f_flag &= ~FDEFER;
  669.                 unp_defer--;
  670.             } else {
  671.                 if (fp->f_flag & FMARK)
  672.                     continue;
  673.                 if (fp->f_count == fp->f_msgcount)
  674.                     continue;
  675.                 fp->f_flag |= FMARK;
  676.             }
  677.             if (fp->f_type != DTYPE_SOCKET ||
  678.                 (so = (struct socket *)fp->f_data) == 0)
  679.                 continue;
  680.             if (so->so_proto->pr_domain != &unixdomain ||
  681.                 (so->so_proto->pr_flags&PR_RIGHTS) == 0)
  682.                 continue;
  683. #ifdef notdef
  684.             if (so->so_rcv.sb_flags & SB_LOCK) {
  685.                 /*
  686.                  * This is problematical; it's not clear
  687.                  * we need to wait for the sockbuf to be
  688.                  * unlocked (on a uniprocessor, at least),
  689.                  * and it's also not clear what to do
  690.                  * if sbwait returns an error due to receipt
  691.                  * of a signal.  If sbwait does return
  692.                  * an error, we'll go into an infinite
  693.                  * loop.  Delete all of this for now.
  694.                  */
  695.                 (void) sbwait(&so->so_rcv);
  696.                 goto restart;
  697.             }
  698. #endif
  699.             unp_scan(so->so_rcv.sb_mb, unp_mark);
  700.         }
  701.     } while (unp_defer);
  702.     for (fp = filehead; fp; fp = fp->f_filef) {
  703.         if (fp->f_count == 0)
  704.             continue;
  705.         if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0)
  706.             while (fp->f_msgcount)
  707.                 unp_discard(fp);
  708.     }
  709.     unp_gcing = 0;
  710. }
  711.  
  712. unp_dispose(m)
  713.     struct mbuf *m;
  714. {
  715.     int unp_discard();
  716.  
  717.     if (m)
  718.         unp_scan(m, unp_discard);
  719. }
  720.  
  721. unp_scan(m0, op)
  722.     register struct mbuf *m0;
  723.     int (*op)();
  724. {
  725.     register struct mbuf *m;
  726.     register struct file **rp;
  727.     register struct cmsghdr *cm;
  728.     register int i;
  729.     int qfds;
  730.  
  731.     while (m0) {
  732.         for (m = m0; m; m = m->m_next)
  733.             if (m->m_type == MT_CONTROL &&
  734.                 m->m_len >= sizeof(*cm)) {
  735.                 cm = mtod(m, struct cmsghdr *);
  736.                 if (cm->cmsg_level != SOL_SOCKET ||
  737.                     cm->cmsg_type != SCM_RIGHTS)
  738.                     continue;
  739.                 qfds = (cm->cmsg_len - sizeof *cm)
  740.                         / sizeof (struct file *);
  741.                 rp = (struct file **)(cm + 1);
  742.                 for (i = 0; i < qfds; i++)
  743.                     (*op)(*rp++);
  744.                 break;        /* XXX, but saves time */
  745.             }
  746.         m0 = m0->m_act;
  747.     }
  748. }
  749.  
  750. unp_mark(fp)
  751.     struct file *fp;
  752. {
  753.  
  754.     if (fp->f_flag & FMARK)
  755.         return;
  756.     unp_defer++;
  757.     fp->f_flag |= (FMARK|FDEFER);
  758. }
  759.  
  760. unp_discard(fp)
  761.     struct file *fp;
  762. {
  763.  
  764.     fp->f_msgcount--;
  765.     unp_rights--;
  766.     (void) closef(fp);
  767. }
  768.