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