X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/7bcf9d138b83559264aa0049292269f0a7ddab7e..15d436e0ed8d8c3d1d6dae157d8d010bbc94f48e:/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 02ebd120b4..645dd3be07 100644 --- a/usr/src/sys/kern/uipc_socket.c +++ b/usr/src/sys/kern/uipc_socket.c @@ -1,31 +1,32 @@ /* - * 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. + * Copyright (c) 1982, 1986, 1988 Regents of the University of California. + * All rights reserved. * - * @(#)uipc_socket.c 7.2 (Berkeley) %G% + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#)uipc_socket.c 7.14 (Berkeley) %G% */ #include "param.h" -#include "systm.h" -#include "dir.h" #include "user.h" #include "proc.h" #include "file.h" -#include "inode.h" -#include "buf.h" +#include "malloc.h" #include "mbuf.h" -#include "un.h" #include "domain.h" #include "protosw.h" #include "socket.h" #include "socketvar.h" -#include "stat.h" -#include "ioctl.h" -#include "uio.h" -#include "../net/route.h" -#include "../netinet/in.h" -#include "../net/if.h" /* * Socket operation routines. @@ -47,7 +48,6 @@ socreate(dom, aso, type, proto) { register struct protosw *prp; register struct socket *so; - register struct mbuf *m; register int error; if (proto) @@ -58,10 +58,8 @@ socreate(dom, aso, type, proto) return (EPROTONOSUPPORT); if (prp->pr_type != type) return (EPROTOTYPE); - m = m_getclr(M_WAIT, MT_SOCKET); - so = mtod(m, struct socket *); - so->so_options = 0; - so->so_state = 0; + MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT); + bzero((caddr_t)so, sizeof(*so)); so->so_type = type; if (u.u_uid == 0) so->so_state = SS_PRIV; @@ -112,7 +110,7 @@ solisten(so, backlog) } if (backlog < 0) backlog = 0; - so->so_qlimit = MIN(backlog, SOMAXCONN); + so->so_qlimit = min(backlog, SOMAXCONN); splx(s); return (0); } @@ -121,16 +119,16 @@ sofree(so) register struct socket *so; { + if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) + return; if (so->so_head) { if (!soqremque(so, 0) && !soqremque(so, 1)) panic("sofree dq"); so->so_head = 0; } - if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) - return; sbrelease(&so->so_snd); sorflush(so); - (void) m_free(dtom(so)); + FREE(so, M_SOCKET); } /* @@ -142,7 +140,7 @@ soclose(so) register struct socket *so; { int s = splnet(); /* conservative */ - int error; + int error = 0; if (so->so_options & SO_ACCEPTCONN) { while (so->so_q0 != so) @@ -281,19 +279,20 @@ bad: * inform user that this would block and do nothing. * Otherwise, if nonblocking, send as much as possible. */ -sosend(so, nam, uio, flags, rights) +sosend(so, nam, uio, flags, rights, control) register struct socket *so; struct mbuf *nam; register struct uio *uio; int flags; - struct mbuf *rights; + struct mbuf *rights, *control; { - struct mbuf *top = 0; - register struct mbuf *m, **mp; - register int space; - int len, rlen = 0, error = 0, s, dontroute, first = 1; + struct mbuf *top = 0, **mp; + register struct mbuf *m; + register int space, len; + int rlen = 0, error = 0, s, dontroute, first = 1, mlen; + int atomic = sosendallatonce(so); - if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat) + if (atomic && uio->uio_resid > so->so_snd.sb_hiwat) return (EMSGSIZE); dontroute = (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && @@ -309,16 +308,19 @@ restart: s = splnet(); if (so->so_state & SS_CANTSENDMORE) snderr(EPIPE); - if (so->so_error) { - error = so->so_error; - so->so_error = 0; /* ??? */ - splx(s); - goto release; - } + if (so->so_error) + snderr(so->so_error); if ((so->so_state & SS_ISCONNECTED) == 0) { - if (so->so_proto->pr_flags & PR_CONNREQUIRED) - snderr(ENOTCONN); - if (nam == 0) + if (so->so_proto->pr_flags & PR_CONNREQUIRED) { + if (!uio->uio_resid && !rights && control) { + snderr((*so->so_proto->pr_usrreq)(so, + (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, + top, (caddr_t)0, rights, control)); + } else if (so->so_state & SS_ISCONFIRMING) + /* is ok */; + else + snderr(ENOTCONN); + } else if (nam == 0) snderr(EDESTADDRREQ); } if (flags & MSG_OOB) @@ -326,10 +328,9 @@ restart: else { space = sbspace(&so->so_snd); if (space <= rlen || - (sosendallatonce(so) && - space < uio->uio_resid + rlen) || - (uio->uio_resid >= CLBYTES && space < CLBYTES && - so->so_snd.sb_cc >= CLBYTES && + (atomic && space < uio->uio_resid + rlen) || + (uio->uio_resid >= MCLBYTES && space < MCLBYTES && + so->so_snd.sb_cc >= MCLBYTES && (so->so_state & SS_NBIO) == 0)) { if (so->so_state & SS_NBIO) { if (first) @@ -346,43 +347,72 @@ restart: splx(s); mp = ⊤ space -= rlen; - while (space > 0) { - MGET(m, M_WAIT, MT_DATA); - if (uio->uio_resid >= CLBYTES / 2 && space >= CLBYTES) { - MCLGET(m); - if (m->m_len != CLBYTES) + do { + do { + if (top == 0) { + MGETHDR(m, M_WAIT, MT_DATA); + mlen = MHLEN; + m->m_pkthdr.len = 0; + m->m_pkthdr.rcvif = (struct ifnet *)0; + } else { + MGET(m, M_WAIT, MT_DATA); + mlen = MLEN; + } + if (uio->uio_resid >= MINCLSIZE && space >= MCLBYTES) { + MCLGET(m, M_WAIT); + if ((m->m_flags & M_EXT) == 0) goto nopages; - len = MIN(CLBYTES, uio->uio_resid); - space -= CLBYTES; + mlen = MCLBYTES; +#ifdef MAPPED_MBUFS + len = min(MCLBYTES, uio->uio_resid); + if (len < mlen - max_hdr) + m->m_data += max_hdr; +#else + len = min(MCLBYTES - max_hdr, uio->uio_resid); + m->m_data += max_hdr; +#endif + space -= MCLBYTES; } else { nopages: - len = MIN(MIN(MLEN, uio->uio_resid), space); + len = min(min(mlen, uio->uio_resid), space); space -= len; + /* + * For datagram protocols, leave room + * for protocol headers in first mbuf. + */ + if (atomic && top == 0 && len < mlen) + MH_ALIGN(m, len); } - error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); + error = uiomove(mtod(m, caddr_t), len, uio); m->m_len = len; *mp = m; + top->m_pkthdr.len += len; if (error) goto release; mp = &m->m_next; - if (uio->uio_resid <= 0) + if (uio->uio_resid <= 0) { + if ((flags & MSG_EOR) && top) + top->m_flags |= M_EOR; break; - } - if (dontroute) - so->so_options |= SO_DONTROUTE; - s = splnet(); /* XXX */ - error = (*so->so_proto->pr_usrreq)(so, - (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, - top, (caddr_t)nam, rights); - splx(s); - if (dontroute) - so->so_options &= ~SO_DONTROUTE; - rights = 0; - rlen = 0; - top = 0; - first = 0; - if (error) - break; + } + } while (space > 0 && atomic); + if (dontroute) + so->so_options |= SO_DONTROUTE; + s = splnet(); /* XXX */ + error = (*so->so_proto->pr_usrreq)(so, + (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, + top, (caddr_t)nam, rights, control); + splx(s); + if (dontroute) + so->so_options &= ~SO_DONTROUTE; + rights = 0; + rlen = 0; + top = 0; + mp = ⊤ + first = 0; + if (error) + goto release; + } while (uio->uio_resid && space > 0); } while (uio->uio_resid); release: @@ -406,15 +436,15 @@ release: * Although the sockbuf is locked, new data may still be appended, * and thus we must maintain consistency of the sockbuf during that time. */ -soreceive(so, aname, uio, flags, rightsp) +soreceive(so, aname, uio, flagsp, rightsp, controlp) register struct socket *so; struct mbuf **aname; register struct uio *uio; - int flags; - struct mbuf **rightsp; + int *flagsp; + struct mbuf **rightsp, **controlp; { register struct mbuf *m; - register int len, error = 0, s, tomark; + register int flags, len, error = 0, s, offset; struct protosw *pr = so->so_proto; struct mbuf *nextrecord; int moff; @@ -423,6 +453,12 @@ soreceive(so, aname, uio, flags, rightsp) *rightsp = 0; if (aname) *aname = 0; + if (controlp) + *controlp = 0; + if (flagsp) + flags = *flagsp &~ MSG_EOR; + else + flags = 0; if (flags & MSG_OOB) { m = m_get(M_WAIT, MT_DATA); error = (*pr->pr_usrreq)(so, PRU_RCVOOB, @@ -433,8 +469,7 @@ soreceive(so, aname, uio, flags, rightsp) len = uio->uio_resid; if (len > m->m_len) len = m->m_len; - error = - uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); + error = uiomove(mtod(m, caddr_t), (int)len, uio); m = m_free(m); } while (uio->uio_resid && error == 0 && m); bad: @@ -442,40 +477,45 @@ bad: m_freem(m); return (error); } + if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) + (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, + (struct mbuf *)0, (struct mbuf *)0); restart: sblock(&so->so_rcv); s = splnet(); -#define rcverr(errno) { error = errno; splx(s); goto release; } - if (so->so_rcv.sb_cc == 0) { + m = so->so_rcv.sb_mb; + if (m == 0) { + if (so->so_rcv.sb_cc) + panic("receive 1"); if (so->so_error) { error = so->so_error; so->so_error = 0; - splx(s); goto release; } - if (so->so_state & SS_CANTRCVMORE) { - splx(s); + if (so->so_state & SS_CANTRCVMORE) goto release; - } if ((so->so_state & SS_ISCONNECTED) == 0 && - (so->so_proto->pr_flags & PR_CONNREQUIRED)) - rcverr(ENOTCONN); + (so->so_proto->pr_flags & PR_CONNREQUIRED)) { + error = ENOTCONN; + goto release; + } if (uio->uio_resid == 0) goto release; - if (so->so_state & SS_NBIO) - rcverr(EWOULDBLOCK); + if (so->so_state & SS_NBIO) { + error = EWOULDBLOCK; + goto release; + } sbunlock(&so->so_rcv); sbwait(&so->so_rcv); splx(s); goto restart; } u.u_ru.ru_msgrcv++; - m = so->so_rcv.sb_mb; - if (m == 0) - panic("receive 1"); - nextrecord = m->m_act; +if (m->m_type == 0) +panic("receive 3a"); + nextrecord = m->m_nextpkt; if (pr->pr_flags & PR_ADDR) { if (m->m_type != MT_SONAME) panic("receive 1a"); @@ -487,15 +527,13 @@ restart: sbfree(&so->so_rcv, m); if (aname) { *aname = m; - m = m->m_next; - (*aname)->m_next = 0; - so->so_rcv.sb_mb = m; + so->so_rcv.sb_mb = m->m_next; + m->m_next = 0; + m = so->so_rcv.sb_mb; } else { MFREE(m, so->so_rcv.sb_mb); m = so->so_rcv.sb_mb; } - if (m) - m->m_act = nextrecord; } } if (m && m->m_type == MT_RIGHTS) { @@ -516,71 +554,100 @@ restart: MFREE(m, so->so_rcv.sb_mb); m = so->so_rcv.sb_mb; } - if (m) - m->m_act = nextrecord; } } + if (m && m->m_type == MT_CONTROL) { + if (flags & MSG_PEEK) { + if (controlp) + *controlp = m_copy(m, 0, m->m_len); + m = m->m_next; + } else { + sbfree(&so->so_rcv, m); + if (controlp) { + *controlp = m; + so->so_rcv.sb_mb = m->m_next; + m->m_next = 0; + m = so->so_rcv.sb_mb; + } else { + MFREE(m, so->so_rcv.sb_mb); + m = so->so_rcv.sb_mb; + } + } + } + if (m) + m->m_nextpkt = nextrecord; moff = 0; - tomark = so->so_oobmark; + offset = 0; while (m && uio->uio_resid > 0 && error == 0) { - if (m->m_type != MT_DATA && m->m_type != MT_HEADER) + if (m->m_type == MT_OOBDATA) + flags |= MSG_OOB; + else if (m->m_type != MT_DATA && m->m_type != MT_HEADER) panic("receive 3"); + if (m->m_flags & M_EOR) + flags |= MSG_EOR; len = uio->uio_resid; so->so_state &= ~SS_RCVATMARK; - if (tomark && len > tomark) - len = tomark; + if (so->so_oobmark && len > so->so_oobmark - offset) + len = so->so_oobmark - offset; if (len > m->m_len - moff) len = m->m_len - moff; splx(s); - error = - uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio); + error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); s = splnet(); if (len == m->m_len - moff) { if (flags & MSG_PEEK) { m = m->m_next; moff = 0; } else { - nextrecord = m->m_act; + nextrecord = m->m_nextpkt; sbfree(&so->so_rcv, m); MFREE(m, so->so_rcv.sb_mb); m = so->so_rcv.sb_mb; if (m) - m->m_act = nextrecord; + m->m_nextpkt = nextrecord; } } else { if (flags & MSG_PEEK) moff += len; else { - m->m_off += len; + m->m_data += len; m->m_len -= len; so->so_rcv.sb_cc -= len; } } - if ((flags & MSG_PEEK) == 0 && so->so_oobmark) { - so->so_oobmark -= len; - if (so->so_oobmark == 0) { - so->so_state |= SS_RCVATMARK; - break; - } - } - if (tomark) { - tomark -= len; - if (tomark == 0) - break; + if (so->so_oobmark) { + if ((flags & MSG_PEEK) == 0) { + so->so_oobmark -= len; + if (so->so_oobmark == 0) { + so->so_state |= SS_RCVATMARK; + break; + } + } else + offset += len; } } + if (m && (flags & MSG_EOR)) { + flags &= ~MSG_EOR; + if ((flags & MSG_PEEK) == 0) + m->m_flags |= M_EOR; + } if ((flags & MSG_PEEK) == 0) { if (m == 0) so->so_rcv.sb_mb = nextrecord; - else if (pr->pr_flags & PR_ATOMIC) + 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 *)0, (struct mbuf *)0); + (struct mbuf *)flags, (struct mbuf *)0, + (struct mbuf *)0); if (error == 0 && rightsp && *rightsp && pr->pr_domain->dom_externalize) error = (*pr->pr_domain->dom_externalize)(*rightsp); } + if (flagsp) + *flagsp |= flags; release: sbunlock(&so->so_rcv); splx(s); @@ -677,8 +744,9 @@ sosetopt(so, level, optname, m0) case SO_SNDBUF: case SO_RCVBUF: - if (sbreserve(optname == SO_SNDBUF ? &so->so_snd : - &so->so_rcv, *mtod(m, int *)) == 0) { + if (sbreserve(optname == SO_SNDBUF ? + &so->so_snd : &so->so_rcv, + (u_long) *mtod(m, int *)) == 0) { error = ENOBUFS; goto bad; } @@ -793,9 +861,9 @@ sohasoutofband(so) { struct proc *p; - if (so->so_pgrp < 0) - gsignal(-so->so_pgrp, SIGURG); - else if (so->so_pgrp > 0 && (p = pfind(so->so_pgrp)) != 0) + if (so->so_pgid < 0) + 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);