|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.