X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/44eb2da39a85fc1ada790d94816b2e7d0c91177c..5c723b90ceb41c125105d2a818e372ee31f2e522:/usr/src/sys/kern/uipc_usrreq.c diff --git a/usr/src/sys/kern/uipc_usrreq.c b/usr/src/sys/kern/uipc_usrreq.c index f325e364d8..a0ac7f123a 100644 --- a/usr/src/sys/kern/uipc_usrreq.c +++ b/usr/src/sys/kern/uipc_usrreq.c @@ -1,26 +1,35 @@ -/* uipc_usrreq.c 1.12 83/06/13 */ - -#include "../h/param.h" -#include "../h/dir.h" -#include "../h/user.h" -#include "../h/mbuf.h" -#include "../h/protosw.h" -#include "../h/socket.h" -#include "../h/socketvar.h" -#include "../h/unpcb.h" -#include "../h/un.h" -#include "../h/inode.h" -#include "../h/nami.h" -#include "../h/file.h" +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)uipc_usrreq.c 7.1 (Berkeley) %G% + */ + +#include "param.h" +#include "dir.h" +#include "user.h" +#include "mbuf.h" +#include "domain.h" +#include "protosw.h" +#include "socket.h" +#include "socketvar.h" +#include "unpcb.h" +#include "un.h" +#include "inode.h" +#include "file.h" +#include "stat.h" /* * Unix communications domain. * * TODO: * SEQPACKET, RDM - * change for names in file system + * rethink name space problems * need a proper out-of-band */ +struct sockaddr sun_noname = { AF_UNIX }; +ino_t unp_ino; /* prototype for fake inode numbers */ /*ARGSUSED*/ uipc_usrreq(so, req, m, nam, rights) @@ -32,6 +41,8 @@ uipc_usrreq(so, req, m, nam, rights) register struct socket *so2; int error = 0; + if (req == PRU_CONTROL) + return (EOPNOTSUPP); if (req != PRU_SEND && rights && rights->m_len) { error = EOPNOTSUPP; goto release; @@ -67,20 +78,28 @@ uipc_usrreq(so, req, m, nam, rights) error = unp_connect(so, nam); break; -#ifdef notdef case PRU_CONNECT2: - error = unp_connect2(so, (struct mbuf *)0, (struct socket *)nam); + error = unp_connect2(so, (struct socket *)nam); break; -#endif case PRU_DISCONNECT: unp_disconnect(unp); break; case PRU_ACCEPT: - nam->m_len = unp->unp_remaddr->m_len; - bcopy(mtod(unp->unp_remaddr, caddr_t), - mtod(nam, caddr_t), (unsigned)nam->m_len); + /* + * Pass back name of connected socket, + * if it was bound and we are still connected + * (our peer may have closed already!). + */ + if (unp->unp_conn && unp->unp_conn->unp_addr) { + nam->m_len = unp->unp_conn->unp_addr->m_len; + bcopy(mtod(unp->unp_conn->unp_addr, caddr_t), + mtod(nam, caddr_t), (unsigned)nam->m_len); + } else { + nam->m_len = sizeof(sun_noname); + *(mtod(nam, struct sockaddr *)) = sun_noname; + } break; case PRU_SHUTDOWN: @@ -102,14 +121,14 @@ uipc_usrreq(so, req, m, nam, rights) break; so2 = unp->unp_conn->unp_socket; /* - * Transfer resources back to send port + * Adjust backpressure on sender * and wakeup any waiting to write. */ - snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt; - rcv->sb_mbmax = rcv->sb_mbcnt; - snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc; - rcv->sb_hiwat = rcv->sb_cc; - sbwakeup(snd); + snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt; + unp->unp_mbcnt = rcv->sb_mbcnt; + snd->sb_hiwat += unp->unp_cc - rcv->sb_cc; + unp->unp_cc = rcv->sb_cc; + sowwakeup(so2); #undef snd #undef rcv break; @@ -120,9 +139,16 @@ uipc_usrreq(so, req, m, nam, rights) break; case PRU_SEND: + if (rights) { + error = unp_internalize(rights); + if (error) + break; + } switch (so->so_type) { - case SOCK_DGRAM: + case SOCK_DGRAM: { + struct sockaddr *from; + if (nam) { if (unp->unp_conn) { error = EISCONN; @@ -138,45 +164,47 @@ uipc_usrreq(so, req, m, nam, rights) } } so2 = unp->unp_conn->unp_socket; - /* BEGIN XXX */ - if (rights) { - error = unp_internalize(rights); - if (error) - break; - } - if (sbspace(&so2->so_rcv) > 0) { - (void) sbappendaddr(&so2->so_rcv, - mtod(nam, struct sockaddr *), m, - rights); - sbwakeup(&so2->so_rcv); + if (unp->unp_addr) + from = mtod(unp->unp_addr, struct sockaddr *); + else + from = &sun_noname; + if (sbspace(&so2->so_rcv) > 0 && + sbappendaddr(&so2->so_rcv, from, m, rights)) { + sorwakeup(so2); m = 0; - } - /* END XXX */ + } else + error = ENOBUFS; if (nam) unp_disconnect(unp); break; + } case SOCK_STREAM: #define rcv (&so2->so_rcv) #define snd (&so->so_snd) - if (rights && rights->m_len) { - error = EOPNOTSUPP; + if (so->so_state & SS_CANTSENDMORE) { + error = EPIPE; break; } if (unp->unp_conn == 0) panic("uipc 3"); so2 = unp->unp_conn->unp_socket; /* - * Send to paired receive port, and then - * give it enough resources to hold what it already has. + * Send to paired receive port, and then reduce + * send buffer hiwater marks to maintain backpressure. * Wake up readers. */ - sbappend(rcv, m); - snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax; - rcv->sb_mbmax = rcv->sb_mbcnt; - snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat; - rcv->sb_hiwat = rcv->sb_cc; - sbwakeup(rcv); + if (rights) + (void)sbappendrights(rcv, m, rights); + else + sbappend(rcv, m); + snd->sb_mbmax -= + rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt; + unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt; + snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc; + unp->unp_conn->unp_cc = rcv->sb_cc; + sorwakeup(so2); + m = 0; #undef snd #undef rcv break; @@ -184,31 +212,42 @@ uipc_usrreq(so, req, m, nam, rights) default: panic("uipc 4"); } - m = 0; break; case PRU_ABORT: unp_drop(unp, ECONNABORTED); break; -/* SOME AS YET UNIMPLEMENTED HOOKS */ - case PRU_CONTROL: - return (EOPNOTSUPP); - case PRU_SENSE: - error = EOPNOTSUPP; - break; -/* END UNIMPLEMENTED HOOKS */ + ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; + if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) { + so2 = unp->unp_conn->unp_socket; + ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc; + } + ((struct stat *) m)->st_dev = NODEV; + if (unp->unp_ino == 0) + unp->unp_ino = unp_ino++; + ((struct stat *) m)->st_ino = unp->unp_ino; + return (0); case PRU_RCVOOB: - break; + return (EOPNOTSUPP); case PRU_SENDOOB: + error = EOPNOTSUPP; break; case PRU_SOCKADDR: break; + case PRU_PEERADDR: + if (unp->unp_conn && unp->unp_conn->unp_addr) { + nam->m_len = unp->unp_conn->unp_addr->m_len; + bcopy(mtod(unp->unp_conn->unp_addr, caddr_t), + mtod(m, caddr_t), (unsigned)m->m_len); + } + break; + case PRU_SLOWTIMO: break; @@ -221,9 +260,21 @@ release: return (error); } -/* SHOULD BE PIPSIZ and 0 */ -int unp_sendspace = 1024*2; -int unp_recvspace = 1024*2; +/* + * Both send and receive buffers are allocated PIPSIZ bytes of buffering + * for stream sockets, although the total for sender and receiver is + * actually only PIPSIZ. + * Datagram sockets really use the sendspace as the maximum datagram size, + * and don't really want to reserve the sendspace. Their recvspace should + * be large enough for at least one max-size datagram plus address. + */ +#define PIPSIZ 4096 +int unpst_sendspace = PIPSIZ; +int unpst_recvspace = PIPSIZ; +int unpdg_sendspace = 2*1024; /* really max datagram size */ +int unpdg_recvspace = 4*1024; + +int unp_rights; /* file descriptors in flight */ unp_attach(so) struct socket *so; @@ -232,7 +283,16 @@ unp_attach(so) register struct unpcb *unp; int error; - error = soreserve(so, unp_sendspace, unp_recvspace); + switch (so->so_type) { + + case SOCK_STREAM: + error = soreserve(so, unpst_sendspace, unpst_recvspace); + break; + + case SOCK_DGRAM: + error = soreserve(so, unpdg_sendspace, unpdg_recvspace); + break; + } if (error) return (error); m = m_getclr(M_DONTWAIT, MT_PCB); @@ -249,6 +309,7 @@ unp_detach(unp) { if (unp->unp_inode) { + unp->unp_inode->i_socket = 0; irele(unp->unp_inode); unp->unp_inode = 0; } @@ -258,8 +319,10 @@ unp_detach(unp) unp_drop(unp->unp_refs, ECONNRESET); soisdisconnected(unp->unp_socket); unp->unp_socket->so_pcb = 0; - m_freem(unp->unp_remaddr); + m_freem(unp->unp_addr); (void) m_free(dtom(unp)); + if (unp_rights) + unp_gc(); } unp_bind(unp, nam) @@ -268,15 +331,17 @@ unp_bind(unp, nam) { struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); register struct inode *ip; - extern schar(); + register struct nameidata *ndp = &u.u_nd; int error; - u.u_dirp = soun->sun_path; - if (nam->m_len == MLEN) + ndp->ni_dirp = soun->sun_path; + if (unp->unp_inode != NULL || nam->m_len == MLEN) return (EINVAL); *(mtod(nam, caddr_t) + nam->m_len) = 0; /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ - ip = namei(schar, CREATE, 1); + ndp->ni_nameiop = CREATE | FOLLOW; + ndp->ni_segflg = UIO_SYSSPACE; + ip = namei(ndp); if (ip) { iput(ip); return (EADDRINUSE); @@ -285,7 +350,7 @@ unp_bind(unp, nam) u.u_error = 0; /* XXX */ return (error); } - ip = maknode(IFSOCK | 0777); + ip = maknode(IFSOCK | 0777, ndp); if (ip == NULL) { error = u.u_error; /* XXX */ u.u_error = 0; /* XXX */ @@ -293,6 +358,7 @@ unp_bind(unp, nam) } ip->i_socket = unp->unp_socket; unp->unp_inode = ip; + unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL); iunlock(ip); /* but keep reference */ return (0); } @@ -305,17 +371,25 @@ unp_connect(so, nam) register struct inode *ip; int error; register struct socket *so2; + register struct nameidata *ndp = &u.u_nd; - u.u_dirp = soun->sun_path; + ndp->ni_dirp = soun->sun_path; if (nam->m_len + (nam->m_off - MMINOFF) == MLEN) return (EMSGSIZE); *(mtod(nam, caddr_t) + nam->m_len) = 0; - ip = namei(schar, LOOKUP, 1); + ndp->ni_nameiop = LOOKUP | FOLLOW; + ndp->ni_segflg = UIO_SYSSPACE; + ip = namei(ndp); if (ip == 0) { error = u.u_error; u.u_error = 0; return (error); /* XXX */ } + if (access(ip, IWRITE)) { + error = u.u_error; + u.u_error = 0; /* XXX */ + goto bad; + } if ((ip->i_mode&IFMT) != IFSOCK) { error = ENOTSOCK; goto bad; @@ -325,15 +399,24 @@ unp_connect(so, nam) error = ECONNREFUSED; goto bad; } - error = unp_connect2(so, nam, so2); + if (so->so_type != so2->so_type) { + error = EPROTOTYPE; + goto bad; + } + if (so->so_proto->pr_flags & PR_CONNREQUIRED && + ((so2->so_options&SO_ACCEPTCONN) == 0 || + (so2 = sonewconn(so2)) == 0)) { + error = ECONNREFUSED; + goto bad; + } + error = unp_connect2(so, so2); bad: iput(ip); return (error); } -unp_connect2(so, sonam, so2) +unp_connect2(so, so2) register struct socket *so; - struct mbuf *sonam; register struct socket *so2; { register struct unpcb *unp = sotounpcb(so); @@ -341,31 +424,25 @@ unp_connect2(so, sonam, so2) if (so2->so_type != so->so_type) return (EPROTOTYPE); + unp2 = sotounpcb(so2); + unp->unp_conn = unp2; switch (so->so_type) { case SOCK_DGRAM: - unp2 = sotounpcb(so2); - unp->unp_conn = unp2; unp->unp_nextref = unp2->unp_refs; unp2->unp_refs = unp; + soisconnected(so); break; case SOCK_STREAM: - if ((so2->so_options&SO_ACCEPTCONN) == 0 || - (so2 = sonewconn(so2)) == 0) - return (ECONNREFUSED); - unp2 = sotounpcb(so2); - unp->unp_conn = unp2; unp2->unp_conn = unp; - if (sonam) - unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL); + soisconnected(so2); + soisconnected(so); break; default: panic("unp_connect2"); } - soisconnected(so2); - soisconnected(so); return (0); } @@ -377,7 +454,6 @@ unp_disconnect(unp) if (unp2 == 0) return; unp->unp_conn = 0; - soisdisconnected(unp->unp_socket); switch (unp->unp_socket->so_type) { case SOCK_DGRAM: @@ -395,9 +471,11 @@ unp_disconnect(unp) unp2->unp_nextref = unp->unp_nextref; } unp->unp_nextref = 0; + unp->unp_socket->so_state &= ~SS_ISCONNECTED; break; case SOCK_STREAM: + soisdisconnected(unp->unp_socket); unp2->unp_conn = 0; soisdisconnected(unp2->unp_socket); break; @@ -424,9 +502,16 @@ unp_drop(unp, errno) struct unpcb *unp; int errno; { + struct socket *so = unp->unp_socket; - unp->unp_socket->so_error = errno; + so->so_error = errno; unp_disconnect(unp); + if (so->so_head) { + so->so_pcb = (caddr_t) 0; + m_freem(unp->unp_addr); + (void) m_free(dtom(unp)); + sofree(so); + } } #ifdef notdef @@ -460,7 +545,8 @@ unp_externalize(rights) fp = *rp; u.u_ofile[f] = fp; fp->f_msgcount--; - *(int *)rp = f; + unp_rights--; + *(int *)rp++ = f; } return (0); } @@ -483,12 +569,14 @@ unp_internalize(rights) *rp++ = fp; fp->f_count++; fp->f_msgcount++; + unp_rights++; } return (0); } int unp_defer, unp_gcing; int unp_mark(); +extern struct domain unixdomain; unp_gc() { @@ -519,8 +607,8 @@ restart: if (fp->f_type != DTYPE_SOCKET) continue; so = (struct socket *)fp->f_data; - if (so->so_proto->pr_family != AF_UNIX || - (so->so_proto->pr_flags&PR_ADDR) == 0) + if (so->so_proto->pr_domain != &unixdomain || + (so->so_proto->pr_flags&PR_RIGHTS) == 0) continue; if (so->so_rcv.sb_flags & SB_LOCK) { sbwait(&so->so_rcv); @@ -532,43 +620,42 @@ restart: for (fp = file; fp < fileNFILE; fp++) { if (fp->f_count == 0) continue; - if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) { - if (fp->f_type != DTYPE_SOCKET) - panic("unp_gc"); - (void) soshutdown((struct socket *)fp->f_data, 0); - } + if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0) + while (fp->f_msgcount) + unp_discard(fp); } unp_gcing = 0; } -unp_scan(m, op) - register struct mbuf *m; +unp_dispose(m) + struct mbuf *m; +{ + int unp_discard(); + + if (m) + unp_scan(m, unp_discard); +} + +unp_scan(m0, op) + register struct mbuf *m0; int (*op)(); { + register struct mbuf *m; register struct file **rp; register int i; int qfds; - while (m) { - m = m->m_next; - if (m == 0) - goto bad; - if (m->m_len) { - qfds = m->m_len / sizeof (struct file *); - rp = mtod(m, struct file **); - for (i = 0; i < qfds; i++) - (*op)(*rp++); - } - do { - m = m->m_next; - if (m == 0) - goto bad; - } while (m->m_act == 0); - m = m->m_next; + while (m0) { + for (m = m0; m; m = m->m_next) + if (m->m_type == MT_RIGHTS && m->m_len) { + qfds = m->m_len / sizeof (struct file *); + rp = mtod(m, struct file **); + for (i = 0; i < qfds; i++) + (*op)(*rp++); + break; /* XXX, but saves time */ + } + m0 = m0->m_act; } - return; -bad: - panic("unp_gcscan"); } unp_mark(fp) @@ -586,5 +673,6 @@ unp_discard(fp) { fp->f_msgcount--; + unp_rights--; closef(fp); }