Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/kern/uipc_socket.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/kern/uipc_socket.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.1 retrieving revision 1.1.1.3 diff -u -p -r1.1 -r1.1.1.3 --- src/sys/kern/uipc_socket.c 1993/03/21 09:45:37 1.1 +++ src/sys/kern/uipc_socket.c 1998/03/01 02:13:08 1.1.1.3 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California. - * All rights reserved. + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,20 +30,21 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)uipc_socket.c 7.28 (Berkeley) 5/4/91 + * @(#)uipc_socket.c 8.6 (Berkeley) 5/2/95 */ -#include "param.h" -#include "proc.h" -#include "file.h" -#include "malloc.h" -#include "mbuf.h" -#include "domain.h" -#include "kernel.h" -#include "protosw.h" -#include "socket.h" -#include "socketvar.h" -#include "resourcevar.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* * Socket operation routines. @@ -53,7 +54,9 @@ * switching out to the protocol specific routines. */ /*ARGSUSED*/ +int socreate(dom, aso, type, proto) + int dom; struct socket **aso; register int type; int proto; @@ -67,7 +70,7 @@ socreate(dom, aso, type, proto) prp = pffindproto(dom, proto, type); else prp = pffindtype(dom, type); - if (prp == 0) + if (prp == 0 || prp->pr_usrreq == 0) return (EPROTONOSUPPORT); if (prp->pr_type != type) return (EPROTOTYPE); @@ -77,9 +80,8 @@ socreate(dom, aso, type, proto) if (p->p_ucred->cr_uid == 0) so->so_state = SS_PRIV; so->so_proto = prp; - error = - (*prp->pr_usrreq)(so, PRU_ATTACH, - (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0); + error = (*prp->pr_usrreq)(so, PRU_ATTACH, (struct mbuf *)0, + (struct mbuf *)(long)proto, (struct mbuf *)0); if (error) { so->so_state |= SS_NOFDREF; sofree(so); @@ -89,6 +91,7 @@ socreate(dom, aso, type, proto) return (0); } +int sobind(so, nam) struct socket *so; struct mbuf *nam; @@ -103,6 +106,7 @@ sobind(so, nam) return (error); } +int solisten(so, backlog) register struct socket *so; int backlog; @@ -125,6 +129,7 @@ solisten(so, backlog) return (0); } +int sofree(so) register struct socket *so; { @@ -146,6 +151,7 @@ sofree(so) * Initiate disconnect if connected. * Free socket when disconnect complete. */ +int soclose(so) register struct socket *so; { @@ -172,7 +178,7 @@ soclose(so) goto drop; while (so->so_state & SS_ISCONNECTED) if (error = tsleep((caddr_t)&so->so_timeo, - PSOCK | PCATCH, netcls, so->so_linger)) + PSOCK | PCATCH, netcls, so->so_linger * hz)) break; } } @@ -196,6 +202,7 @@ discard: /* * Must be called at splnet... */ +int soabort(so) struct socket *so; { @@ -205,6 +212,7 @@ soabort(so) (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); } +int soaccept(so, nam) register struct socket *so; struct mbuf *nam; @@ -221,6 +229,7 @@ soaccept(so, nam) return (error); } +int soconnect(so, nam) register struct socket *so; struct mbuf *nam; @@ -248,6 +257,7 @@ soconnect(so, nam) return (error); } +int soconnect2(so1, so2) register struct socket *so1; struct socket *so2; @@ -261,6 +271,7 @@ soconnect2(so1, so2) return (error); } +int sodisconnect(so) register struct socket *so; { @@ -282,6 +293,7 @@ bad: return (error); } +#define SBLOCKWAIT(f) (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK) /* * Send on a socket. * If send must go all at once and message is larger than @@ -299,6 +311,7 @@ bad: * must check for short counts if EINTR/ERESTART are returned. * Data and control buffers are freed on return. */ +int sosend(so, addr, uio, top, control, flags) register struct socket *so; struct mbuf *addr; @@ -318,6 +331,15 @@ sosend(so, addr, uio, top, control, flag resid = uio->uio_resid; else resid = top->m_pkthdr.len; + /* + * In theory resid should be unsigned. + * However, space must be signed, as it might be less than 0 + * if we over-committed, and we must use a signed comparison + * of space and resid. On the other hand, a negative resid + * causes us to loop sending 0-length segments to the protocol. + */ + if (resid < 0) + return (EINVAL); dontroute = (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && (so->so_proto->pr_flags & PR_ATOMIC); @@ -327,7 +349,7 @@ sosend(so, addr, uio, top, control, flag #define snderr(errno) { error = errno; splx(s); goto release; } restart: - if (error = sblock(&so->so_snd)) + if (error = sblock(&so->so_snd, SBLOCKWAIT(flags))) goto out; do { s = splnet(); @@ -346,11 +368,11 @@ restart: space = sbspace(&so->so_snd); if (flags & MSG_OOB) space += 1024; - if (space < resid + clen && + if (atomic && resid > so->so_snd.sb_hiwat || + clen > so->so_snd.sb_hiwat) + snderr(EMSGSIZE); + if (space < resid + clen && uio && (atomic || space < so->so_snd.sb_lowat || space < clen)) { - if (atomic && resid > so->so_snd.sb_hiwat || - clen > so->so_snd.sb_hiwat) - snderr(EMSGSIZE); if (so->so_state & SS_NBIO) snderr(EWOULDBLOCK); sbunlock(&so->so_snd); @@ -389,7 +411,7 @@ restart: #ifdef MAPPED_MBUFS len = min(MCLBYTES, resid); #else - if (top == 0) { + if (atomic && top == 0) { len = min(MCLBYTES - max_hdr, resid); m->m_data += max_hdr; } else @@ -465,6 +487,7 @@ out: * an mbuf **mp0 for use in returning the chain. The uio is then used * only for the count in uio_resid. */ +int soreceive(so, paddr, uio, mp0, controlp, flagsp) register struct socket *so; struct mbuf **paddr; @@ -473,12 +496,12 @@ soreceive(so, paddr, uio, mp0, controlp, struct mbuf **controlp; int *flagsp; { - struct proc *p = curproc; /* XXX */ register struct mbuf *m, **mp; register int flags, len, error, s, offset; struct protosw *pr = so->so_proto; struct mbuf *nextrecord; int moff, type; + int orig_resid = uio->uio_resid; mp = mp0; if (paddr) @@ -491,8 +514,8 @@ soreceive(so, paddr, uio, mp0, controlp, flags = 0; if (flags & MSG_OOB) { m = m_get(M_WAIT, MT_DATA); - error = (*pr->pr_usrreq)(so, PRU_RCVOOB, - m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0); + error = (*pr->pr_usrreq)(so, PRU_RCVOOB, m, + (struct mbuf *)(long)(flags & MSG_PEEK), (struct mbuf *)0); if (error) goto bad; do { @@ -512,7 +535,7 @@ bad: (struct mbuf *)0, (struct mbuf *)0); restart: - if (error = sblock(&so->so_rcv)) + if (error = sblock(&so->so_rcv, SBLOCKWAIT(flags))) return (error); s = splnet(); @@ -522,22 +545,24 @@ restart: * (subject to any timeout) if: * 1. the current count is less than the low water mark, or * 2. MSG_WAITALL is set, and it is possible to do the entire - * receive operation at once if we block (resid <= hiwat). + * receive operation at once if we block (resid <= hiwat), or + * 3. MSG_DONTWAIT is not set. * If MSG_WAITALL is set but resid is larger than the receive buffer, * we have to do the receive in sections, and thus risk returning * a short count if a timeout or signal occurs after we start. */ - while (m == 0 || so->so_rcv.sb_cc < uio->uio_resid && + if (m == 0 || ((flags & MSG_DONTWAIT) == 0 && + so->so_rcv.sb_cc < uio->uio_resid) && (so->so_rcv.sb_cc < so->so_rcv.sb_lowat || ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) && - m->m_nextpkt == 0) { + m->m_nextpkt == 0 && (pr->pr_flags & PR_ATOMIC) == 0) { #ifdef DIAGNOSTIC if (m == 0 && so->so_rcv.sb_cc) panic("receive 1"); #endif if (so->so_error) { if (m) - break; + goto dontblock; error = so->so_error; if ((flags & MSG_PEEK) == 0) so->so_error = 0; @@ -545,7 +570,7 @@ restart: } if (so->so_state & SS_CANTRCVMORE) { if (m) - break; + goto dontblock; else goto release; } @@ -561,7 +586,7 @@ restart: } if (uio->uio_resid == 0) goto release; - if (so->so_state & SS_NBIO) { + if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) { error = EWOULDBLOCK; goto release; } @@ -573,13 +598,15 @@ restart: goto restart; } dontblock: - p->p_stats->p_ru.ru_msgrcv++; + if (uio->uio_procp) + uio->uio_procp->p_stats->p_ru.ru_msgrcv++; nextrecord = m->m_nextpkt; if (pr->pr_flags & PR_ADDR) { #ifdef DIAGNOSTIC if (m->m_type != MT_SONAME) panic("receive 1a"); #endif + orig_resid = 0; if (flags & MSG_PEEK) { if (paddr) *paddr = m_copy(m, 0, m->m_len); @@ -618,8 +645,10 @@ dontblock: m = so->so_rcv.sb_mb; } } - if (controlp) + if (controlp) { + orig_resid = 0; controlp = &(*controlp)->m_next; + } } if (m) { if ((flags & MSG_PEEK) == 0) @@ -699,8 +728,11 @@ dontblock: so->so_state |= SS_RCVATMARK; break; } - } else + } else { offset += len; + if (offset == so->so_oobmark) + break; + } } if (flags & MSG_EOR) break; @@ -712,7 +744,7 @@ dontblock: * Keep sockbuf locked against other readers. */ while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 && - !sosendallatonce(so)) { + !sosendallatonce(so) && !nextrecord) { if (so->so_error || so->so_state & SS_CANTRCVMORE) break; error = sbwait(&so->so_rcv); @@ -725,18 +757,27 @@ dontblock: nextrecord = m->m_nextpkt; } } + + if (m && pr->pr_flags & PR_ATOMIC) { + flags |= MSG_TRUNC; + if ((flags & MSG_PEEK) == 0) + (void) sbdroprecord(&so->so_rcv); + } if ((flags & MSG_PEEK) == 0) { if (m == 0) so->so_rcv.sb_mb = nextrecord; - else if (pr->pr_flags & PR_ATOMIC) { - flags |= MSG_TRUNC; - (void) sbdroprecord(&so->so_rcv); - } if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, - (struct mbuf *)flags, (struct mbuf *)0, + (struct mbuf *)(long)flags, (struct mbuf *)0, (struct mbuf *)0); } + if (orig_resid == uio->uio_resid && orig_resid && + (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) { + sbunlock(&so->so_rcv); + splx(s); + goto restart; + } + if (flagsp) *flagsp |= flags; release: @@ -745,6 +786,7 @@ release: return (error); } +int soshutdown(so, how) register struct socket *so; register int how; @@ -760,6 +802,7 @@ soshutdown(so, how) return (0); } +void sorflush(so) register struct socket *so; { @@ -769,7 +812,7 @@ sorflush(so) struct sockbuf asb; sb->sb_flags |= SB_NOINTR; - (void) sblock(sb); + (void) sblock(sb, M_WAITOK); s = splimp(); socantrcvmore(so); sbunlock(sb); @@ -781,6 +824,7 @@ sorflush(so) sbrelease(&asb); } +int sosetopt(so, level, optname, m0) register struct socket *so; int level, optname; @@ -811,6 +855,7 @@ sosetopt(so, level, optname, m0) case SO_USELOOPBACK: case SO_BROADCAST: case SO_REUSEADDR: + case SO_REUSEPORT: case SO_OOBINLINE: if (m == NULL || m->m_len < sizeof (int)) { error = EINVAL; @@ -862,7 +907,7 @@ sosetopt(so, level, optname, m0) goto bad; } tv = mtod(m, struct timeval *); - if (tv->tv_sec > SHRT_MAX / hz - hz) { + if (tv->tv_sec * hz + tv->tv_usec / tick > SHRT_MAX) { error = EDOM; goto bad; } @@ -884,6 +929,11 @@ sosetopt(so, level, optname, m0) error = ENOPROTOOPT; break; } + if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) { + (void) ((*so->so_proto->pr_ctloutput) + (PRCO_SETOPT, so, level, optname, &m0)); + m = NULL; /* freed by protocol */ + } } bad: if (m) @@ -891,6 +941,7 @@ bad: return (error); } +int sogetopt(so, level, optname, mp) register struct socket *so; int level, optname; @@ -922,6 +973,7 @@ sogetopt(so, level, optname, mp) case SO_DEBUG: case SO_KEEPALIVE: case SO_REUSEADDR: + case SO_REUSEPORT: case SO_BROADCAST: case SO_OOBINLINE: *mtod(m, int *) = so->so_options & optname; @@ -961,7 +1013,7 @@ sogetopt(so, level, optname, mp) m->m_len = sizeof(struct timeval); mtod(m, struct timeval *)->tv_sec = val / hz; mtod(m, struct timeval *)->tv_usec = - (val % hz) / tick; + (val % hz) * tick; break; } @@ -974,6 +1026,7 @@ sogetopt(so, level, optname, mp) } } +void sohasoutofband(so) register struct socket *so; { @@ -983,9 +1036,5 @@ sohasoutofband(so) gsignal(-so->so_pgid, SIGURG); else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) psignal(p, SIGURG); - if (so->so_rcv.sb_sel) { - selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL); - so->so_rcv.sb_sel = 0; - so->so_rcv.sb_flags &= ~SB_COLL; - } + selwakeup(&so->so_rcv.sb_sel); }