|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
26: /*
27: * Copyright (c) 1982, 1986, 1989, 1991, 1993
28: * The Regents of the University of California. All rights reserved.
29: *
30: * Redistribution and use in source and binary forms, with or without
31: * modification, are permitted provided that the following conditions
32: * are met:
33: * 1. Redistributions of source code must retain the above copyright
34: * notice, this list of conditions and the following disclaimer.
35: * 2. Redistributions in binary form must reproduce the above copyright
36: * notice, this list of conditions and the following disclaimer in the
37: * documentation and/or other materials provided with the distribution.
38: * 3. All advertising materials mentioning features or use of this software
39: * must display the following acknowledgement:
40: * This product includes software developed by the University of
41: * California, Berkeley and its contributors.
42: * 4. Neither the name of the University nor the names of its contributors
43: * may be used to endorse or promote products derived from this software
44: * without specific prior written permission.
45: *
46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56: * SUCH DAMAGE.
57: *
58: * @(#)uipc_usrreq.c 8.9 (Berkeley) 5/14/95
59: */
60:
61: #include <sys/param.h>
62: #include <sys/systm.h>
63: #include <sys/proc.h>
64: #include <sys/filedesc.h>
65: #include <sys/domain.h>
66: #include <sys/protosw.h>
67: #include <sys/socket.h>
68: #include <sys/socketvar.h>
69: #include <sys/unpcb.h>
70: #include <sys/un.h>
71: #include <sys/namei.h>
72: #include <sys/vnode.h>
73: #include <sys/file.h>
74: #include <sys/stat.h>
75: #include <sys/mbuf.h>
76: #include <sys/malloc.h>
77:
78: /*
79: * Unix communications domain.
80: *
81: * TODO:
82: * SEQPACKET, RDM
83: * rethink name space problems
84: * need a proper out-of-band
85: */
86: struct sockaddr sun_noname = { sizeof(sun_noname), AF_UNIX };
87: ino_t unp_ino; /* prototype for fake inode numbers */
88:
89: /*ARGSUSED*/
90: int
91: uipc_usrreq(so, req, m, nam, control)
92: struct socket *so;
93: int req;
94: struct mbuf *m, *nam, *control;
95: {
96: struct unpcb *unp = sotounpcb(so);
97: register struct socket *so2;
98: register int error = 0;
99: struct proc *p = current_proc(); /* XXX */
100:
101: if (req == PRU_CONTROL)
102: return (EOPNOTSUPP);
103: if (req != PRU_SEND && control && control->m_len) {
104: error = EOPNOTSUPP;
105: goto release;
106: }
107: if (unp == 0 && req != PRU_ATTACH) {
108: error = EINVAL;
109: goto release;
110: }
111: switch (req) {
112:
113: case PRU_ATTACH:
114: if (unp) {
115: error = EISCONN;
116: break;
117: }
118: error = unp_attach(so);
119: break;
120:
121: case PRU_DETACH:
122: unp_detach(unp);
123: break;
124:
125: case PRU_BIND:
126: error = unp_bind(unp, nam, p);
127: break;
128:
129: case PRU_LISTEN:
130: if (unp->unp_vnode == 0)
131: error = EINVAL;
132: break;
133:
134: case PRU_CONNECT:
135: error = unp_connect(so, nam, p);
136: break;
137:
138: case PRU_CONNECT2:
139: error = unp_connect2(so, (struct socket *)nam);
140: break;
141:
142: case PRU_DISCONNECT:
143: unp_disconnect(unp);
144: break;
145:
146: case PRU_ACCEPT:
147: /*
148: * Pass back name of connected socket,
149: * if it was bound and we are still connected
150: * (our peer may have closed already!).
151: */
152: if (unp->unp_conn && unp->unp_conn->unp_addr) {
153: nam->m_len = unp->unp_conn->unp_addr->m_len;
154: bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
155: mtod(nam, caddr_t), (unsigned)nam->m_len);
156: } else {
157: nam->m_len = sizeof(sun_noname);
158: *(mtod(nam, struct sockaddr *)) = sun_noname;
159: }
160: break;
161:
162: case PRU_SHUTDOWN:
163: socantsendmore(so);
164: unp_shutdown(unp);
165: break;
166:
167: case PRU_RCVD:
168: switch (so->so_type) {
169:
170: case SOCK_DGRAM:
171: panic("uipc 1");
172: /*NOTREACHED*/
173:
174: case SOCK_STREAM:
175: #define rcv (&so->so_rcv)
176: #define snd (&so2->so_snd)
177: if (unp->unp_conn == 0)
178: break;
179: so2 = unp->unp_conn->unp_socket;
180: /*
181: * Adjust backpressure on sender
182: * and wakeup any waiting to write.
183: */
184: snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;
185: unp->unp_mbcnt = rcv->sb_mbcnt;
186: snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;
187: unp->unp_cc = rcv->sb_cc;
188: sowwakeup(so2);
189: #undef snd
190: #undef rcv
191: break;
192:
193: default:
194: panic("uipc 2");
195: }
196: break;
197:
198: case PRU_SEND:
199: if (control && (error = unp_internalize(control, p)))
200: break;
201: switch (so->so_type) {
202:
203: case SOCK_DGRAM: {
204: struct sockaddr *from;
205:
206: if (nam) {
207: if (unp->unp_conn) {
208: error = EISCONN;
209: break;
210: }
211: error = unp_connect(so, nam, p);
212: if (error)
213: break;
214: } else {
215: if (unp->unp_conn == 0) {
216: error = ENOTCONN;
217: break;
218: }
219: }
220: so2 = unp->unp_conn->unp_socket;
221: if (unp->unp_addr)
222: from = mtod(unp->unp_addr, struct sockaddr *);
223: else
224: from = &sun_noname;
225: if (sbappendaddr(&so2->so_rcv, from, m, control)) {
226: sorwakeup(so2);
227: m = 0;
228: control = 0;
229: } else
230: error = ENOBUFS;
231: if (nam)
232: unp_disconnect(unp);
233: break;
234: }
235:
236: case SOCK_STREAM:
237: #define rcv (&so2->so_rcv)
238: #define snd (&so->so_snd)
239: if (so->so_state & SS_CANTSENDMORE) {
240: error = EPIPE;
241: break;
242: }
243: if (unp->unp_conn == 0)
244: panic("uipc 3");
245: so2 = unp->unp_conn->unp_socket;
246: /*
247: * Send to paired receive port, and then reduce
248: * send buffer hiwater marks to maintain backpressure.
249: * Wake up readers.
250: */
251: if (control) {
252: if (sbappendcontrol(rcv, m, control))
253: control = 0;
254: } else
255: sbappend(rcv, m);
256: snd->sb_mbmax -=
257: rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;
258: unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;
259: snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;
260: unp->unp_conn->unp_cc = rcv->sb_cc;
261: sorwakeup(so2);
262: m = 0;
263: #undef snd
264: #undef rcv
265: break;
266:
267: default:
268: panic("uipc 4");
269: }
270: break;
271:
272: case PRU_ABORT:
273: unp_drop(unp, ECONNABORTED);
274: break;
275:
276: case PRU_SENSE:
277: ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
278: if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
279: so2 = unp->unp_conn->unp_socket;
280: ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
281: }
282: ((struct stat *) m)->st_dev = NODEV;
283: if (unp->unp_ino == 0)
284: unp->unp_ino = unp_ino++;
285: ((struct stat *) m)->st_ino = unp->unp_ino;
286: return (0);
287:
288: case PRU_RCVOOB:
289: return (EOPNOTSUPP);
290:
291: case PRU_SENDOOB:
292: error = EOPNOTSUPP;
293: break;
294:
295: case PRU_SOCKADDR:
296: if (unp->unp_addr) {
297: nam->m_len = unp->unp_addr->m_len;
298: bcopy(mtod(unp->unp_addr, caddr_t),
299: mtod(nam, caddr_t), (unsigned)nam->m_len);
300: } else
301: nam->m_len = 0;
302: break;
303:
304: case PRU_PEERADDR:
305: if (unp->unp_conn && unp->unp_conn->unp_addr) {
306: nam->m_len = unp->unp_conn->unp_addr->m_len;
307: bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
308: mtod(nam, caddr_t), (unsigned)nam->m_len);
309: } else
310: nam->m_len = 0;
311: break;
312:
313: case PRU_SLOWTIMO:
314: break;
315:
316: default:
317: panic("piusrreq");
318: }
319: release:
320: if (control)
321: m_freem(control);
322: if (m)
323: m_freem(m);
324: return (error);
325: }
326:
327: /*
328: * Both send and receive buffers are allocated PIPSIZ bytes of buffering
329: * for stream sockets, although the total for sender and receiver is
330: * actually only PIPSIZ.
331: * Datagram sockets really use the sendspace as the maximum datagram size,
332: * and don't really want to reserve the sendspace. Their recvspace should
333: * be large enough for at least one max-size datagram plus address.
334: */
335: #define PIPSIZ 4096
336: u_long unpst_sendspace = PIPSIZ;
337: u_long unpst_recvspace = PIPSIZ;
338: u_long unpdg_sendspace = 2*1024; /* really max datagram size */
339: u_long unpdg_recvspace = 4*1024;
340:
341: int unp_rights; /* file descriptors in flight */
342:
343: int
344: unp_attach(so)
345: struct socket *so;
346: {
347: register struct mbuf *m;
348: register struct unpcb *unp;
349: int error;
350:
351: if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
352: switch (so->so_type) {
353:
354: case SOCK_STREAM:
355: error = soreserve(so, unpst_sendspace, unpst_recvspace);
356: break;
357:
358: case SOCK_DGRAM:
359: error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
360: break;
361:
362: default:
363: panic("unp_attach");
364: }
365: if (error)
366: return (error);
367: }
368: m = m_getclr(M_DONTWAIT, MT_PCB);
369: if (m == NULL)
370: return (ENOBUFS);
371: unp = mtod(m, struct unpcb *);
372: so->so_pcb = (caddr_t)unp;
373: unp->unp_socket = so;
374: return (0);
375: }
376:
377: int
378: unp_detach(unp)
379: register struct unpcb *unp;
380: {
381:
382: if (unp->unp_vnode) {
383: unp->unp_vnode->v_socket = 0;
384: vrele(unp->unp_vnode);
385: unp->unp_vnode = 0;
386: }
387: if (unp->unp_conn)
388: unp_disconnect(unp);
389: while (unp->unp_refs)
390: unp_drop(unp->unp_refs, ECONNRESET);
391: soisdisconnected(unp->unp_socket);
392: unp->unp_socket->so_pcb = 0;
393: m_freem(unp->unp_addr);
394: (void) m_free(dtom(unp));
395: if (unp_rights) {
396: /*
397: * Normally the receive buffer is flushed later,
398: * in sofree, but if our receive buffer holds references
399: * to descriptors that are now garbage, we will dispose
400: * of those descriptor references after the garbage collector
401: * gets them (resulting in a "panic: closef: count < 0").
402: */
403: sorflush(unp->unp_socket);
404: unp_gc();
405: }
406: }
407:
408: int
409: unp_bind(unp, nam, p)
410: struct unpcb *unp;
411: struct mbuf *nam;
412: struct proc *p;
413: {
414: struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
415: register struct vnode *vp;
416: struct vattr vattr;
417: int error;
418: struct nameidata nd;
419:
420: NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_SYSSPACE,
421: soun->sun_path, p);
422: if (unp->unp_vnode != NULL)
423: return (EINVAL);
424: if (nam->m_len == MLEN) {
425: if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
426: return (EINVAL);
427: } else
428: *(mtod(nam, caddr_t) + nam->m_len) = 0;
429: /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
430: if (error = namei(&nd))
431: return (error);
432: vp = nd.ni_vp;
433: if (vp != NULL) {
434: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
435: if (nd.ni_dvp == vp)
436: vrele(nd.ni_dvp);
437: else
438: vput(nd.ni_dvp);
439: vrele(vp);
440: return (EADDRINUSE);
441: }
442: VATTR_NULL(&vattr);
443: vattr.va_type = VSOCK;
444: vattr.va_mode = ACCESSPERMS;
445: VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
446: if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr))
447: return (error);
448: vp = nd.ni_vp;
449: vp->v_socket = unp->unp_socket;
450: unp->unp_vnode = vp;
451: unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);
452: VOP_UNLOCK(vp, 0, p);
453: return (0);
454: }
455:
456: int
457: unp_connect(so, nam, p)
458: struct socket *so;
459: struct mbuf *nam;
460: struct proc *p;
461: {
462: register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
463: register struct vnode *vp;
464: register struct socket *so2, *so3;
465: struct unpcb *unp2, *unp3;
466: int error;
467: struct nameidata nd;
468:
469: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, soun->sun_path, p);
470: if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) { /* XXX */
471: if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
472: return (EMSGSIZE);
473: } else
474: *(mtod(nam, caddr_t) + nam->m_len) = 0;
475: if (error = namei(&nd))
476: return (error);
477: vp = nd.ni_vp;
478: if (vp->v_type != VSOCK) {
479: error = ENOTSOCK;
480: goto bad;
481: }
482: if (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))
483: goto bad;
484: so2 = vp->v_socket;
485: if (so2 == 0) {
486: error = ECONNREFUSED;
487: goto bad;
488: }
489: if (so->so_type != so2->so_type) {
490: error = EPROTOTYPE;
491: goto bad;
492: }
493: if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
494: if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
495: (so3 = sonewconn(so2, 0)) == 0) {
496: error = ECONNREFUSED;
497: goto bad;
498: }
499: unp2 = sotounpcb(so2);
500: unp3 = sotounpcb(so3);
501: if (unp2->unp_addr)
502: unp3->unp_addr =
503: m_copy(unp2->unp_addr, 0, (int)M_COPYALL);
504: so2 = so3;
505: }
506: error = unp_connect2(so, so2);
507: bad:
508: vput(vp);
509: return (error);
510: }
511:
512: int
513: unp_connect2(so, so2)
514: register struct socket *so;
515: register struct socket *so2;
516: {
517: register struct unpcb *unp = sotounpcb(so);
518: register struct unpcb *unp2;
519:
520: if (so2->so_type != so->so_type)
521: return (EPROTOTYPE);
522: unp2 = sotounpcb(so2);
523: unp->unp_conn = unp2;
524: switch (so->so_type) {
525:
526: case SOCK_DGRAM:
527: unp->unp_nextref = unp2->unp_refs;
528: unp2->unp_refs = unp;
529: soisconnected(so);
530: break;
531:
532: case SOCK_STREAM:
533: unp2->unp_conn = unp;
534: soisconnected(so);
535: soisconnected(so2);
536: break;
537:
538: default:
539: panic("unp_connect2");
540: }
541: return (0);
542: }
543:
544: void
545: unp_disconnect(unp)
546: struct unpcb *unp;
547: {
548: register struct unpcb *unp2 = unp->unp_conn;
549:
550: if (unp2 == 0)
551: return;
552: unp->unp_conn = 0;
553: switch (unp->unp_socket->so_type) {
554:
555: case SOCK_DGRAM:
556: if (unp2->unp_refs == unp)
557: unp2->unp_refs = unp->unp_nextref;
558: else {
559: unp2 = unp2->unp_refs;
560: for (;;) {
561: if (unp2 == 0)
562: panic("unp_disconnect");
563: if (unp2->unp_nextref == unp)
564: break;
565: unp2 = unp2->unp_nextref;
566: }
567: unp2->unp_nextref = unp->unp_nextref;
568: }
569: unp->unp_nextref = 0;
570: unp->unp_socket->so_state &= ~SS_ISCONNECTED;
571: break;
572:
573: case SOCK_STREAM:
574: soisdisconnected(unp->unp_socket);
575: unp2->unp_conn = 0;
576: soisdisconnected(unp2->unp_socket);
577: break;
578: }
579: }
580:
581: #ifdef notdef
582: unp_abort(unp)
583: struct unpcb *unp;
584: {
585:
586: unp_detach(unp);
587: }
588: #endif
589:
590: void
591: unp_shutdown(unp)
592: struct unpcb *unp;
593: {
594: struct socket *so;
595:
596: if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn &&
597: (so = unp->unp_conn->unp_socket))
598: socantrcvmore(so);
599: }
600:
601: void
602: unp_drop(unp, errno)
603: struct unpcb *unp;
604: int errno;
605: {
606: struct socket *so = unp->unp_socket;
607:
608: so->so_error = errno;
609: unp_disconnect(unp);
610: if (so->so_head) {
611: so->so_pcb = (caddr_t) 0;
612: m_freem(unp->unp_addr);
613: (void) m_free(dtom(unp));
614: sofree(so);
615: }
616: }
617:
618: #ifdef notdef
619: unp_drain()
620: {
621:
622: }
623: #endif
624:
625: int
626: unp_externalize(rights)
627: struct mbuf *rights;
628: {
629: struct proc *p = current_proc(); /* XXX */
630: register int i;
631: register struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
632: register struct file **rp = (struct file **)(cm + 1);
633: register struct file *fp;
634: int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int);
635: int f;
636:
637: if (!fdavail(p, newfds)) {
638: for (i = 0; i < newfds; i++) {
639: fp = *rp;
640: unp_discard(fp);
641: *rp++ = 0;
642: }
643: return (EMSGSIZE);
644: }
645: for (i = 0; i < newfds; i++) {
646: if (fdalloc(p, 0, &f))
647: panic("unp_externalize");
648: fp = *rp;
649: *fdfile(p, f) = fp;
650: *fdflags(p, f) &= ~UF_RESERVED;
651: fp->f_msgcount--;
652: unp_rights--;
653: *(int *)rp++ = f;
654: }
655: return (0);
656: }
657:
658: int
659: unp_internalize(control, p)
660: struct mbuf *control;
661: struct proc *p;
662: {
663: register struct cmsghdr *cm = mtod(control, struct cmsghdr *);
664: register struct file **rp;
665: struct file *fp;
666: register int i, error;
667: int oldfds;
668:
669: if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
670: cm->cmsg_len != control->m_len)
671: return (EINVAL);
672: oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);
673: rp = (struct file **)(cm + 1);
674: for (i = 0; i < oldfds; i++)
675: if (error = fdgetf(p, *(int *)rp++, 0))
676: return (error);
677: rp = (struct file **)(cm + 1);
678: for (i = 0; i < oldfds; i++) {
679: (void) fdgetf(p, *(int *)rp, &fp);
680: *rp++ = fp;
1.1.1.2 ! root 681: if (++fp->f_count <= 0)
! 682: panic("unp_internalize f_count");
! 683: /* The following line needs no overflow check
! 684: * as if f_msgcount overflows we already
! 685: * panic with the f_count overflow above */
1.1 root 686: fp->f_msgcount++;
687: unp_rights++;
688: }
689: return (0);
690: }
691:
692: int unp_defer, unp_gcing;
693: extern struct domain unixdomain;
694:
695: void
696: unp_gc()
697: {
698: register struct file *fp, *nextfp;
699: register struct socket *so;
700: struct file **extra_ref, **fpp;
701: int nextra_ref, nunref, i;
702:
703: if (unp_gcing)
704: return;
705: unp_gcing = 1;
706: unp_defer = 0;
707: for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next)
708: fp->f_flag &= ~(FMARK|FDEFER);
709: do {
710: for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) {
711: if (fp->f_count == 0)
712: continue;
713: if (fp->f_flag & FDEFER) {
714: fp->f_flag &= ~FDEFER;
715: unp_defer--;
716: } else {
717: if (fp->f_flag & FMARK)
718: continue;
719: if (fp->f_count == fp->f_msgcount)
720: continue;
721: fp->f_flag |= FMARK;
722: }
723: if (fp->f_type != DTYPE_SOCKET ||
724: (so = (struct socket *)fp->f_data) == 0)
725: continue;
726: if (so->so_proto->pr_domain != &unixdomain ||
727: (so->so_proto->pr_flags&PR_RIGHTS) == 0)
728: continue;
729: #ifdef notdef
730: if (so->so_rcv.sb_flags & SB_LOCK) {
731: /*
732: * This is problematical; it's not clear
733: * we need to wait for the sockbuf to be
734: * unlocked (on a uniprocessor, at least),
735: * and it's also not clear what to do
736: * if sbwait returns an error due to receipt
737: * of a signal. If sbwait does return
738: * an error, we'll go into an infinite
739: * loop. Delete all of this for now.
740: */
741: (void) sbwait(&so->so_rcv);
742: goto restart;
743: }
744: #endif
745: unp_scan(so->so_rcv.sb_mb, unp_mark);
746: }
747: } while (unp_defer);
748: /*
749: * We grab an extra reference to each of the file table entries
750: * that are not otherwise accessible and then free the rights
751: * that are stored in messages on them.
752: *
753: * The bug in the orginal code is a little tricky, so I'll describe
754: * what's wrong with it here.
755: *
756: * It is incorrect to simply unp_discard each entry for f_msgcount
757: * times -- consider the case of sockets A and B that contain
758: * references to each other. On a last close of some other socket,
759: * we trigger a gc since the number of outstanding rights (unp_rights)
760: * is non-zero. If during the sweep phase the gc code un_discards,
761: * we end up doing a (full) closef on the descriptor. A closef on A
762: * results in the following chain. Closef calls soo_close, which
763: * calls soclose. Soclose calls first (through the switch
764: * uipc_usrreq) unp_detach, which re-invokes unp_gc. Unp_gc simply
765: * returns because the previous instance had set unp_gcing, and
766: * we return all the way back to soclose, which marks the socket
767: * with SS_NOFDREF, and then calls sofree. Sofree calls sorflush
768: * to free up the rights that are queued in messages on the socket A,
769: * i.e., the reference on B. The sorflush calls via the dom_dispose
770: * switch unp_dispose, which unp_scans with unp_discard. This second
771: * instance of unp_discard just calls closef on B.
772: *
773: * Well, a similar chain occurs on B, resulting in a sorflush on B,
774: * which results in another closef on A. Unfortunately, A is already
775: * being closed, and the descriptor has already been marked with
776: * SS_NOFDREF, and soclose panics at this point.
777: *
778: * Here, we first take an extra reference to each inaccessible
779: * descriptor. Then, we call sorflush ourself, since we know
780: * it is a Unix domain socket anyhow. After we destroy all the
781: * rights carried in messages, we do a last closef to get rid
782: * of our extra reference. This is the last close, and the
783: * unp_detach etc will shut down the socket.
784: *
785: * 91/09/19, [email protected]
786: */
787: nextra_ref = nfiles;
788: extra_ref = _MALLOC_ZONE(nextra_ref * sizeof(struct file *),
789: M_FILE, M_WAITOK);
790: for (nunref = 0, fp = filehead.lh_first, fpp = extra_ref; fp != 0;
791: fp = nextfp) {
792: nextfp = fp->f_list.le_next;
793: if (fp->f_count == 0)
794: continue;
795: if (fp->f_count == fp->f_msgcount && !(fp->f_flag & FMARK)) {
796: *fpp++ = fp;
797: nunref++;
1.1.1.2 ! root 798: if (++fp->f_count <= 0)
! 799: panic("unp_gc f_count");
1.1 root 800: }
801: }
802: for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)
803: sorflush((struct socket *)(*fpp)->f_data);
804: for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)
805: (void) closef(*fpp, (struct proc *)0);
806: _FREE_ZONE((caddr_t)extra_ref,
807: nextra_ref * sizeof(struct file *), M_FILE);
808: unp_gcing = 0;
809: }
810:
811: void
812: unp_dispose(m)
813: struct mbuf *m;
814: {
815:
816: if (m)
817: unp_scan(m, unp_discard);
818: }
819:
820: void
821: unp_scan(m0, op)
822: register struct mbuf *m0;
823: void (*op) __P((struct file *));
824: {
825: register struct mbuf *m;
826: register struct file **rp;
827: register struct cmsghdr *cm;
828: register int i;
829: int qfds;
830:
831: while (m0) {
832: for (m = m0; m; m = m->m_next)
833: if (m->m_type == MT_CONTROL &&
834: m->m_len >= sizeof(*cm)) {
835: cm = mtod(m, struct cmsghdr *);
836: if (cm->cmsg_level != SOL_SOCKET ||
837: cm->cmsg_type != SCM_RIGHTS)
838: continue;
839: qfds = (cm->cmsg_len - sizeof *cm)
840: / sizeof (struct file *);
841: rp = (struct file **)(cm + 1);
842: for (i = 0; i < qfds; i++)
843: (*op)(*rp++);
844: break; /* XXX, but saves time */
845: }
846: m0 = m0->m_act;
847: }
848: }
849:
850: void
851: unp_mark(fp)
852: struct file *fp;
853: {
854:
855: if (fp->f_flag & FMARK)
856: return;
857: unp_defer++;
858: fp->f_flag |= (FMARK|FDEFER);
859: }
860:
861: void
862: unp_discard(fp)
863: struct file *fp;
864: {
865:
866: fp->f_msgcount--;
867: unp_rights--;
868: (void) closef(fp, (struct proc *)0);
869: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.