|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.