Annotation of XNU/bsd/kern/uipc_usrreq.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:  * Copyright (c) 1982, 1986, 1989, 1991, 1993
        !            24:  *     The Regents of the University of California.  All rights reserved.
        !            25:  *
        !            26:  * Redistribution and use in source and binary forms, with or without
        !            27:  * modification, are permitted provided that the following conditions
        !            28:  * are met:
        !            29:  * 1. Redistributions of source code must retain the above copyright
        !            30:  *    notice, this list of conditions and the following disclaimer.
        !            31:  * 2. Redistributions in binary form must reproduce the above copyright
        !            32:  *    notice, this list of conditions and the following disclaimer in the
        !            33:  *    documentation and/or other materials provided with the distribution.
        !            34:  * 3. All advertising materials mentioning features or use of this software
        !            35:  *    must display the following acknowledgement:
        !            36:  *     This product includes software developed by the University of
        !            37:  *     California, Berkeley and its contributors.
        !            38:  * 4. Neither the name of the University nor the names of its contributors
        !            39:  *    may be used to endorse or promote products derived from this software
        !            40:  *    without specific prior written permission.
        !            41:  *
        !            42:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            43:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            44:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            45:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            46:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            47:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            48:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            49:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            50:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            51:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            52:  * SUCH DAMAGE.
        !            53:  *
        !            54:  *     From: @(#)uipc_usrreq.c 8.3 (Berkeley) 1/4/94
        !            55:  */
        !            56: 
        !            57: #include <sys/param.h>
        !            58: #include <sys/systm.h>
        !            59: #include <sys/kernel.h>
        !            60: #include <sys/domain.h>
        !            61: #include <sys/fcntl.h>
        !            62: #include <sys/malloc.h>                /* XXX must be before <sys/file.h> */
        !            63: #include <sys/file.h>
        !            64: #include <sys/filedesc.h>
        !            65: #include <sys/lock.h>
        !            66: #include <sys/mbuf.h>
        !            67: #include <sys/namei.h>
        !            68: #include <sys/proc.h>
        !            69: #include <sys/protosw.h>
        !            70: #include <sys/socket.h>
        !            71: #include <sys/socketvar.h>
        !            72: #include <sys/stat.h>
        !            73: #include <sys/sysctl.h>
        !            74: #include <sys/un.h>
        !            75: #include <sys/unpcb.h>
        !            76: #include <sys/vnode.h>
        !            77: 
        !            78: #include <kern/zalloc.h>
        !            79: 
        !            80: struct zone *unp_zone;
        !            81: static unp_gen_t unp_gencnt;
        !            82: static u_int unp_count;
        !            83: 
        !            84: static struct unp_head unp_shead, unp_dhead;
        !            85: 
        !            86: /*
        !            87:  * Unix communications domain.
        !            88:  *
        !            89:  * TODO:
        !            90:  *     SEQPACKET, RDM
        !            91:  *     rethink name space problems
        !            92:  *     need a proper out-of-band
        !            93:  *     lock pushdown
        !            94:  */
        !            95: static struct  sockaddr sun_noname = { sizeof(sun_noname), AF_LOCAL };
        !            96: static ino_t   unp_ino;                /* prototype for fake inode numbers */
        !            97: 
        !            98: static int     unp_attach __P((struct socket *));
        !            99: static void    unp_detach __P((struct unpcb *));
        !           100: static int     unp_bind __P((struct unpcb *,struct sockaddr *, struct proc *));
        !           101: static int     unp_connect __P((struct socket *,struct sockaddr *,
        !           102:                                struct proc *));
        !           103: static void    unp_disconnect __P((struct unpcb *));
        !           104: static void    unp_shutdown __P((struct unpcb *));
        !           105: static void    unp_drop __P((struct unpcb *, int));
        !           106: static void    unp_gc __P((void));
        !           107: static void    unp_scan __P((struct mbuf *, void (*)(struct file *)));
        !           108: static void    unp_mark __P((struct file *));
        !           109: static void    unp_discard __P((struct file *));
        !           110: static int     unp_internalize __P((struct mbuf *, struct proc *));
        !           111: 
        !           112: static int
        !           113: uipc_abort(struct socket *so)
        !           114: {
        !           115:        struct unpcb *unp = sotounpcb(so);
        !           116: 
        !           117:        if (unp == 0)
        !           118:                return EINVAL;
        !           119:        unp_drop(unp, ECONNABORTED);
        !           120:        return 0;
        !           121: }
        !           122: 
        !           123: static int
        !           124: uipc_accept(struct socket *so, struct sockaddr **nam)
        !           125: {
        !           126:        struct unpcb *unp = sotounpcb(so);
        !           127: 
        !           128:        if (unp == 0)
        !           129:                return EINVAL;
        !           130: 
        !           131:        /*
        !           132:         * Pass back name of connected socket,
        !           133:         * if it was bound and we are still connected
        !           134:         * (our peer may have closed already!).
        !           135:         */
        !           136:        if (unp->unp_conn && unp->unp_conn->unp_addr) {
        !           137:                *nam = dup_sockaddr((struct sockaddr *)unp->unp_conn->unp_addr,
        !           138:                                    1);
        !           139:        } else {
        !           140:                *nam = dup_sockaddr((struct sockaddr *)&sun_noname, 1);
        !           141:        }
        !           142:        return 0;
        !           143: }
        !           144: 
        !           145: static int
        !           146: uipc_attach(struct socket *so, int proto, struct proc *p)
        !           147: {
        !           148:        struct unpcb *unp = sotounpcb(so);
        !           149: 
        !           150:        if (unp != 0)
        !           151:                return EISCONN;
        !           152:        return unp_attach(so);
        !           153: }
        !           154: 
        !           155: static int
        !           156: uipc_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
        !           157: {
        !           158:        struct unpcb *unp = sotounpcb(so);
        !           159: 
        !           160:        if (unp == 0)
        !           161:                return EINVAL;
        !           162: 
        !           163:        return unp_bind(unp, nam, p);
        !           164: }
        !           165: 
        !           166: static int
        !           167: uipc_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
        !           168: {
        !           169:        struct unpcb *unp = sotounpcb(so);
        !           170: 
        !           171:        if (unp == 0)
        !           172:                return EINVAL;
        !           173:        return unp_connect(so, nam, p);
        !           174: }
        !           175: 
        !           176: static int
        !           177: uipc_connect2(struct socket *so1, struct socket *so2)
        !           178: {
        !           179:        struct unpcb *unp = sotounpcb(so1);
        !           180: 
        !           181:        if (unp == 0)
        !           182:                return EINVAL;
        !           183: 
        !           184:        return unp_connect2(so1, so2);
        !           185: }
        !           186: 
        !           187: /* control is EOPNOTSUPP */
        !           188: 
        !           189: static int
        !           190: uipc_detach(struct socket *so)
        !           191: {
        !           192:        struct unpcb *unp = sotounpcb(so);
        !           193: 
        !           194:        if (unp == 0)
        !           195:                return EINVAL;
        !           196: 
        !           197:        unp_detach(unp);
        !           198:        return 0;
        !           199: }
        !           200: 
        !           201: static int
        !           202: uipc_disconnect(struct socket *so)
        !           203: {
        !           204:        struct unpcb *unp = sotounpcb(so);
        !           205: 
        !           206:        if (unp == 0)
        !           207:                return EINVAL;
        !           208:        unp_disconnect(unp);
        !           209:        return 0;
        !           210: }
        !           211: 
        !           212: static int
        !           213: uipc_listen(struct socket *so, struct proc *p)
        !           214: {
        !           215:        struct unpcb *unp = sotounpcb(so);
        !           216: 
        !           217:        if (unp == 0 || unp->unp_vnode == 0)
        !           218:                return EINVAL;
        !           219:        return 0;
        !           220: }
        !           221: 
        !           222: static int
        !           223: uipc_peeraddr(struct socket *so, struct sockaddr **nam)
        !           224: {
        !           225:        struct unpcb *unp = sotounpcb(so);
        !           226: 
        !           227:        if (unp == 0)
        !           228:                return EINVAL;
        !           229:        if (unp->unp_conn && unp->unp_conn->unp_addr)
        !           230:                *nam = dup_sockaddr((struct sockaddr *)unp->unp_conn->unp_addr,
        !           231:                                    1);
        !           232:        return 0;
        !           233: }
        !           234: 
        !           235: static int
        !           236: uipc_rcvd(struct socket *so, int flags)
        !           237: {
        !           238:        struct unpcb *unp = sotounpcb(so);
        !           239:        struct socket *so2;
        !           240: 
        !           241:        if (unp == 0)
        !           242:                return EINVAL;
        !           243:        switch (so->so_type) {
        !           244:        case SOCK_DGRAM:
        !           245:                panic("uipc_rcvd DGRAM?");
        !           246:                /*NOTREACHED*/
        !           247: 
        !           248:        case SOCK_STREAM:
        !           249: #define        rcv (&so->so_rcv)
        !           250: #define snd (&so2->so_snd)
        !           251:                if (unp->unp_conn == 0)
        !           252:                        break;
        !           253:                so2 = unp->unp_conn->unp_socket;
        !           254:                /*
        !           255:                 * Adjust backpressure on sender
        !           256:                 * and wakeup any waiting to write.
        !           257:                 */
        !           258:                snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;
        !           259:                unp->unp_mbcnt = rcv->sb_mbcnt;
        !           260:                snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;
        !           261:                unp->unp_cc = rcv->sb_cc;
        !           262:                sowwakeup(so2);
        !           263: #undef snd
        !           264: #undef rcv
        !           265:                break;
        !           266: 
        !           267:        default:
        !           268:                panic("uipc_rcvd unknown socktype");
        !           269:        }
        !           270:        return 0;
        !           271: }
        !           272: 
        !           273: /* pru_rcvoob is EOPNOTSUPP */
        !           274: 
        !           275: static int
        !           276: uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
        !           277:          struct mbuf *control, struct proc *p)
        !           278: {
        !           279:        int error = 0;
        !           280:        struct unpcb *unp = sotounpcb(so);
        !           281:        struct socket *so2;
        !           282: 
        !           283:        if (unp == 0) {
        !           284:                error = EINVAL;
        !           285:                goto release;
        !           286:        }
        !           287:        if (flags & PRUS_OOB) {
        !           288:                error = EOPNOTSUPP;
        !           289:                goto release;
        !           290:        }
        !           291: 
        !           292:        if (control && (error = unp_internalize(control, p)))
        !           293:                goto release;
        !           294: 
        !           295:        switch (so->so_type) {
        !           296:        case SOCK_DGRAM: 
        !           297:        {
        !           298:                struct sockaddr *from;
        !           299: 
        !           300:                if (nam) {
        !           301:                        if (unp->unp_conn) {
        !           302:                                error = EISCONN;
        !           303:                                break;
        !           304:                        }
        !           305:                        error = unp_connect(so, nam, p);
        !           306:                        if (error)
        !           307:                                break;
        !           308:                } else {
        !           309:                        if (unp->unp_conn == 0) {
        !           310:                                error = ENOTCONN;
        !           311:                                break;
        !           312:                        }
        !           313:                }
        !           314:                so2 = unp->unp_conn->unp_socket;
        !           315:                if (unp->unp_addr)
        !           316:                        from = (struct sockaddr *)unp->unp_addr;
        !           317:                else
        !           318:                        from = &sun_noname;
        !           319:                if (sbappendaddr(&so2->so_rcv, from, m, control)) {
        !           320:                        sorwakeup(so2);
        !           321:                        m = 0;
        !           322:                        control = 0;
        !           323:                } else
        !           324:                        error = ENOBUFS;
        !           325:                if (nam)
        !           326:                        unp_disconnect(unp);
        !           327:                break;
        !           328:        }
        !           329: 
        !           330:        case SOCK_STREAM:
        !           331: #define        rcv (&so2->so_rcv)
        !           332: #define        snd (&so->so_snd)
        !           333:                /* Connect if not connected yet. */
        !           334:                /*
        !           335:                 * Note: A better implementation would complain
        !           336:                 * if not equal to the peer's address.
        !           337:                 */
        !           338:                if ((so->so_state & SS_ISCONNECTED) == 0) {
        !           339:                        if (nam) {
        !           340:                                error = unp_connect(so, nam, p);
        !           341:                                if (error)
        !           342:                                        break;  /* XXX */
        !           343:                        } else {
        !           344:                                error = ENOTCONN;
        !           345:                                break;
        !           346:                        }
        !           347:                }
        !           348: 
        !           349:                if (so->so_state & SS_CANTSENDMORE) {
        !           350:                        error = EPIPE;
        !           351:                        break;
        !           352:                }
        !           353:                if (unp->unp_conn == 0)
        !           354:                        panic("uipc_send connected but no connection?");
        !           355:                so2 = unp->unp_conn->unp_socket;
        !           356:                /*
        !           357:                 * Send to paired receive port, and then reduce
        !           358:                 * send buffer hiwater marks to maintain backpressure.
        !           359:                 * Wake up readers.
        !           360:                 */
        !           361:                if (control) {
        !           362:                        if (sbappendcontrol(rcv, m, control))
        !           363:                                control = 0;
        !           364:                } else
        !           365:                        sbappend(rcv, m);
        !           366:                snd->sb_mbmax -=
        !           367:                        rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;
        !           368:                unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;
        !           369:                snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;
        !           370:                unp->unp_conn->unp_cc = rcv->sb_cc;
        !           371:                sorwakeup(so2);
        !           372:                m = 0;
        !           373: #undef snd
        !           374: #undef rcv
        !           375:                break;
        !           376: 
        !           377:        default:
        !           378:                panic("uipc_send unknown socktype");
        !           379:        }
        !           380: 
        !           381:        /*
        !           382:         * SEND_EOF is equivalent to a SEND followed by
        !           383:         * a SHUTDOWN.
        !           384:         */
        !           385:        if (flags & PRUS_EOF) {
        !           386:                socantsendmore(so);
        !           387:                unp_shutdown(unp);
        !           388:        }
        !           389: 
        !           390: release:
        !           391:        if (control)
        !           392:                m_freem(control);
        !           393:        if (m)
        !           394:                m_freem(m);
        !           395:        return error;
        !           396: }
        !           397: 
        !           398: static int
        !           399: uipc_sense(struct socket *so, struct stat *sb)
        !           400: {
        !           401:        struct unpcb *unp = sotounpcb(so);
        !           402:        struct socket *so2;
        !           403: 
        !           404:        if (unp == 0)
        !           405:                return EINVAL;
        !           406:        sb->st_blksize = so->so_snd.sb_hiwat;
        !           407:        if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
        !           408:                so2 = unp->unp_conn->unp_socket;
        !           409:                sb->st_blksize += so2->so_rcv.sb_cc;
        !           410:        }
        !           411:        sb->st_dev = NODEV;
        !           412:        if (unp->unp_ino == 0)
        !           413:                unp->unp_ino = unp_ino++;
        !           414:        sb->st_ino = unp->unp_ino;
        !           415:        return (0);
        !           416: }
        !           417: 
        !           418: static int
        !           419: uipc_shutdown(struct socket *so)
        !           420: {
        !           421:        struct unpcb *unp = sotounpcb(so);
        !           422: 
        !           423:        if (unp == 0)
        !           424:                return EINVAL;
        !           425:        socantsendmore(so);
        !           426:        unp_shutdown(unp);
        !           427:        return 0;
        !           428: }
        !           429: 
        !           430: static int
        !           431: uipc_sockaddr(struct socket *so, struct sockaddr **nam)
        !           432: {
        !           433:        struct unpcb *unp = sotounpcb(so);
        !           434: 
        !           435:        if (unp == 0)
        !           436:                return EINVAL;
        !           437:        if (unp->unp_addr)
        !           438:                *nam = dup_sockaddr((struct sockaddr *)unp->unp_addr, 1);
        !           439:        return 0;
        !           440: }
        !           441: 
        !           442: struct pr_usrreqs uipc_usrreqs = {
        !           443:        uipc_abort, uipc_accept, uipc_attach, uipc_bind, uipc_connect,
        !           444:        uipc_connect2, pru_control_notsupp, uipc_detach, uipc_disconnect,
        !           445:        uipc_listen, uipc_peeraddr, uipc_rcvd, pru_rcvoob_notsupp,
        !           446:        uipc_send, uipc_sense, uipc_shutdown, uipc_sockaddr,
        !           447:        sosend, soreceive, sopoll
        !           448: };
        !           449:        
        !           450: /*
        !           451:  * Both send and receive buffers are allocated PIPSIZ bytes of buffering
        !           452:  * for stream sockets, although the total for sender and receiver is
        !           453:  * actually only PIPSIZ.
        !           454:  * Datagram sockets really use the sendspace as the maximum datagram size,
        !           455:  * and don't really want to reserve the sendspace.  Their recvspace should
        !           456:  * be large enough for at least one max-size datagram plus address.
        !           457:  */
        !           458: #ifndef PIPSIZ
        !           459: #define        PIPSIZ  8192
        !           460: #endif
        !           461: static u_long  unpst_sendspace = PIPSIZ;
        !           462: static u_long  unpst_recvspace = PIPSIZ;
        !           463: static u_long  unpdg_sendspace = 2*1024;       /* really max datagram size */
        !           464: static u_long  unpdg_recvspace = 4*1024;
        !           465: 
        !           466: static int     unp_rights;                     /* file descriptors in flight */
        !           467: 
        !           468: SYSCTL_DECL(_net_local_stream);
        !           469: SYSCTL_INT(_net_local_stream, OID_AUTO, sendspace, CTLFLAG_RW, 
        !           470:           &unpst_sendspace, 0, "");
        !           471: SYSCTL_INT(_net_local_stream, OID_AUTO, recvspace, CTLFLAG_RW,
        !           472:           &unpst_recvspace, 0, "");
        !           473: SYSCTL_DECL(_net_local_dgram);
        !           474: SYSCTL_INT(_net_local_dgram, OID_AUTO, maxdgram, CTLFLAG_RW,
        !           475:           &unpdg_sendspace, 0, "");
        !           476: SYSCTL_INT(_net_local_dgram, OID_AUTO, recvspace, CTLFLAG_RW,
        !           477:           &unpdg_recvspace, 0, "");
        !           478: SYSCTL_DECL(_net_local);
        !           479: SYSCTL_INT(_net_local, OID_AUTO, inflight, CTLFLAG_RD, &unp_rights, 0, "");
        !           480: 
        !           481: static int
        !           482: unp_attach(so)
        !           483:        struct socket *so;
        !           484: {
        !           485:        register struct unpcb *unp;
        !           486:        int error;
        !           487: 
        !           488:        if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
        !           489:                switch (so->so_type) {
        !           490: 
        !           491:                case SOCK_STREAM:
        !           492:                        error = soreserve(so, unpst_sendspace, unpst_recvspace);
        !           493:                        break;
        !           494: 
        !           495:                case SOCK_DGRAM:
        !           496:                        error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
        !           497:                        break;
        !           498: 
        !           499:                default:
        !           500:                        panic("unp_attach");
        !           501:                }
        !           502:                if (error)
        !           503:                        return (error);
        !           504:        }
        !           505:        unp = zalloc(unp_zone);
        !           506:        if (unp == NULL)
        !           507:                return (ENOBUFS);
        !           508:        bzero(unp, sizeof *unp);
        !           509:        unp->unp_gencnt = ++unp_gencnt;
        !           510:        unp_count++;
        !           511:        LIST_INIT(&unp->unp_refs);
        !           512:        unp->unp_socket = so;
        !           513:        LIST_INSERT_HEAD(so->so_type == SOCK_DGRAM ? &unp_dhead
        !           514:                         : &unp_shead, unp, unp_link);
        !           515:        so->so_pcb = (caddr_t)unp;
        !           516:        return (0);
        !           517: }
        !           518: 
        !           519: static void
        !           520: unp_detach(unp)
        !           521:        register struct unpcb *unp;
        !           522: {
        !           523:        LIST_REMOVE(unp, unp_link);
        !           524:        unp->unp_gencnt = ++unp_gencnt;
        !           525:        --unp_count;
        !           526:        if (unp->unp_vnode) {
        !           527:                unp->unp_vnode->v_socket = 0;
        !           528:                vrele(unp->unp_vnode);
        !           529:                unp->unp_vnode = 0;
        !           530:        }
        !           531:        if (unp->unp_conn)
        !           532:                unp_disconnect(unp);
        !           533:        while (unp->unp_refs.lh_first)
        !           534:                unp_drop(unp->unp_refs.lh_first, ECONNRESET);
        !           535:        soisdisconnected(unp->unp_socket);
        !           536:        unp->unp_socket->so_pcb = 0;
        !           537:        if (unp_rights) {
        !           538:                /*
        !           539:                 * Normally the receive buffer is flushed later,
        !           540:                 * in sofree, but if our receive buffer holds references
        !           541:                 * to descriptors that are now garbage, we will dispose
        !           542:                 * of those descriptor references after the garbage collector
        !           543:                 * gets them (resulting in a "panic: closef: count < 0").
        !           544:                 */
        !           545:                sorflush(unp->unp_socket);
        !           546:                unp_gc();
        !           547:        }
        !           548:        if (unp->unp_addr)
        !           549:                FREE(unp->unp_addr, M_SONAME);
        !           550:        zfree(unp_zone, unp);
        !           551: }
        !           552: 
        !           553: static int
        !           554: unp_bind(unp, nam, p)
        !           555:        struct unpcb *unp;
        !           556:        struct sockaddr *nam;
        !           557:        struct proc *p;
        !           558: {
        !           559:        struct sockaddr_un *soun = (struct sockaddr_un *)nam;
        !           560:        register struct vnode *vp;
        !           561:        struct vattr vattr;
        !           562:        int error, namelen;
        !           563:        struct nameidata nd;
        !           564:        char buf[SOCK_MAXADDRLEN];
        !           565: 
        !           566:        if (unp->unp_vnode != NULL)
        !           567:                return (EINVAL);
        !           568: #define offsetof(s, e) ((char *)&((s *)0)->e - (char *)((s *)0))
        !           569:        namelen = soun->sun_len - offsetof(struct sockaddr_un, sun_path);
        !           570:        if (namelen <= 0)
        !           571:                return EINVAL;
        !           572:        strncpy(buf, soun->sun_path, namelen);
        !           573:        buf[namelen] = 0;       /* null-terminate the string */
        !           574:        NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_SYSSPACE,
        !           575:            buf, p);
        !           576: /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
        !           577:        error = namei(&nd);
        !           578:        if (error)
        !           579:                return (error);
        !           580:        vp = nd.ni_vp;
        !           581:        if (vp != NULL) {
        !           582:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
        !           583:                if (nd.ni_dvp == vp)
        !           584:                        vrele(nd.ni_dvp);
        !           585:                else
        !           586:                        vput(nd.ni_dvp);
        !           587:                vrele(vp);
        !           588:                return (EADDRINUSE);
        !           589:        }
        !           590:        VATTR_NULL(&vattr);
        !           591:        vattr.va_type = VSOCK;
        !           592:        vattr.va_mode = (ACCESSPERMS & ~p->p_fd->fd_cmask);
        !           593:        VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
        !           594:        error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
        !           595: #if 0
        !           596:        /* In FreeBSD create leave s parent held ; not here */
        !           597:        vput(nd.ni_dvp);
        !           598: #endif
        !           599:        if (error)
        !           600:                return (error);
        !           601:        vp = nd.ni_vp;
        !           602:        vp->v_socket = unp->unp_socket;
        !           603:        unp->unp_vnode = vp;
        !           604:        unp->unp_addr = (struct sockaddr_un *)dup_sockaddr(nam, 1);
        !           605:        VOP_UNLOCK(vp, 0, p);
        !           606:        return (0);
        !           607: }
        !           608: 
        !           609: static int
        !           610: unp_connect(so, nam, p)
        !           611:        struct socket *so;
        !           612:        struct sockaddr *nam;
        !           613:        struct proc *p;
        !           614: {
        !           615:        register struct sockaddr_un *soun = (struct sockaddr_un *)nam;
        !           616:        register struct vnode *vp;
        !           617:        register struct socket *so2, *so3;
        !           618:        struct unpcb *unp2, *unp3;
        !           619:        int error, len;
        !           620:        struct nameidata nd;
        !           621:        char buf[SOCK_MAXADDRLEN];
        !           622: 
        !           623:        len = nam->sa_len - offsetof(struct sockaddr_un, sun_path);
        !           624:        if (len <= 0)
        !           625:                return EINVAL;
        !           626:        strncpy(buf, soun->sun_path, len);
        !           627:        buf[len] = 0;
        !           628: 
        !           629:        NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, buf, p);
        !           630:        error = namei(&nd);
        !           631:        if (error)
        !           632:                return (error);
        !           633:        vp = nd.ni_vp;
        !           634:        if (vp->v_type != VSOCK) {
        !           635:                error = ENOTSOCK;
        !           636:                goto bad;
        !           637:        }
        !           638:        error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p);
        !           639:        if (error)
        !           640:                goto bad;
        !           641:        so2 = vp->v_socket;
        !           642:        if (so2 == 0) {
        !           643:                error = ECONNREFUSED;
        !           644:                goto bad;
        !           645:        }
        !           646:        if (so->so_type != so2->so_type) {
        !           647:                error = EPROTOTYPE;
        !           648:                goto bad;
        !           649:        }
        !           650:        if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
        !           651:                if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
        !           652:                    (so3 = sonewconn(so2, 0)) == 0) {
        !           653:                        error = ECONNREFUSED;
        !           654:                        goto bad;
        !           655:                }
        !           656:                unp2 = sotounpcb(so2);
        !           657:                unp3 = sotounpcb(so3);
        !           658:                if (unp2->unp_addr)
        !           659:                        unp3->unp_addr = (struct sockaddr_un *)
        !           660:                                dup_sockaddr((struct sockaddr *)
        !           661:                                             unp2->unp_addr, 1);
        !           662:                so2 = so3;
        !           663:        }
        !           664:        error = unp_connect2(so, so2);
        !           665: bad:
        !           666:        vput(vp);
        !           667:        return (error);
        !           668: }
        !           669: 
        !           670: int
        !           671: unp_connect2(so, so2)
        !           672:        register struct socket *so;
        !           673:        register struct socket *so2;
        !           674: {
        !           675:        register struct unpcb *unp = sotounpcb(so);
        !           676:        register struct unpcb *unp2;
        !           677: 
        !           678:        if (so2->so_type != so->so_type)
        !           679:                return (EPROTOTYPE);
        !           680:        unp2 = sotounpcb(so2);
        !           681:        unp->unp_conn = unp2;
        !           682:        switch (so->so_type) {
        !           683: 
        !           684:        case SOCK_DGRAM:
        !           685:                LIST_INSERT_HEAD(&unp2->unp_refs, unp, unp_reflink);
        !           686:                soisconnected(so);
        !           687:                break;
        !           688: 
        !           689:        case SOCK_STREAM:
        !           690:                unp2->unp_conn = unp;
        !           691:                soisconnected(so);
        !           692:                soisconnected(so2);
        !           693:                break;
        !           694: 
        !           695:        default:
        !           696:                panic("unp_connect2");
        !           697:        }
        !           698:        return (0);
        !           699: }
        !           700: 
        !           701: static void
        !           702: unp_disconnect(unp)
        !           703:        struct unpcb *unp;
        !           704: {
        !           705:        register struct unpcb *unp2 = unp->unp_conn;
        !           706: 
        !           707:        if (unp2 == 0)
        !           708:                return;
        !           709:        unp->unp_conn = 0;
        !           710:        switch (unp->unp_socket->so_type) {
        !           711: 
        !           712:        case SOCK_DGRAM:
        !           713:                LIST_REMOVE(unp, unp_reflink);
        !           714:                unp->unp_socket->so_state &= ~SS_ISCONNECTED;
        !           715:                break;
        !           716: 
        !           717:        case SOCK_STREAM:
        !           718:                soisdisconnected(unp->unp_socket);
        !           719:                unp2->unp_conn = 0;
        !           720:                soisdisconnected(unp2->unp_socket);
        !           721:                break;
        !           722:        }
        !           723: }
        !           724: 
        !           725: #ifdef notdef
        !           726: void
        !           727: unp_abort(unp)
        !           728:        struct unpcb *unp;
        !           729: {
        !           730: 
        !           731:        unp_detach(unp);
        !           732: }
        !           733: #endif
        !           734: 
        !           735: static int
        !           736: unp_pcblist SYSCTL_HANDLER_ARGS
        !           737: {
        !           738:        int error, i, n;
        !           739:        struct unpcb *unp, **unp_list;
        !           740:        unp_gen_t gencnt;
        !           741:        struct xunpgen xug;
        !           742:        struct unp_head *head;
        !           743: 
        !           744:        head = ((intptr_t)arg1 == SOCK_DGRAM ? &unp_dhead : &unp_shead);
        !           745: 
        !           746:        /*
        !           747:         * The process of preparing the PCB list is too time-consuming and
        !           748:         * resource-intensive to repeat twice on every request.
        !           749:         */
        !           750:        if (req->oldptr == 0) {
        !           751:                n = unp_count;
        !           752:                req->oldidx = 2 * (sizeof xug)
        !           753:                        + (n + n/8) * sizeof(struct xunpcb);
        !           754:                return 0;
        !           755:        }
        !           756: 
        !           757:        if (req->newptr != 0)
        !           758:                return EPERM;
        !           759: 
        !           760:        /*
        !           761:         * OK, now we're committed to doing something.
        !           762:         */
        !           763:        gencnt = unp_gencnt;
        !           764:        n = unp_count;
        !           765: 
        !           766:        xug.xug_len = sizeof xug;
        !           767:        xug.xug_count = n;
        !           768:        xug.xug_gen = gencnt;
        !           769:        xug.xug_sogen = so_gencnt;
        !           770:        error = SYSCTL_OUT(req, &xug, sizeof xug);
        !           771:        if (error)
        !           772:                return error;
        !           773: 
        !           774:        unp_list = _MALLOC(n * sizeof *unp_list, M_TEMP, M_WAITOK);
        !           775:        if (unp_list == 0)
        !           776:                return ENOMEM;
        !           777:        
        !           778:        for (unp = head->lh_first, i = 0; unp && i < n;
        !           779:             unp = unp->unp_link.le_next) {
        !           780:                if (unp->unp_gencnt <= gencnt)
        !           781:                        unp_list[i++] = unp;
        !           782:        }
        !           783:        n = i;                  /* in case we lost some during malloc */
        !           784: 
        !           785:        error = 0;
        !           786:        for (i = 0; i < n; i++) {
        !           787:                unp = unp_list[i];
        !           788:                if (unp->unp_gencnt <= gencnt) {
        !           789:                        struct xunpcb xu;
        !           790:                        xu.xu_len = sizeof xu;
        !           791:                        xu.xu_unpp = unp;
        !           792:                        /*
        !           793:                         * XXX - need more locking here to protect against
        !           794:                         * connect/disconnect races for SMP.
        !           795:                         */
        !           796:                        if (unp->unp_addr)
        !           797:                                bcopy(unp->unp_addr, &xu.xu_addr, 
        !           798:                                      unp->unp_addr->sun_len);
        !           799:                        if (unp->unp_conn && unp->unp_conn->unp_addr)
        !           800:                                bcopy(unp->unp_conn->unp_addr,
        !           801:                                      &xu.xu_caddr,
        !           802:                                      unp->unp_conn->unp_addr->sun_len);
        !           803:                        bcopy(unp, &xu.xu_unp, sizeof *unp);
        !           804:                        sotoxsocket(unp->unp_socket, &xu.xu_socket);
        !           805:                        error = SYSCTL_OUT(req, &xu, sizeof xu);
        !           806:                }
        !           807:        }
        !           808:        if (!error) {
        !           809:                /*
        !           810:                 * Give the user an updated idea of our state.
        !           811:                 * If the generation differs from what we told
        !           812:                 * her before, she knows that something happened
        !           813:                 * while we were processing this request, and it
        !           814:                 * might be necessary to retry.
        !           815:                 */
        !           816:                xug.xug_gen = unp_gencnt;
        !           817:                xug.xug_sogen = so_gencnt;
        !           818:                xug.xug_count = unp_count;
        !           819:                error = SYSCTL_OUT(req, &xug, sizeof xug);
        !           820:        }
        !           821:        FREE(unp_list, M_TEMP);
        !           822:        return error;
        !           823: }
        !           824: 
        !           825: SYSCTL_PROC(_net_local_dgram, OID_AUTO, pcblist, CTLFLAG_RD, 
        !           826:            (caddr_t)(long)SOCK_DGRAM, 0, unp_pcblist, "S,xunpcb",
        !           827:            "List of active local datagram sockets");
        !           828: SYSCTL_PROC(_net_local_stream, OID_AUTO, pcblist, CTLFLAG_RD, 
        !           829:            (caddr_t)(long)SOCK_STREAM, 0, unp_pcblist, "S,xunpcb",
        !           830:            "List of active local stream sockets");
        !           831: 
        !           832: static void
        !           833: unp_shutdown(unp)
        !           834:        struct unpcb *unp;
        !           835: {
        !           836:        struct socket *so;
        !           837: 
        !           838:        if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn &&
        !           839:            (so = unp->unp_conn->unp_socket))
        !           840:                socantrcvmore(so);
        !           841: }
        !           842: 
        !           843: static void
        !           844: unp_drop(unp, errno)
        !           845:        struct unpcb *unp;
        !           846:        int errno;
        !           847: {
        !           848:        struct socket *so = unp->unp_socket;
        !           849: 
        !           850:        so->so_error = errno;
        !           851:        unp_disconnect(unp);
        !           852:        if (so->so_head) {
        !           853:                LIST_REMOVE(unp, unp_link);
        !           854:                unp->unp_gencnt = ++unp_gencnt;
        !           855:                unp_count--;
        !           856:                so->so_pcb = (caddr_t) 0;
        !           857:                if (unp->unp_addr)
        !           858:                        FREE(unp->unp_addr, M_SONAME);
        !           859:                zfree(unp_zone, unp);
        !           860:                sofree(so);
        !           861:        }
        !           862: }
        !           863: 
        !           864: #ifdef notdef
        !           865: void
        !           866: unp_drain()
        !           867: {
        !           868: 
        !           869: }
        !           870: #endif
        !           871: 
        !           872: int
        !           873: unp_externalize(rights)
        !           874:        struct mbuf *rights;
        !           875: {
        !           876:        struct proc *p = current_proc();                /* XXX */
        !           877:        register int i;
        !           878:        register struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
        !           879:        register struct file **rp = (struct file **)(cm + 1);
        !           880:        register struct file *fp;
        !           881:        int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int);
        !           882:        int f;
        !           883: 
        !           884:        /*
        !           885:         * if the new FD's will not fit, then we free them all
        !           886:         */
        !           887:        if (!fdavail(p, newfds)) {
        !           888:                for (i = 0; i < newfds; i++) {
        !           889:                        fp = *rp;
        !           890:                        unp_discard(fp);
        !           891:                        *rp++ = 0;
        !           892:                }
        !           893:                return (EMSGSIZE);
        !           894:        }
        !           895:        /*
        !           896:         * now change each pointer to an fd in the global table to 
        !           897:         * an integer that is the index to the local fd table entry
        !           898:         * that we set up to point to the global one we are transferring.
        !           899:         * XXX this assumes a pointer and int are the same size...!
        !           900:         */
        !           901:        for (i = 0; i < newfds; i++) {
        !           902:                if (fdalloc(p, 0, &f))
        !           903:                        panic("unp_externalize");
        !           904:                fp = *rp;
        !           905:                p->p_fd->fd_ofiles[f] = fp;
        !           906:                fp->f_msgcount--;
        !           907:                unp_rights--;
        !           908:                *(int *)rp++ = f;
        !           909:        }
        !           910:        return (0);
        !           911: }
        !           912: 
        !           913: void
        !           914: unp_init(void)
        !           915: {
        !           916:        unp_zone = zinit(sizeof(struct unpcb), 
        !           917:                         (nmbclusters * sizeof(struct unpcb)), 
        !           918:                          4096, "unpzone");
        !           919:        if (unp_zone == 0)
        !           920:                panic("unp_init");
        !           921:        LIST_INIT(&unp_dhead);
        !           922:        LIST_INIT(&unp_shead);
        !           923: }
        !           924: 
        !           925: #ifndef MIN
        !           926: #define        MIN(a,b) (((a)<(b))?(a):(b))
        !           927: #endif
        !           928: 
        !           929: static int
        !           930: unp_internalize(control, p)
        !           931:        struct mbuf *control;
        !           932:        struct proc *p;
        !           933: {
        !           934:        register struct cmsghdr *cm = mtod(control, struct cmsghdr *);
        !           935:        register struct file **rp;
        !           936:        struct file *fp;
        !           937:        register int i, error;
        !           938:        int oldfds;
        !           939: 
        !           940:        if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
        !           941:            cm->cmsg_len != control->m_len)
        !           942:                return (EINVAL);
        !           943:        oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);
        !           944:        rp = (struct file **)(cm + 1);
        !           945:        for (i = 0; i < oldfds; i++)
        !           946:                if (error = fdgetf(p, *(int *)rp++, 0))
        !           947:                        return (error);
        !           948:        rp = (struct file **)(cm + 1);
        !           949:        for (i = 0; i < oldfds; i++) {
        !           950:                (void) fdgetf(p, *(int *)rp, &fp);
        !           951:                *rp++ = fp;
        !           952:                fp->f_count++;
        !           953:                if (fp->f_count <= 0)
        !           954:                        panic("unp_internalize f_count");
        !           955:                fp->f_msgcount++;
        !           956:                unp_rights++;
        !           957:        }
        !           958:        return (0);
        !           959: }
        !           960: 
        !           961: static int     unp_defer, unp_gcing;
        !           962: 
        !           963: static void
        !           964: unp_gc()
        !           965: {
        !           966:        register struct file *fp, *nextfp;
        !           967:        register struct socket *so;
        !           968:        struct file **extra_ref, **fpp;
        !           969:        int nunref, i;
        !           970: 
        !           971:        if (unp_gcing)
        !           972:                return;
        !           973:        unp_gcing = 1;
        !           974:        unp_defer = 0;
        !           975:        /* 
        !           976:         * before going through all this, set all FDs to 
        !           977:         * be NOT defered and NOT externally accessible
        !           978:         */
        !           979:        for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next)
        !           980:                fp->f_flag &= ~(FMARK|FDEFER);
        !           981:        do {
        !           982:                for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) {
        !           983:                        /*
        !           984:                         * If the file is not open, skip it
        !           985:                         */
        !           986:                        if (fp->f_count == 0)
        !           987:                                continue;
        !           988:                        /*
        !           989:                         * If we already marked it as 'defer'  in a
        !           990:                         * previous pass, then try process it this time
        !           991:                         * and un-mark it
        !           992:                         */
        !           993:                        if (fp->f_flag & FDEFER) {
        !           994:                                fp->f_flag &= ~FDEFER;
        !           995:                                unp_defer--;
        !           996:                        } else {
        !           997:                                /*
        !           998:                                 * if it's not defered, then check if it's
        !           999:                                 * already marked.. if so skip it
        !          1000:                                 */
        !          1001:                                if (fp->f_flag & FMARK)
        !          1002:                                        continue;
        !          1003:                                /* 
        !          1004:                                 * If all references are from messages
        !          1005:                                 * in transit, then skip it. it's not 
        !          1006:                                 * externally accessible.
        !          1007:                                 */ 
        !          1008:                                if (fp->f_count == fp->f_msgcount)
        !          1009:                                        continue;
        !          1010:                                /* 
        !          1011:                                 * If it got this far then it must be
        !          1012:                                 * externally accessible.
        !          1013:                                 */
        !          1014:                                fp->f_flag |= FMARK;
        !          1015:                        }
        !          1016:                        /*
        !          1017:                         * either it was defered, or it is externally 
        !          1018:                         * accessible and not already marked so.
        !          1019:                         * Now check if it is possibly one of OUR sockets.
        !          1020:                         */ 
        !          1021:                        if (fp->f_type != DTYPE_SOCKET ||
        !          1022:                            (so = (struct socket *)fp->f_data) == 0)
        !          1023:                                continue;
        !          1024:                        if (so->so_proto->pr_domain != &localdomain ||
        !          1025:                            (so->so_proto->pr_flags&PR_RIGHTS) == 0)
        !          1026:                                continue;
        !          1027: #ifdef notdef
        !          1028:                        if (so->so_rcv.sb_flags & SB_LOCK) {
        !          1029:                                /*
        !          1030:                                 * This is problematical; it's not clear
        !          1031:                                 * we need to wait for the sockbuf to be
        !          1032:                                 * unlocked (on a uniprocessor, at least),
        !          1033:                                 * and it's also not clear what to do
        !          1034:                                 * if sbwait returns an error due to receipt
        !          1035:                                 * of a signal.  If sbwait does return
        !          1036:                                 * an error, we'll go into an infinite
        !          1037:                                 * loop.  Delete all of this for now.
        !          1038:                                 */
        !          1039:                                (void) sbwait(&so->so_rcv);
        !          1040:                                goto restart;
        !          1041:                        }
        !          1042: #endif
        !          1043:                        /*
        !          1044:                         * So, Ok, it's one of our sockets and it IS externally
        !          1045:                         * accessible (or was defered). Now we look
        !          1046:                         * to see if we hold any file descriptors in its
        !          1047:                         * message buffers. Follow those links and mark them 
        !          1048:                         * as accessible too.
        !          1049:                         */
        !          1050:                        unp_scan(so->so_rcv.sb_mb, unp_mark);
        !          1051:                }
        !          1052:        } while (unp_defer);
        !          1053:        /*
        !          1054:         * We grab an extra reference to each of the file table entries
        !          1055:         * that are not otherwise accessible and then free the rights
        !          1056:         * that are stored in messages on them.
        !          1057:         *
        !          1058:         * The bug in the orginal code is a little tricky, so I'll describe
        !          1059:         * what's wrong with it here.
        !          1060:         *
        !          1061:         * It is incorrect to simply unp_discard each entry for f_msgcount
        !          1062:         * times -- consider the case of sockets A and B that contain
        !          1063:         * references to each other.  On a last close of some other socket,
        !          1064:         * we trigger a gc since the number of outstanding rights (unp_rights)
        !          1065:         * is non-zero.  If during the sweep phase the gc code un_discards,
        !          1066:         * we end up doing a (full) closef on the descriptor.  A closef on A
        !          1067:         * results in the following chain.  Closef calls soo_close, which
        !          1068:         * calls soclose.   Soclose calls first (through the switch
        !          1069:         * uipc_usrreq) unp_detach, which re-invokes unp_gc.  Unp_gc simply
        !          1070:         * returns because the previous instance had set unp_gcing, and
        !          1071:         * we return all the way back to soclose, which marks the socket
        !          1072:         * with SS_NOFDREF, and then calls sofree.  Sofree calls sorflush
        !          1073:         * to free up the rights that are queued in messages on the socket A,
        !          1074:         * i.e., the reference on B.  The sorflush calls via the dom_dispose
        !          1075:         * switch unp_dispose, which unp_scans with unp_discard.  This second
        !          1076:         * instance of unp_discard just calls closef on B.
        !          1077:         *
        !          1078:         * Well, a similar chain occurs on B, resulting in a sorflush on B,
        !          1079:         * which results in another closef on A.  Unfortunately, A is already
        !          1080:         * being closed, and the descriptor has already been marked with
        !          1081:         * SS_NOFDREF, and soclose panics at this point.
        !          1082:         *
        !          1083:         * Here, we first take an extra reference to each inaccessible
        !          1084:         * descriptor.  Then, we call sorflush ourself, since we know
        !          1085:         * it is a Unix domain socket anyhow.  After we destroy all the
        !          1086:         * rights carried in messages, we do a last closef to get rid
        !          1087:         * of our extra reference.  This is the last close, and the
        !          1088:         * unp_detach etc will shut down the socket.
        !          1089:         *
        !          1090:         * 91/09/19, [email protected]
        !          1091:         */
        !          1092:        extra_ref = _MALLOC(nfiles * sizeof(struct file *), M_FILE, M_WAITOK);
        !          1093:        for (nunref = 0, fp = filehead.lh_first, fpp = extra_ref; fp != 0;
        !          1094:            fp = nextfp) {
        !          1095:                nextfp = fp->f_list.le_next;
        !          1096:                /* 
        !          1097:                 * If it's not open, skip it
        !          1098:                 */
        !          1099:                if (fp->f_count == 0)
        !          1100:                        continue;
        !          1101:                /* 
        !          1102:                 * If all refs are from msgs, and it's not marked accessible
        !          1103:                 * then it must be referenced from some unreachable cycle
        !          1104:                 * of (shut-down) FDs, so include it in our
        !          1105:                 * list of FDs to remove
        !          1106:                 */
        !          1107:                if (fp->f_count == fp->f_msgcount && !(fp->f_flag & FMARK)) {
        !          1108:                        *fpp++ = fp;
        !          1109:                        nunref++;
        !          1110:                        fp->f_count++;
        !          1111:                        if (fp->f_count <= 0)
        !          1112:                                panic("unp_gc f_count");
        !          1113:                }
        !          1114:        }
        !          1115:        /* 
        !          1116:         * for each FD on our hit list, do the following two things
        !          1117:         */
        !          1118:        for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) {
        !          1119:                struct file *tfp = *fpp;
        !          1120:                if (tfp->f_type == DTYPE_SOCKET && tfp->f_data != NULL)
        !          1121:                        sorflush((struct socket *)(tfp->f_data));
        !          1122:        }
        !          1123: 
        !          1124: 
        !          1125:        for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)
        !          1126:                closef(*fpp, (struct proc *) NULL);
        !          1127:        FREE((caddr_t)extra_ref, M_FILE);
        !          1128:        unp_gcing = 0;
        !          1129: }
        !          1130: 
        !          1131: void
        !          1132: unp_dispose(m)
        !          1133:        struct mbuf *m;
        !          1134: {
        !          1135: 
        !          1136:        if (m)
        !          1137:                unp_scan(m, unp_discard);
        !          1138: }
        !          1139: 
        !          1140: static void
        !          1141: unp_scan(m0, op)
        !          1142:        register struct mbuf *m0;
        !          1143:        void (*op) __P((struct file *));
        !          1144: {
        !          1145:        register struct mbuf *m;
        !          1146:        register struct file **rp;
        !          1147:        register struct cmsghdr *cm;
        !          1148:        register int i;
        !          1149:        int qfds;
        !          1150: 
        !          1151:        while (m0) {
        !          1152:                for (m = m0; m; m = m->m_next)
        !          1153:                        if (m->m_type == MT_CONTROL &&
        !          1154:                            m->m_len >= sizeof(*cm)) {
        !          1155:                                cm = mtod(m, struct cmsghdr *);
        !          1156:                                if (cm->cmsg_level != SOL_SOCKET ||
        !          1157:                                    cm->cmsg_type != SCM_RIGHTS)
        !          1158:                                        continue;
        !          1159:                                qfds = (cm->cmsg_len - sizeof *cm)
        !          1160:                                                / sizeof (struct file *);
        !          1161:                                rp = (struct file **)(cm + 1);
        !          1162:                                for (i = 0; i < qfds; i++)
        !          1163:                                        (*op)(*rp++);
        !          1164:                                break;          /* XXX, but saves time */
        !          1165:                        }
        !          1166:                m0 = m0->m_act;
        !          1167:        }
        !          1168: }
        !          1169: 
        !          1170: static void
        !          1171: unp_mark(fp)
        !          1172:        struct file *fp;
        !          1173: {
        !          1174: 
        !          1175:        if (fp->f_flag & FMARK)
        !          1176:                return;
        !          1177:        unp_defer++;
        !          1178:        fp->f_flag |= (FMARK|FDEFER);
        !          1179: }
        !          1180: 
        !          1181: static void
        !          1182: unp_discard(fp)
        !          1183:        struct file *fp;
        !          1184: {
        !          1185: 
        !          1186:        fp->f_msgcount--;
        !          1187:        unp_rights--;
        !          1188:        (void) closef(fp, (struct proc *)NULL);
        !          1189: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.