X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/2b4b57cde32cd59d62925e7cfa02dc478cde4624..4a2ddbf18dd19f34cdd8770365cc6ac08d10c423:/usr/src/sys/kern/uipc_socket.c diff --git a/usr/src/sys/kern/uipc_socket.c b/usr/src/sys/kern/uipc_socket.c index 3b650f01bb..150ba408e0 100644 --- a/usr/src/sys/kern/uipc_socket.c +++ b/usr/src/sys/kern/uipc_socket.c @@ -1,4 +1,4 @@ -/* uipc_socket.c 4.6 81/11/18 */ +/* uipc_socket.c 4.42 82/06/20 */ #include "../h/param.h" #include "../h/systm.h" @@ -13,8 +13,10 @@ #include "../h/socket.h" #include "../h/socketvar.h" #include "../h/stat.h" -#include "../net/inet.h" -#include "../net/inet_systm.h" +#include "../h/ioctl.h" +#include "../net/in.h" +#include "../net/in_systm.h" +#include "../net/route.h" /* * Socket support routines. @@ -36,7 +38,6 @@ socreate(aso, type, asp, asa, options) register struct socket *so; struct mbuf *m; int pf, proto, error; -COUNT(SOCREATE); /* * Use process standard protocol/protocol family if none @@ -69,16 +70,21 @@ COUNT(SOCREATE); return (ENOBUFS); so = mtod(m, struct socket *); so->so_options = options; + so->so_state = 0; + if (u.u_uid == 0) + so->so_state = SS_PRIV; /* * Attach protocol to socket, initializing * and reserving resources. */ so->so_proto = prp; - (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa); - if (so->so_error) { - error = so->so_error; - m_free(dtom(so)); + error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa); + if (error) { + if (so->so_snd.sb_mbmax || so->so_rcv.sb_mbmax) + panic("socreate"); + so->so_state |= SS_USERGONE; + sofree(so); return (error); } *aso = so; @@ -89,71 +95,75 @@ sofree(so) struct socket *so; { -COUNT(SOFREE); - m_free(dtom(so)); + if (so->so_pcb || (so->so_state & SS_USERGONE) == 0) + return; + sbrelease(&so->so_snd); + sbrelease(&so->so_rcv); + (void) m_free(dtom(so)); } /* * Close a socket on last file table reference removal. * Initiate disconnect if connected. * Free socket when disconnect complete. + * + * THIS IS REALLY A UNIX INTERFACE ROUTINE */ -soclose(so) +soclose(so, exiting) register struct socket *so; + int exiting; { int s = splnet(); /* conservative */ -COUNT(SOCLOSE); if (so->so_pcb == 0) goto discard; + if (exiting) + so->so_options |= SO_KEEPALIVE; if (so->so_state & SS_ISCONNECTED) { if ((so->so_state & SS_ISDISCONNECTING) == 0) { u.u_error = sodisconnect(so, (struct sockaddr *)0); if (u.u_error) { + if (exiting) + goto drop; + splx(s); + return; + } + } + if ((so->so_options & SO_DONTLINGER) == 0) { + if ((so->so_state & SS_ISDISCONNECTING) && + (so->so_state & SS_NBIO) && + exiting == 0) { + u.u_error = EINPROGRESS; splx(s); return; } + /* should use tsleep here, for at most linger */ + while (so->so_state & SS_ISCONNECTED) + sleep((caddr_t)&so->so_timeo, PZERO+1); } - if ((so->so_state & SS_ISDISCONNECTING) && - (so->so_options & SO_NBIO)) { - u.u_error = EINPROGRESS; + } +drop: + if (so->so_pcb) { + u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0); + if (exiting == 0 && u.u_error) { splx(s); return; } - while (so->so_state & SS_ISCONNECTED) - sleep((caddr_t)&so->so_timeo, PZERO+1); } - u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0); discard: - if (so->so_pcb == 0) - sofree(so); + so->so_state |= SS_USERGONE; + sofree(so); splx(s); } -sosplice(pso, so) - struct socket *pso, *so; -{ - -COUNT(SOSPLICE); - if (pso->so_proto->pr_family != PF_LOCAL) { - struct socket *tso; - tso = pso; pso = so; so = tso; - } - if (pso->so_proto->pr_family != PF_LOCAL) - return (EOPNOTSUPP); - /* check types and buffer space */ - /* merge buffers */ - return (0); -} - /*ARGSUSED*/ sostat(so, sb) struct socket *so; struct stat *sb; { -COUNT(SOSTAT); - return (EOPNOTSUPP); + bzero((caddr_t)sb, sizeof (*sb)); /* XXX */ + return (0); /* XXX */ } /* @@ -166,15 +176,15 @@ soaccept(so, asa) int s = splnet(); int error; -COUNT(SOACCEPT); - if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { - error = EISCONN; - goto bad; - } if ((so->so_options & SO_ACCEPTCONN) == 0) { error = EINVAL; /* XXX */ goto bad; } + if ((so->so_state & SS_CONNAWAITING) == 0) { + error = ENOTCONN; + goto bad; + } + so->so_state &= ~SS_CONNAWAITING; error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa); bad: splx(s); @@ -193,7 +203,6 @@ soconnect(so, asa) int s = splnet(); int error; -COUNT(SOCONNECT); if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { error = EISCONN; goto bad; @@ -217,7 +226,6 @@ sodisconnect(so, asa) int s = splnet(); int error; -COUNT(SODISCONNECT); if ((so->so_state & SS_ISCONNECTED) == 0) { error = ENOTCONN; goto bad; @@ -249,58 +257,71 @@ sosend(so, asa) register u_int len; int error = 0, space, s; -COUNT(SOSEND); - if (so->so_state & SS_CANTSENDMORE) - return (EPIPE); if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat) return (EMSGSIZE); - if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO)) +#ifdef notdef + /* NEED TO PREVENT BUSY WAITING IN SELECT FOR WRITING */ + if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_state & SS_NBIO)) return (EWOULDBLOCK); +#endif +restart: sblock(&so->so_snd); #define snderr(errno) { error = errno; splx(s); goto release; } - s = splnet(); again: + s = splnet(); + if (so->so_state & SS_CANTSENDMORE) { + psignal(u.u_procp, SIGPIPE); + snderr(EPIPE); + } + if (so->so_error) { + error = so->so_error; + so->so_error = 0; /* ??? */ + splx(s); + goto release; + } if ((so->so_state & SS_ISCONNECTED) == 0) { if (so->so_proto->pr_flags & PR_CONNREQUIRED) snderr(ENOTCONN); if (asa == 0) snderr(EDESTADDRREQ); } - if (so->so_error) - snderr(so->so_error); if (top) { error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa); + top = 0; if (error) { splx(s); goto release; } - top = 0; mp = ⊤ } - if (sosendallatonce(so) && sbspace(&so->so_snd) < u.u_count) { - if (so->so_options & SO_NBIO) + if (u.u_count == 0) { + splx(s); + goto release; + } + space = sbspace(&so->so_snd); + if (space <= 0 || sosendallatonce(so) && space < u.u_count) { + if (so->so_state & SS_NBIO) snderr(EWOULDBLOCK); sbunlock(&so->so_snd); sbwait(&so->so_snd); splx(s); - goto again; + goto restart; } splx(s); - while (u.u_count && (space = sbspace(&so->so_snd)) > 0) { + while (u.u_count && space > 0) { MGET(m, 1); if (m == NULL) { - error = ENOBUFS; - m_freem(top); + error = ENOBUFS; /* SIGPIPE? */ goto release; } - if (u.u_count >= PGSIZE && space >= NMBPG) { + if (u.u_count >= CLBYTES && space >= CLBYTES) { register struct mbuf *p; - MPGET(p, 1); + MCLGET(p, 1); if (p == 0) goto nopages; m->m_off = (int)p - (int)m; - len = PGSIZE; + len = CLBYTES; } else { nopages: m->m_off = MMINOFF; @@ -310,12 +331,14 @@ nopages: m->m_len = len; *mp = m; mp = &m->m_next; + space = sbspace(&so->so_snd); } - s = splnet(); goto again; release: sbunlock(&so->so_snd); + if (top) + m_freem(top); return (error); } @@ -325,61 +348,71 @@ soreceive(so, asa) { register struct mbuf *m, *n; u_int len; - int eor, s, error = 0; + int eor, s, error = 0, cnt = u.u_count; + caddr_t base = u.u_base; -COUNT(SORECEIVE); restart: sblock(&so->so_rcv); s = splnet(); #define rcverr(errno) { error = errno; splx(s); goto release; } if (so->so_rcv.sb_cc == 0) { - if ((so->so_state & SS_ISCONNECTED) == 0 && - (so->so_proto->pr_flags & PR_CONNREQUIRED)) - rcverr(ENOTCONN); + if (so->so_error) { + error = so->so_error; + so->so_error = 0; + splx(s); + goto release; + } if (so->so_state & SS_CANTRCVMORE) { splx(s); goto release; } - if (so->so_options & SO_NBIO) - rcverr (EWOULDBLOCK); + if ((so->so_state & SS_ISCONNECTED) == 0 && + (so->so_proto->pr_flags & PR_CONNREQUIRED)) + rcverr(ENOTCONN); + if (so->so_state & SS_NBIO) + rcverr(EWOULDBLOCK); sbunlock(&so->so_rcv); - sleep((caddr_t)&so->so_rcv.sb_cc, PZERO+1); + sbwait(&so->so_rcv); + splx(s); goto restart; } m = so->so_rcv.sb_mb; if (m == 0) panic("receive"); - if ((so->so_proto->pr_flags & PR_ADDR)) { - so->so_rcv.sb_mb = m->m_next; - if (asa) { - so->so_rcv.sb_cc -= m->m_len; - len = MIN(m->m_len, sizeof (struct sockaddr)); - bcopy(mtod(m, caddr_t), (caddr_t)asa, len); - } else - bzero((caddr_t)asa, sizeof (*asa)); - m = so->so_rcv.sb_mb; + if (so->so_proto->pr_flags & PR_ADDR) { + if (m->m_len != sizeof (struct sockaddr)) + panic("soreceive addr"); + if (asa) + bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa)); + so->so_rcv.sb_cc -= m->m_len; + so->so_rcv.sb_mbcnt -= MSIZE; + m = m_free(m); if (m == 0) panic("receive 2"); + so->so_rcv.sb_mb = m; } + so->so_state &= ~SS_RCVATMARK; + if (so->so_oobmark && cnt > so->so_oobmark) + cnt = so->so_oobmark; eor = 0; do { - len = MIN(m->m_len, u.u_count); - if (len == m->m_len) { - eor = (int)m->m_act; - sbfree(&so->so_rcv, m); - } + len = MIN(m->m_len, cnt); splx(s); iomove(mtod(m, caddr_t), len, B_READ); + cnt -= len; s = splnet(); if (len == m->m_len) { + eor = (int)m->m_act; + sbfree(&so->so_rcv, m); + so->so_rcv.sb_mb = m->m_next; MFREE(m, n); } else { m->m_off += len; m->m_len -= len; so->so_rcv.sb_cc -= len; } - } while ((m = so->so_rcv.sb_mb) && u.u_count && !eor); + } while ((m = so->so_rcv.sb_mb) && cnt && !eor); if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) do { if (m == 0) @@ -392,12 +425,33 @@ restart: } while (eor == 0); if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); + if (so->so_oobmark) { + so->so_oobmark -= u.u_base - base; + if (so->so_oobmark == 0) + so->so_state |= SS_RCVATMARK; + } release: sbunlock(&so->so_rcv); splx(s); return (error); } +sohasoutofband(so) + struct socket *so; +{ + + if (so->so_pgrp == 0) + return; + if (so->so_pgrp > 0) + gsignal(so->so_pgrp, SIGURG); + else { + struct proc *p = pfind(-so->so_pgrp); + + if (p) + psignal(p, SIGURG); + } +} + /*ARGSUSED*/ soioctl(so, cmd, cmdp) register struct socket *so; @@ -405,23 +459,171 @@ soioctl(so, cmd, cmdp) register caddr_t cmdp; { -COUNT(SOIOCTL); - switch (cmdp) { + switch (cmd) { + + case FIONBIO: { + int nbio; + if (copyin(cmdp, (caddr_t)&nbio, sizeof (nbio))) { + u.u_error = EFAULT; + return; + } + if (nbio) + so->so_state |= SS_NBIO; + else + so->so_state &= ~SS_NBIO; + return; + } + + case FIOASYNC: { + int async; + if (copyin(cmdp, (caddr_t)&async, sizeof (async))) { + u.u_error = EFAULT; + return; + } + if (async) + so->so_state |= SS_ASYNC; + else + so->so_state &= ~SS_ASYNC; + return; + } + + case SIOCSKEEP: { + int keep; + if (copyin(cmdp, (caddr_t)&keep, sizeof (keep))) { + u.u_error = EFAULT; + return; + } + if (keep) + so->so_options &= ~SO_KEEPALIVE; + else + so->so_options |= SO_KEEPALIVE; + return; + } + + case SIOCGKEEP: { + int keep = (so->so_options & SO_KEEPALIVE) != 0; + if (copyout((caddr_t)&keep, cmdp, sizeof (keep))) + u.u_error = EFAULT; + return; + } + + case SIOCSLINGER: { + int linger; + if (copyin(cmdp, (caddr_t)&linger, sizeof (linger))) { + u.u_error = EFAULT; + return; + } + so->so_linger = linger; + if (so->so_linger) + so->so_options &= ~SO_DONTLINGER; + else + so->so_options |= SO_DONTLINGER; + return; + } + + case SIOCGLINGER: { + int linger = so->so_linger; + if (copyout((caddr_t)&linger, cmdp, sizeof (linger))) { + u.u_error = EFAULT; + return; + } + } + case SIOCSPGRP: { + int pgrp; + if (copyin(cmdp, (caddr_t)&pgrp, sizeof (pgrp))) { + u.u_error = EFAULT; + return; + } + so->so_pgrp = pgrp; + return; + } + + case SIOCGPGRP: { + int pgrp = so->so_pgrp; + if (copyout((caddr_t)&pgrp, cmdp, sizeof (pgrp))) { + u.u_error = EFAULT; + return; + } + } + case SIOCDONE: { + int flags; + if (copyin(cmdp, (caddr_t)&flags, sizeof (flags))) { + u.u_error = EFAULT; + return; + } + flags++; + if (flags & FREAD) { + int s = splimp(); + socantrcvmore(so); + sbflush(&so->so_rcv); + splx(s); + } + if (flags & FWRITE) + u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0); + return; } - switch (so->so_type) { - case SOCK_STREAM: - break; + case SIOCSENDOOB: { + char oob; + struct mbuf *m; + if (copyin(cmdp, (caddr_t)&oob, sizeof (oob))) { + u.u_error = EFAULT; + return; + } + m = m_get(M_DONTWAIT); + if (m == 0) { + u.u_error = ENOBUFS; + return; + } + m->m_off = MMINOFF; + m->m_len = 1; + *mtod(m, caddr_t) = oob; + (*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0); + return; + } - case SOCK_DGRAM: - break; + case SIOCRCVOOB: { + struct mbuf *m = m_get(M_DONTWAIT); + if (m == 0) { + u.u_error = ENOBUFS; + return; + } + m->m_off = MMINOFF; *mtod(m, caddr_t) = 0; + (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0); + if (copyout(mtod(m, caddr_t), cmdp, sizeof (char))) { + u.u_error = EFAULT; + return; + } + m_free(m); + return; + } - case SOCK_RDM: - break; + case SIOCATMARK: { + int atmark = (so->so_state&SS_RCVATMARK) != 0; + if (copyout((caddr_t)&atmark, cmdp, sizeof (atmark))) { + u.u_error = EFAULT; + return; + } + return; + } - case SOCK_RAW: - break; + /* routing table update calls */ + case SIOCADDRT: + case SIOCDELRT: + case SIOCCHGRT: { + struct rtentry route; + if (!suser()) + return; + if (copyin(cmdp, (caddr_t)&route, sizeof (route))) { + u.u_error = EFAULT; + return; + } + u.u_error = rtrequest(cmd, &route); + return; + } + /* type/protocol specific ioctls */ } + u.u_error = EOPNOTSUPP; }