|
|
1.1 ! cgd 1: /*
! 2: * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
! 3: * All rights reserved.
! 4: *
! 5: * Redistribution and use in source and binary forms, with or without
! 6: * modification, are permitted provided that the following conditions
! 7: * are met:
! 8: * 1. Redistributions of source code must retain the above copyright
! 9: * notice, this list of conditions and the following disclaimer.
! 10: * 2. Redistributions in binary form must reproduce the above copyright
! 11: * notice, this list of conditions and the following disclaimer in the
! 12: * documentation and/or other materials provided with the distribution.
! 13: * 3. All advertising materials mentioning features or use of this software
! 14: * must display the following acknowledgement:
! 15: * This product includes software developed by the University of
! 16: * California, Berkeley and its contributors.
! 17: * 4. Neither the name of the University nor the names of its contributors
! 18: * may be used to endorse or promote products derived from this software
! 19: * without specific prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 31: * SUCH DAMAGE.
! 32: *
! 33: * @(#)uipc_socket.c 7.28 (Berkeley) 5/4/91
! 34: */
! 35:
! 36: #include "param.h"
! 37: #include "proc.h"
! 38: #include "file.h"
! 39: #include "malloc.h"
! 40: #include "mbuf.h"
! 41: #include "domain.h"
! 42: #include "kernel.h"
! 43: #include "protosw.h"
! 44: #include "socket.h"
! 45: #include "socketvar.h"
! 46: #include "resourcevar.h"
! 47:
! 48: /*
! 49: * Socket operation routines.
! 50: * These routines are called by the routines in
! 51: * sys_socket.c or from a system process, and
! 52: * implement the semantics of socket operations by
! 53: * switching out to the protocol specific routines.
! 54: */
! 55: /*ARGSUSED*/
! 56: socreate(dom, aso, type, proto)
! 57: struct socket **aso;
! 58: register int type;
! 59: int proto;
! 60: {
! 61: struct proc *p = curproc; /* XXX */
! 62: register struct protosw *prp;
! 63: register struct socket *so;
! 64: register int error;
! 65:
! 66: if (proto)
! 67: prp = pffindproto(dom, proto, type);
! 68: else
! 69: prp = pffindtype(dom, type);
! 70: if (prp == 0)
! 71: return (EPROTONOSUPPORT);
! 72: if (prp->pr_type != type)
! 73: return (EPROTOTYPE);
! 74: MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT);
! 75: bzero((caddr_t)so, sizeof(*so));
! 76: so->so_type = type;
! 77: if (p->p_ucred->cr_uid == 0)
! 78: so->so_state = SS_PRIV;
! 79: so->so_proto = prp;
! 80: error =
! 81: (*prp->pr_usrreq)(so, PRU_ATTACH,
! 82: (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0);
! 83: if (error) {
! 84: so->so_state |= SS_NOFDREF;
! 85: sofree(so);
! 86: return (error);
! 87: }
! 88: *aso = so;
! 89: return (0);
! 90: }
! 91:
! 92: sobind(so, nam)
! 93: struct socket *so;
! 94: struct mbuf *nam;
! 95: {
! 96: int s = splnet();
! 97: int error;
! 98:
! 99: error =
! 100: (*so->so_proto->pr_usrreq)(so, PRU_BIND,
! 101: (struct mbuf *)0, nam, (struct mbuf *)0);
! 102: splx(s);
! 103: return (error);
! 104: }
! 105:
! 106: solisten(so, backlog)
! 107: register struct socket *so;
! 108: int backlog;
! 109: {
! 110: int s = splnet(), error;
! 111:
! 112: error =
! 113: (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
! 114: (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
! 115: if (error) {
! 116: splx(s);
! 117: return (error);
! 118: }
! 119: if (so->so_q == 0)
! 120: so->so_options |= SO_ACCEPTCONN;
! 121: if (backlog < 0)
! 122: backlog = 0;
! 123: so->so_qlimit = min(backlog, SOMAXCONN);
! 124: splx(s);
! 125: return (0);
! 126: }
! 127:
! 128: sofree(so)
! 129: register struct socket *so;
! 130: {
! 131:
! 132: if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
! 133: return;
! 134: if (so->so_head) {
! 135: if (!soqremque(so, 0) && !soqremque(so, 1))
! 136: panic("sofree dq");
! 137: so->so_head = 0;
! 138: }
! 139: sbrelease(&so->so_snd);
! 140: sorflush(so);
! 141: FREE(so, M_SOCKET);
! 142: }
! 143:
! 144: /*
! 145: * Close a socket on last file table reference removal.
! 146: * Initiate disconnect if connected.
! 147: * Free socket when disconnect complete.
! 148: */
! 149: soclose(so)
! 150: register struct socket *so;
! 151: {
! 152: int s = splnet(); /* conservative */
! 153: int error = 0;
! 154:
! 155: if (so->so_options & SO_ACCEPTCONN) {
! 156: while (so->so_q0)
! 157: (void) soabort(so->so_q0);
! 158: while (so->so_q)
! 159: (void) soabort(so->so_q);
! 160: }
! 161: if (so->so_pcb == 0)
! 162: goto discard;
! 163: if (so->so_state & SS_ISCONNECTED) {
! 164: if ((so->so_state & SS_ISDISCONNECTING) == 0) {
! 165: error = sodisconnect(so);
! 166: if (error)
! 167: goto drop;
! 168: }
! 169: if (so->so_options & SO_LINGER) {
! 170: if ((so->so_state & SS_ISDISCONNECTING) &&
! 171: (so->so_state & SS_NBIO))
! 172: goto drop;
! 173: while (so->so_state & SS_ISCONNECTED)
! 174: if (error = tsleep((caddr_t)&so->so_timeo,
! 175: PSOCK | PCATCH, netcls, so->so_linger))
! 176: break;
! 177: }
! 178: }
! 179: drop:
! 180: if (so->so_pcb) {
! 181: int error2 =
! 182: (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
! 183: (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
! 184: if (error == 0)
! 185: error = error2;
! 186: }
! 187: discard:
! 188: if (so->so_state & SS_NOFDREF)
! 189: panic("soclose: NOFDREF");
! 190: so->so_state |= SS_NOFDREF;
! 191: sofree(so);
! 192: splx(s);
! 193: return (error);
! 194: }
! 195:
! 196: /*
! 197: * Must be called at splnet...
! 198: */
! 199: soabort(so)
! 200: struct socket *so;
! 201: {
! 202:
! 203: return (
! 204: (*so->so_proto->pr_usrreq)(so, PRU_ABORT,
! 205: (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
! 206: }
! 207:
! 208: soaccept(so, nam)
! 209: register struct socket *so;
! 210: struct mbuf *nam;
! 211: {
! 212: int s = splnet();
! 213: int error;
! 214:
! 215: if ((so->so_state & SS_NOFDREF) == 0)
! 216: panic("soaccept: !NOFDREF");
! 217: so->so_state &= ~SS_NOFDREF;
! 218: error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
! 219: (struct mbuf *)0, nam, (struct mbuf *)0);
! 220: splx(s);
! 221: return (error);
! 222: }
! 223:
! 224: soconnect(so, nam)
! 225: register struct socket *so;
! 226: struct mbuf *nam;
! 227: {
! 228: int s;
! 229: int error;
! 230:
! 231: if (so->so_options & SO_ACCEPTCONN)
! 232: return (EOPNOTSUPP);
! 233: s = splnet();
! 234: /*
! 235: * If protocol is connection-based, can only connect once.
! 236: * Otherwise, if connected, try to disconnect first.
! 237: * This allows user to disconnect by connecting to, e.g.,
! 238: * a null address.
! 239: */
! 240: if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
! 241: ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
! 242: (error = sodisconnect(so))))
! 243: error = EISCONN;
! 244: else
! 245: error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
! 246: (struct mbuf *)0, nam, (struct mbuf *)0);
! 247: splx(s);
! 248: return (error);
! 249: }
! 250:
! 251: soconnect2(so1, so2)
! 252: register struct socket *so1;
! 253: struct socket *so2;
! 254: {
! 255: int s = splnet();
! 256: int error;
! 257:
! 258: error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,
! 259: (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0);
! 260: splx(s);
! 261: return (error);
! 262: }
! 263:
! 264: sodisconnect(so)
! 265: register struct socket *so;
! 266: {
! 267: int s = splnet();
! 268: int error;
! 269:
! 270: if ((so->so_state & SS_ISCONNECTED) == 0) {
! 271: error = ENOTCONN;
! 272: goto bad;
! 273: }
! 274: if (so->so_state & SS_ISDISCONNECTING) {
! 275: error = EALREADY;
! 276: goto bad;
! 277: }
! 278: error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
! 279: (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
! 280: bad:
! 281: splx(s);
! 282: return (error);
! 283: }
! 284:
! 285: /*
! 286: * Send on a socket.
! 287: * If send must go all at once and message is larger than
! 288: * send buffering, then hard error.
! 289: * Lock against other senders.
! 290: * If must go all at once and not enough room now, then
! 291: * inform user that this would block and do nothing.
! 292: * Otherwise, if nonblocking, send as much as possible.
! 293: * The data to be sent is described by "uio" if nonzero,
! 294: * otherwise by the mbuf chain "top" (which must be null
! 295: * if uio is not). Data provided in mbuf chain must be small
! 296: * enough to send all at once.
! 297: *
! 298: * Returns nonzero on error, timeout or signal; callers
! 299: * must check for short counts if EINTR/ERESTART are returned.
! 300: * Data and control buffers are freed on return.
! 301: */
! 302: sosend(so, addr, uio, top, control, flags)
! 303: register struct socket *so;
! 304: struct mbuf *addr;
! 305: struct uio *uio;
! 306: struct mbuf *top;
! 307: struct mbuf *control;
! 308: int flags;
! 309: {
! 310: struct proc *p = curproc; /* XXX */
! 311: struct mbuf **mp;
! 312: register struct mbuf *m;
! 313: register long space, len, resid;
! 314: int clen = 0, error, s, dontroute, mlen;
! 315: int atomic = sosendallatonce(so) || top;
! 316:
! 317: if (uio)
! 318: resid = uio->uio_resid;
! 319: else
! 320: resid = top->m_pkthdr.len;
! 321: dontroute =
! 322: (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
! 323: (so->so_proto->pr_flags & PR_ATOMIC);
! 324: p->p_stats->p_ru.ru_msgsnd++;
! 325: if (control)
! 326: clen = control->m_len;
! 327: #define snderr(errno) { error = errno; splx(s); goto release; }
! 328:
! 329: restart:
! 330: if (error = sblock(&so->so_snd))
! 331: goto out;
! 332: do {
! 333: s = splnet();
! 334: if (so->so_state & SS_CANTSENDMORE)
! 335: snderr(EPIPE);
! 336: if (so->so_error)
! 337: snderr(so->so_error);
! 338: if ((so->so_state & SS_ISCONNECTED) == 0) {
! 339: if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
! 340: if ((so->so_state & SS_ISCONFIRMING) == 0 &&
! 341: !(resid == 0 && clen != 0))
! 342: snderr(ENOTCONN);
! 343: } else if (addr == 0)
! 344: snderr(EDESTADDRREQ);
! 345: }
! 346: space = sbspace(&so->so_snd);
! 347: if (flags & MSG_OOB)
! 348: space += 1024;
! 349: if (space < resid + clen &&
! 350: (atomic || space < so->so_snd.sb_lowat || space < clen)) {
! 351: if (atomic && resid > so->so_snd.sb_hiwat ||
! 352: clen > so->so_snd.sb_hiwat)
! 353: snderr(EMSGSIZE);
! 354: if (so->so_state & SS_NBIO)
! 355: snderr(EWOULDBLOCK);
! 356: sbunlock(&so->so_snd);
! 357: error = sbwait(&so->so_snd);
! 358: splx(s);
! 359: if (error)
! 360: goto out;
! 361: goto restart;
! 362: }
! 363: splx(s);
! 364: mp = ⊤
! 365: space -= clen;
! 366: do {
! 367: if (uio == NULL) {
! 368: /*
! 369: * Data is prepackaged in "top".
! 370: */
! 371: resid = 0;
! 372: if (flags & MSG_EOR)
! 373: top->m_flags |= M_EOR;
! 374: } else do {
! 375: if (top == 0) {
! 376: MGETHDR(m, M_WAIT, MT_DATA);
! 377: mlen = MHLEN;
! 378: m->m_pkthdr.len = 0;
! 379: m->m_pkthdr.rcvif = (struct ifnet *)0;
! 380: } else {
! 381: MGET(m, M_WAIT, MT_DATA);
! 382: mlen = MLEN;
! 383: }
! 384: if (resid >= MINCLSIZE && space >= MCLBYTES) {
! 385: MCLGET(m, M_WAIT);
! 386: if ((m->m_flags & M_EXT) == 0)
! 387: goto nopages;
! 388: mlen = MCLBYTES;
! 389: #ifdef MAPPED_MBUFS
! 390: len = min(MCLBYTES, resid);
! 391: #else
! 392: if (top == 0) {
! 393: len = min(MCLBYTES - max_hdr, resid);
! 394: m->m_data += max_hdr;
! 395: } else
! 396: len = min(MCLBYTES, resid);
! 397: #endif
! 398: space -= MCLBYTES;
! 399: } else {
! 400: nopages:
! 401: len = min(min(mlen, resid), space);
! 402: space -= len;
! 403: /*
! 404: * For datagram protocols, leave room
! 405: * for protocol headers in first mbuf.
! 406: */
! 407: if (atomic && top == 0 && len < mlen)
! 408: MH_ALIGN(m, len);
! 409: }
! 410: error = uiomove(mtod(m, caddr_t), (int)len, uio);
! 411: resid = uio->uio_resid;
! 412: m->m_len = len;
! 413: *mp = m;
! 414: top->m_pkthdr.len += len;
! 415: if (error)
! 416: goto release;
! 417: mp = &m->m_next;
! 418: if (resid <= 0) {
! 419: if (flags & MSG_EOR)
! 420: top->m_flags |= M_EOR;
! 421: break;
! 422: }
! 423: } while (space > 0 && atomic);
! 424: if (dontroute)
! 425: so->so_options |= SO_DONTROUTE;
! 426: s = splnet(); /* XXX */
! 427: error = (*so->so_proto->pr_usrreq)(so,
! 428: (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
! 429: top, addr, control);
! 430: splx(s);
! 431: if (dontroute)
! 432: so->so_options &= ~SO_DONTROUTE;
! 433: clen = 0;
! 434: control = 0;
! 435: top = 0;
! 436: mp = ⊤
! 437: if (error)
! 438: goto release;
! 439: } while (resid && space > 0);
! 440: } while (resid);
! 441:
! 442: release:
! 443: sbunlock(&so->so_snd);
! 444: out:
! 445: if (top)
! 446: m_freem(top);
! 447: if (control)
! 448: m_freem(control);
! 449: return (error);
! 450: }
! 451:
! 452: /*
! 453: * Implement receive operations on a socket.
! 454: * We depend on the way that records are added to the sockbuf
! 455: * by sbappend*. In particular, each record (mbufs linked through m_next)
! 456: * must begin with an address if the protocol so specifies,
! 457: * followed by an optional mbuf or mbufs containing ancillary data,
! 458: * and then zero or more mbufs of data.
! 459: * In order to avoid blocking network interrupts for the entire time here,
! 460: * we splx() while doing the actual copy to user space.
! 461: * Although the sockbuf is locked, new data may still be appended,
! 462: * and thus we must maintain consistency of the sockbuf during that time.
! 463: *
! 464: * The caller may receive the data as a single mbuf chain by supplying
! 465: * an mbuf **mp0 for use in returning the chain. The uio is then used
! 466: * only for the count in uio_resid.
! 467: */
! 468: soreceive(so, paddr, uio, mp0, controlp, flagsp)
! 469: register struct socket *so;
! 470: struct mbuf **paddr;
! 471: struct uio *uio;
! 472: struct mbuf **mp0;
! 473: struct mbuf **controlp;
! 474: int *flagsp;
! 475: {
! 476: struct proc *p = curproc; /* XXX */
! 477: register struct mbuf *m, **mp;
! 478: register int flags, len, error, s, offset;
! 479: struct protosw *pr = so->so_proto;
! 480: struct mbuf *nextrecord;
! 481: int moff, type;
! 482:
! 483: mp = mp0;
! 484: if (paddr)
! 485: *paddr = 0;
! 486: if (controlp)
! 487: *controlp = 0;
! 488: if (flagsp)
! 489: flags = *flagsp &~ MSG_EOR;
! 490: else
! 491: flags = 0;
! 492: if (flags & MSG_OOB) {
! 493: m = m_get(M_WAIT, MT_DATA);
! 494: error = (*pr->pr_usrreq)(so, PRU_RCVOOB,
! 495: m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0);
! 496: if (error)
! 497: goto bad;
! 498: do {
! 499: error = uiomove(mtod(m, caddr_t),
! 500: (int) min(uio->uio_resid, m->m_len), uio);
! 501: m = m_free(m);
! 502: } while (uio->uio_resid && error == 0 && m);
! 503: bad:
! 504: if (m)
! 505: m_freem(m);
! 506: return (error);
! 507: }
! 508: if (mp)
! 509: *mp = (struct mbuf *)0;
! 510: if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)
! 511: (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
! 512: (struct mbuf *)0, (struct mbuf *)0);
! 513:
! 514: restart:
! 515: if (error = sblock(&so->so_rcv))
! 516: return (error);
! 517: s = splnet();
! 518:
! 519: m = so->so_rcv.sb_mb;
! 520: /*
! 521: * If we have less data than requested, block awaiting more
! 522: * (subject to any timeout) if:
! 523: * 1. the current count is less than the low water mark, or
! 524: * 2. MSG_WAITALL is set, and it is possible to do the entire
! 525: * receive operation at once if we block (resid <= hiwat).
! 526: * If MSG_WAITALL is set but resid is larger than the receive buffer,
! 527: * we have to do the receive in sections, and thus risk returning
! 528: * a short count if a timeout or signal occurs after we start.
! 529: */
! 530: while (m == 0 || so->so_rcv.sb_cc < uio->uio_resid &&
! 531: (so->so_rcv.sb_cc < so->so_rcv.sb_lowat ||
! 532: ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) &&
! 533: m->m_nextpkt == 0) {
! 534: #ifdef DIAGNOSTIC
! 535: if (m == 0 && so->so_rcv.sb_cc)
! 536: panic("receive 1");
! 537: #endif
! 538: if (so->so_error) {
! 539: if (m)
! 540: break;
! 541: error = so->so_error;
! 542: if ((flags & MSG_PEEK) == 0)
! 543: so->so_error = 0;
! 544: goto release;
! 545: }
! 546: if (so->so_state & SS_CANTRCVMORE) {
! 547: if (m)
! 548: break;
! 549: else
! 550: goto release;
! 551: }
! 552: for (; m; m = m->m_next)
! 553: if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) {
! 554: m = so->so_rcv.sb_mb;
! 555: goto dontblock;
! 556: }
! 557: if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
! 558: (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
! 559: error = ENOTCONN;
! 560: goto release;
! 561: }
! 562: if (uio->uio_resid == 0)
! 563: goto release;
! 564: if (so->so_state & SS_NBIO) {
! 565: error = EWOULDBLOCK;
! 566: goto release;
! 567: }
! 568: sbunlock(&so->so_rcv);
! 569: error = sbwait(&so->so_rcv);
! 570: splx(s);
! 571: if (error)
! 572: return (error);
! 573: goto restart;
! 574: }
! 575: dontblock:
! 576: p->p_stats->p_ru.ru_msgrcv++;
! 577: nextrecord = m->m_nextpkt;
! 578: if (pr->pr_flags & PR_ADDR) {
! 579: #ifdef DIAGNOSTIC
! 580: if (m->m_type != MT_SONAME)
! 581: panic("receive 1a");
! 582: #endif
! 583: if (flags & MSG_PEEK) {
! 584: if (paddr)
! 585: *paddr = m_copy(m, 0, m->m_len);
! 586: m = m->m_next;
! 587: } else {
! 588: sbfree(&so->so_rcv, m);
! 589: if (paddr) {
! 590: *paddr = m;
! 591: so->so_rcv.sb_mb = m->m_next;
! 592: m->m_next = 0;
! 593: m = so->so_rcv.sb_mb;
! 594: } else {
! 595: MFREE(m, so->so_rcv.sb_mb);
! 596: m = so->so_rcv.sb_mb;
! 597: }
! 598: }
! 599: }
! 600: while (m && m->m_type == MT_CONTROL && error == 0) {
! 601: if (flags & MSG_PEEK) {
! 602: if (controlp)
! 603: *controlp = m_copy(m, 0, m->m_len);
! 604: m = m->m_next;
! 605: } else {
! 606: sbfree(&so->so_rcv, m);
! 607: if (controlp) {
! 608: if (pr->pr_domain->dom_externalize &&
! 609: mtod(m, struct cmsghdr *)->cmsg_type ==
! 610: SCM_RIGHTS)
! 611: error = (*pr->pr_domain->dom_externalize)(m);
! 612: *controlp = m;
! 613: so->so_rcv.sb_mb = m->m_next;
! 614: m->m_next = 0;
! 615: m = so->so_rcv.sb_mb;
! 616: } else {
! 617: MFREE(m, so->so_rcv.sb_mb);
! 618: m = so->so_rcv.sb_mb;
! 619: }
! 620: }
! 621: if (controlp)
! 622: controlp = &(*controlp)->m_next;
! 623: }
! 624: if (m) {
! 625: if ((flags & MSG_PEEK) == 0)
! 626: m->m_nextpkt = nextrecord;
! 627: type = m->m_type;
! 628: if (type == MT_OOBDATA)
! 629: flags |= MSG_OOB;
! 630: }
! 631: moff = 0;
! 632: offset = 0;
! 633: while (m && uio->uio_resid > 0 && error == 0) {
! 634: if (m->m_type == MT_OOBDATA) {
! 635: if (type != MT_OOBDATA)
! 636: break;
! 637: } else if (type == MT_OOBDATA)
! 638: break;
! 639: #ifdef DIAGNOSTIC
! 640: else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
! 641: panic("receive 3");
! 642: #endif
! 643: so->so_state &= ~SS_RCVATMARK;
! 644: len = uio->uio_resid;
! 645: if (so->so_oobmark && len > so->so_oobmark - offset)
! 646: len = so->so_oobmark - offset;
! 647: if (len > m->m_len - moff)
! 648: len = m->m_len - moff;
! 649: /*
! 650: * If mp is set, just pass back the mbufs.
! 651: * Otherwise copy them out via the uio, then free.
! 652: * Sockbuf must be consistent here (points to current mbuf,
! 653: * it points to next record) when we drop priority;
! 654: * we must note any additions to the sockbuf when we
! 655: * block interrupts again.
! 656: */
! 657: if (mp == 0) {
! 658: splx(s);
! 659: error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio);
! 660: s = splnet();
! 661: } else
! 662: uio->uio_resid -= len;
! 663: if (len == m->m_len - moff) {
! 664: if (m->m_flags & M_EOR)
! 665: flags |= MSG_EOR;
! 666: if (flags & MSG_PEEK) {
! 667: m = m->m_next;
! 668: moff = 0;
! 669: } else {
! 670: nextrecord = m->m_nextpkt;
! 671: sbfree(&so->so_rcv, m);
! 672: if (mp) {
! 673: *mp = m;
! 674: mp = &m->m_next;
! 675: so->so_rcv.sb_mb = m = m->m_next;
! 676: *mp = (struct mbuf *)0;
! 677: } else {
! 678: MFREE(m, so->so_rcv.sb_mb);
! 679: m = so->so_rcv.sb_mb;
! 680: }
! 681: if (m)
! 682: m->m_nextpkt = nextrecord;
! 683: }
! 684: } else {
! 685: if (flags & MSG_PEEK)
! 686: moff += len;
! 687: else {
! 688: if (mp)
! 689: *mp = m_copym(m, 0, len, M_WAIT);
! 690: m->m_data += len;
! 691: m->m_len -= len;
! 692: so->so_rcv.sb_cc -= len;
! 693: }
! 694: }
! 695: if (so->so_oobmark) {
! 696: if ((flags & MSG_PEEK) == 0) {
! 697: so->so_oobmark -= len;
! 698: if (so->so_oobmark == 0) {
! 699: so->so_state |= SS_RCVATMARK;
! 700: break;
! 701: }
! 702: } else
! 703: offset += len;
! 704: }
! 705: if (flags & MSG_EOR)
! 706: break;
! 707: /*
! 708: * If the MSG_WAITALL flag is set (for non-atomic socket),
! 709: * we must not quit until "uio->uio_resid == 0" or an error
! 710: * termination. If a signal/timeout occurs, return
! 711: * with a short count but without error.
! 712: * Keep sockbuf locked against other readers.
! 713: */
! 714: while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 &&
! 715: !sosendallatonce(so)) {
! 716: if (so->so_error || so->so_state & SS_CANTRCVMORE)
! 717: break;
! 718: error = sbwait(&so->so_rcv);
! 719: if (error) {
! 720: sbunlock(&so->so_rcv);
! 721: splx(s);
! 722: return (0);
! 723: }
! 724: if (m = so->so_rcv.sb_mb)
! 725: nextrecord = m->m_nextpkt;
! 726: }
! 727: }
! 728: if ((flags & MSG_PEEK) == 0) {
! 729: if (m == 0)
! 730: so->so_rcv.sb_mb = nextrecord;
! 731: else if (pr->pr_flags & PR_ATOMIC) {
! 732: flags |= MSG_TRUNC;
! 733: (void) sbdroprecord(&so->so_rcv);
! 734: }
! 735: if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
! 736: (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
! 737: (struct mbuf *)flags, (struct mbuf *)0,
! 738: (struct mbuf *)0);
! 739: }
! 740: if (flagsp)
! 741: *flagsp |= flags;
! 742: release:
! 743: sbunlock(&so->so_rcv);
! 744: splx(s);
! 745: return (error);
! 746: }
! 747:
! 748: soshutdown(so, how)
! 749: register struct socket *so;
! 750: register int how;
! 751: {
! 752: register struct protosw *pr = so->so_proto;
! 753:
! 754: how++;
! 755: if (how & FREAD)
! 756: sorflush(so);
! 757: if (how & FWRITE)
! 758: return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN,
! 759: (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
! 760: return (0);
! 761: }
! 762:
! 763: sorflush(so)
! 764: register struct socket *so;
! 765: {
! 766: register struct sockbuf *sb = &so->so_rcv;
! 767: register struct protosw *pr = so->so_proto;
! 768: register int s;
! 769: struct sockbuf asb;
! 770:
! 771: sb->sb_flags |= SB_NOINTR;
! 772: (void) sblock(sb);
! 773: s = splimp();
! 774: socantrcvmore(so);
! 775: sbunlock(sb);
! 776: asb = *sb;
! 777: bzero((caddr_t)sb, sizeof (*sb));
! 778: splx(s);
! 779: if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
! 780: (*pr->pr_domain->dom_dispose)(asb.sb_mb);
! 781: sbrelease(&asb);
! 782: }
! 783:
! 784: sosetopt(so, level, optname, m0)
! 785: register struct socket *so;
! 786: int level, optname;
! 787: struct mbuf *m0;
! 788: {
! 789: int error = 0;
! 790: register struct mbuf *m = m0;
! 791:
! 792: if (level != SOL_SOCKET) {
! 793: if (so->so_proto && so->so_proto->pr_ctloutput)
! 794: return ((*so->so_proto->pr_ctloutput)
! 795: (PRCO_SETOPT, so, level, optname, &m0));
! 796: error = ENOPROTOOPT;
! 797: } else {
! 798: switch (optname) {
! 799:
! 800: case SO_LINGER:
! 801: if (m == NULL || m->m_len != sizeof (struct linger)) {
! 802: error = EINVAL;
! 803: goto bad;
! 804: }
! 805: so->so_linger = mtod(m, struct linger *)->l_linger;
! 806: /* fall thru... */
! 807:
! 808: case SO_DEBUG:
! 809: case SO_KEEPALIVE:
! 810: case SO_DONTROUTE:
! 811: case SO_USELOOPBACK:
! 812: case SO_BROADCAST:
! 813: case SO_REUSEADDR:
! 814: case SO_OOBINLINE:
! 815: if (m == NULL || m->m_len < sizeof (int)) {
! 816: error = EINVAL;
! 817: goto bad;
! 818: }
! 819: if (*mtod(m, int *))
! 820: so->so_options |= optname;
! 821: else
! 822: so->so_options &= ~optname;
! 823: break;
! 824:
! 825: case SO_SNDBUF:
! 826: case SO_RCVBUF:
! 827: case SO_SNDLOWAT:
! 828: case SO_RCVLOWAT:
! 829: if (m == NULL || m->m_len < sizeof (int)) {
! 830: error = EINVAL;
! 831: goto bad;
! 832: }
! 833: switch (optname) {
! 834:
! 835: case SO_SNDBUF:
! 836: case SO_RCVBUF:
! 837: if (sbreserve(optname == SO_SNDBUF ?
! 838: &so->so_snd : &so->so_rcv,
! 839: (u_long) *mtod(m, int *)) == 0) {
! 840: error = ENOBUFS;
! 841: goto bad;
! 842: }
! 843: break;
! 844:
! 845: case SO_SNDLOWAT:
! 846: so->so_snd.sb_lowat = *mtod(m, int *);
! 847: break;
! 848: case SO_RCVLOWAT:
! 849: so->so_rcv.sb_lowat = *mtod(m, int *);
! 850: break;
! 851: }
! 852: break;
! 853:
! 854: case SO_SNDTIMEO:
! 855: case SO_RCVTIMEO:
! 856: {
! 857: struct timeval *tv;
! 858: short val;
! 859:
! 860: if (m == NULL || m->m_len < sizeof (*tv)) {
! 861: error = EINVAL;
! 862: goto bad;
! 863: }
! 864: tv = mtod(m, struct timeval *);
! 865: if (tv->tv_sec > SHRT_MAX / hz - hz) {
! 866: error = EDOM;
! 867: goto bad;
! 868: }
! 869: val = tv->tv_sec * hz + tv->tv_usec / tick;
! 870:
! 871: switch (optname) {
! 872:
! 873: case SO_SNDTIMEO:
! 874: so->so_snd.sb_timeo = val;
! 875: break;
! 876: case SO_RCVTIMEO:
! 877: so->so_rcv.sb_timeo = val;
! 878: break;
! 879: }
! 880: break;
! 881: }
! 882:
! 883: default:
! 884: error = ENOPROTOOPT;
! 885: break;
! 886: }
! 887: }
! 888: bad:
! 889: if (m)
! 890: (void) m_free(m);
! 891: return (error);
! 892: }
! 893:
! 894: sogetopt(so, level, optname, mp)
! 895: register struct socket *so;
! 896: int level, optname;
! 897: struct mbuf **mp;
! 898: {
! 899: register struct mbuf *m;
! 900:
! 901: if (level != SOL_SOCKET) {
! 902: if (so->so_proto && so->so_proto->pr_ctloutput) {
! 903: return ((*so->so_proto->pr_ctloutput)
! 904: (PRCO_GETOPT, so, level, optname, mp));
! 905: } else
! 906: return (ENOPROTOOPT);
! 907: } else {
! 908: m = m_get(M_WAIT, MT_SOOPTS);
! 909: m->m_len = sizeof (int);
! 910:
! 911: switch (optname) {
! 912:
! 913: case SO_LINGER:
! 914: m->m_len = sizeof (struct linger);
! 915: mtod(m, struct linger *)->l_onoff =
! 916: so->so_options & SO_LINGER;
! 917: mtod(m, struct linger *)->l_linger = so->so_linger;
! 918: break;
! 919:
! 920: case SO_USELOOPBACK:
! 921: case SO_DONTROUTE:
! 922: case SO_DEBUG:
! 923: case SO_KEEPALIVE:
! 924: case SO_REUSEADDR:
! 925: case SO_BROADCAST:
! 926: case SO_OOBINLINE:
! 927: *mtod(m, int *) = so->so_options & optname;
! 928: break;
! 929:
! 930: case SO_TYPE:
! 931: *mtod(m, int *) = so->so_type;
! 932: break;
! 933:
! 934: case SO_ERROR:
! 935: *mtod(m, int *) = so->so_error;
! 936: so->so_error = 0;
! 937: break;
! 938:
! 939: case SO_SNDBUF:
! 940: *mtod(m, int *) = so->so_snd.sb_hiwat;
! 941: break;
! 942:
! 943: case SO_RCVBUF:
! 944: *mtod(m, int *) = so->so_rcv.sb_hiwat;
! 945: break;
! 946:
! 947: case SO_SNDLOWAT:
! 948: *mtod(m, int *) = so->so_snd.sb_lowat;
! 949: break;
! 950:
! 951: case SO_RCVLOWAT:
! 952: *mtod(m, int *) = so->so_rcv.sb_lowat;
! 953: break;
! 954:
! 955: case SO_SNDTIMEO:
! 956: case SO_RCVTIMEO:
! 957: {
! 958: int val = (optname == SO_SNDTIMEO ?
! 959: so->so_snd.sb_timeo : so->so_rcv.sb_timeo);
! 960:
! 961: m->m_len = sizeof(struct timeval);
! 962: mtod(m, struct timeval *)->tv_sec = val / hz;
! 963: mtod(m, struct timeval *)->tv_usec =
! 964: (val % hz) / tick;
! 965: break;
! 966: }
! 967:
! 968: default:
! 969: (void)m_free(m);
! 970: return (ENOPROTOOPT);
! 971: }
! 972: *mp = m;
! 973: return (0);
! 974: }
! 975: }
! 976:
! 977: sohasoutofband(so)
! 978: register struct socket *so;
! 979: {
! 980: struct proc *p;
! 981:
! 982: if (so->so_pgid < 0)
! 983: gsignal(-so->so_pgid, SIGURG);
! 984: else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
! 985: psignal(p, SIGURG);
! 986: if (so->so_rcv.sb_sel) {
! 987: selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL);
! 988: so->so_rcv.sb_sel = 0;
! 989: so->so_rcv.sb_flags &= ~SB_COLL;
! 990: }
! 991: }