Annotation of sys/kern/uipc_socket.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: uipc_socket.c,v 1.66 2007/02/26 23:53:33 kurt Exp $ */
! 2: /* $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1982, 1986, 1988, 1990, 1993
! 6: * The Regents of the University of California. All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. Neither the name of the University nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: *
! 32: * @(#)uipc_socket.c 8.3 (Berkeley) 4/15/94
! 33: */
! 34:
! 35: #include <sys/param.h>
! 36: #include <sys/systm.h>
! 37: #include <sys/proc.h>
! 38: #include <sys/file.h>
! 39: #include <sys/malloc.h>
! 40: #include <sys/mbuf.h>
! 41: #include <sys/domain.h>
! 42: #include <sys/kernel.h>
! 43: #include <sys/event.h>
! 44: #include <sys/protosw.h>
! 45: #include <sys/socket.h>
! 46: #include <sys/socketvar.h>
! 47: #include <sys/signalvar.h>
! 48: #include <sys/resourcevar.h>
! 49: #include <sys/pool.h>
! 50:
! 51: void filt_sordetach(struct knote *kn);
! 52: int filt_soread(struct knote *kn, long hint);
! 53: void filt_sowdetach(struct knote *kn);
! 54: int filt_sowrite(struct knote *kn, long hint);
! 55: int filt_solisten(struct knote *kn, long hint);
! 56:
! 57: struct filterops solisten_filtops =
! 58: { 1, NULL, filt_sordetach, filt_solisten };
! 59: struct filterops soread_filtops =
! 60: { 1, NULL, filt_sordetach, filt_soread };
! 61: struct filterops sowrite_filtops =
! 62: { 1, NULL, filt_sowdetach, filt_sowrite };
! 63:
! 64:
! 65: #ifndef SOMINCONN
! 66: #define SOMINCONN 80
! 67: #endif /* SOMINCONN */
! 68:
! 69: int somaxconn = SOMAXCONN;
! 70: int sominconn = SOMINCONN;
! 71:
! 72: struct pool socket_pool;
! 73:
! 74: void
! 75: soinit(void)
! 76: {
! 77:
! 78: pool_init(&socket_pool, sizeof(struct socket), 0, 0, 0, "sockpl", NULL);
! 79: }
! 80:
! 81: /*
! 82: * Socket operation routines.
! 83: * These routines are called by the routines in
! 84: * sys_socket.c or from a system process, and
! 85: * implement the semantics of socket operations by
! 86: * switching out to the protocol specific routines.
! 87: */
! 88: /*ARGSUSED*/
! 89: int
! 90: socreate(int dom, struct socket **aso, int type, int proto)
! 91: {
! 92: struct proc *p = curproc; /* XXX */
! 93: struct protosw *prp;
! 94: struct socket *so;
! 95: int error, s;
! 96:
! 97: if (proto)
! 98: prp = pffindproto(dom, proto, type);
! 99: else
! 100: prp = pffindtype(dom, type);
! 101: if (prp == NULL || prp->pr_usrreq == 0)
! 102: return (EPROTONOSUPPORT);
! 103: if (prp->pr_type != type)
! 104: return (EPROTOTYPE);
! 105: s = splsoftnet();
! 106: so = pool_get(&socket_pool, PR_WAITOK);
! 107: bzero(so, sizeof(*so));
! 108: TAILQ_INIT(&so->so_q0);
! 109: TAILQ_INIT(&so->so_q);
! 110: so->so_type = type;
! 111: if (p->p_ucred->cr_uid == 0)
! 112: so->so_state = SS_PRIV;
! 113: so->so_ruid = p->p_cred->p_ruid;
! 114: so->so_euid = p->p_ucred->cr_uid;
! 115: so->so_rgid = p->p_cred->p_rgid;
! 116: so->so_egid = p->p_ucred->cr_gid;
! 117: so->so_cpid = p->p_pid;
! 118: so->so_proto = prp;
! 119: error = (*prp->pr_usrreq)(so, PRU_ATTACH, NULL,
! 120: (struct mbuf *)(long)proto, NULL);
! 121: if (error) {
! 122: so->so_state |= SS_NOFDREF;
! 123: sofree(so);
! 124: splx(s);
! 125: return (error);
! 126: }
! 127: #ifdef COMPAT_SUNOS
! 128: {
! 129: extern struct emul emul_sunos;
! 130: if (p->p_emul == &emul_sunos && type == SOCK_DGRAM)
! 131: so->so_options |= SO_BROADCAST;
! 132: }
! 133: #endif
! 134: splx(s);
! 135: *aso = so;
! 136: return (0);
! 137: }
! 138:
! 139: int
! 140: sobind(struct socket *so, struct mbuf *nam)
! 141: {
! 142: int s = splsoftnet();
! 143: int error;
! 144:
! 145: error = (*so->so_proto->pr_usrreq)(so, PRU_BIND, NULL, nam, NULL);
! 146: splx(s);
! 147: return (error);
! 148: }
! 149:
! 150: int
! 151: solisten(struct socket *so, int backlog)
! 152: {
! 153: int s = splsoftnet(), error;
! 154:
! 155: error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, NULL, NULL, NULL);
! 156: if (error) {
! 157: splx(s);
! 158: return (error);
! 159: }
! 160: if (TAILQ_FIRST(&so->so_q) == NULL)
! 161: so->so_options |= SO_ACCEPTCONN;
! 162: if (backlog < 0 || backlog > somaxconn)
! 163: backlog = somaxconn;
! 164: if (backlog < sominconn)
! 165: backlog = sominconn;
! 166: so->so_qlimit = backlog;
! 167: splx(s);
! 168: return (0);
! 169: }
! 170:
! 171: /*
! 172: * Must be called at splsoftnet()
! 173: */
! 174:
! 175: void
! 176: sofree(struct socket *so)
! 177: {
! 178: splassert(IPL_SOFTNET);
! 179:
! 180: if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
! 181: return;
! 182: if (so->so_head) {
! 183: /*
! 184: * We must not decommission a socket that's on the accept(2)
! 185: * queue. If we do, then accept(2) may hang after select(2)
! 186: * indicated that the listening socket was ready.
! 187: */
! 188: if (!soqremque(so, 0))
! 189: return;
! 190: }
! 191: sbrelease(&so->so_snd);
! 192: sorflush(so);
! 193: pool_put(&socket_pool, so);
! 194: }
! 195:
! 196: /*
! 197: * Close a socket on last file table reference removal.
! 198: * Initiate disconnect if connected.
! 199: * Free socket when disconnect complete.
! 200: */
! 201: int
! 202: soclose(struct socket *so)
! 203: {
! 204: struct socket *so2;
! 205: int s = splsoftnet(); /* conservative */
! 206: int error = 0;
! 207:
! 208: if (so->so_options & SO_ACCEPTCONN) {
! 209: while ((so2 = TAILQ_FIRST(&so->so_q0)) != NULL) {
! 210: (void) soqremque(so2, 0);
! 211: (void) soabort(so2);
! 212: }
! 213: while ((so2 = TAILQ_FIRST(&so->so_q)) != NULL) {
! 214: (void) soqremque(so2, 1);
! 215: (void) soabort(so2);
! 216: }
! 217: }
! 218: if (so->so_pcb == 0)
! 219: goto discard;
! 220: if (so->so_state & SS_ISCONNECTED) {
! 221: if ((so->so_state & SS_ISDISCONNECTING) == 0) {
! 222: error = sodisconnect(so);
! 223: if (error)
! 224: goto drop;
! 225: }
! 226: if (so->so_options & SO_LINGER) {
! 227: if ((so->so_state & SS_ISDISCONNECTING) &&
! 228: (so->so_state & SS_NBIO))
! 229: goto drop;
! 230: while (so->so_state & SS_ISCONNECTED) {
! 231: error = tsleep(&so->so_timeo,
! 232: PSOCK | PCATCH, netcls,
! 233: so->so_linger * hz);
! 234: if (error)
! 235: break;
! 236: }
! 237: }
! 238: }
! 239: drop:
! 240: if (so->so_pcb) {
! 241: int error2 = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, NULL,
! 242: NULL, NULL);
! 243: if (error == 0)
! 244: error = error2;
! 245: }
! 246: discard:
! 247: if (so->so_state & SS_NOFDREF)
! 248: panic("soclose: NOFDREF");
! 249: so->so_state |= SS_NOFDREF;
! 250: sofree(so);
! 251: splx(s);
! 252: return (error);
! 253: }
! 254:
! 255: /*
! 256: * Must be called at splsoftnet.
! 257: */
! 258: int
! 259: soabort(struct socket *so)
! 260: {
! 261: splassert(IPL_SOFTNET);
! 262:
! 263: return (*so->so_proto->pr_usrreq)(so, PRU_ABORT, NULL, NULL, NULL);
! 264: }
! 265:
! 266: int
! 267: soaccept(struct socket *so, struct mbuf *nam)
! 268: {
! 269: int s = splsoftnet();
! 270: int error = 0;
! 271:
! 272: if ((so->so_state & SS_NOFDREF) == 0)
! 273: panic("soaccept: !NOFDREF");
! 274: so->so_state &= ~SS_NOFDREF;
! 275: if ((so->so_state & SS_ISDISCONNECTED) == 0 ||
! 276: (so->so_proto->pr_flags & PR_ABRTACPTDIS) == 0)
! 277: error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, NULL,
! 278: nam, NULL);
! 279: else
! 280: error = ECONNABORTED;
! 281: splx(s);
! 282: return (error);
! 283: }
! 284:
! 285: int
! 286: soconnect(struct socket *so, struct mbuf *nam)
! 287: {
! 288: int s;
! 289: int error;
! 290:
! 291: if (so->so_options & SO_ACCEPTCONN)
! 292: return (EOPNOTSUPP);
! 293: s = splsoftnet();
! 294: /*
! 295: * If protocol is connection-based, can only connect once.
! 296: * Otherwise, if connected, try to disconnect first.
! 297: * This allows user to disconnect by connecting to, e.g.,
! 298: * a null address.
! 299: */
! 300: if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
! 301: ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
! 302: (error = sodisconnect(so))))
! 303: error = EISCONN;
! 304: else
! 305: error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
! 306: NULL, nam, NULL);
! 307: splx(s);
! 308: return (error);
! 309: }
! 310:
! 311: int
! 312: soconnect2(struct socket *so1, struct socket *so2)
! 313: {
! 314: int s = splsoftnet();
! 315: int error;
! 316:
! 317: error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, NULL,
! 318: (struct mbuf *)so2, NULL);
! 319: splx(s);
! 320: return (error);
! 321: }
! 322:
! 323: int
! 324: sodisconnect(struct socket *so)
! 325: {
! 326: int s = splsoftnet();
! 327: int error;
! 328:
! 329: if ((so->so_state & SS_ISCONNECTED) == 0) {
! 330: error = ENOTCONN;
! 331: goto bad;
! 332: }
! 333: if (so->so_state & SS_ISDISCONNECTING) {
! 334: error = EALREADY;
! 335: goto bad;
! 336: }
! 337: error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, NULL, NULL,
! 338: NULL);
! 339: bad:
! 340: splx(s);
! 341: return (error);
! 342: }
! 343:
! 344: #define SBLOCKWAIT(f) (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK)
! 345: /*
! 346: * Send on a socket.
! 347: * If send must go all at once and message is larger than
! 348: * send buffering, then hard error.
! 349: * Lock against other senders.
! 350: * If must go all at once and not enough room now, then
! 351: * inform user that this would block and do nothing.
! 352: * Otherwise, if nonblocking, send as much as possible.
! 353: * The data to be sent is described by "uio" if nonzero,
! 354: * otherwise by the mbuf chain "top" (which must be null
! 355: * if uio is not). Data provided in mbuf chain must be small
! 356: * enough to send all at once.
! 357: *
! 358: * Returns nonzero on error, timeout or signal; callers
! 359: * must check for short counts if EINTR/ERESTART are returned.
! 360: * Data and control buffers are freed on return.
! 361: */
! 362: int
! 363: sosend(struct socket *so, struct mbuf *addr, struct uio *uio, struct mbuf *top,
! 364: struct mbuf *control, int flags)
! 365: {
! 366: struct mbuf **mp;
! 367: struct mbuf *m;
! 368: long space, len, mlen, clen = 0;
! 369: quad_t resid;
! 370: int error, s, dontroute;
! 371: int atomic = sosendallatonce(so) || top;
! 372:
! 373: if (uio)
! 374: resid = uio->uio_resid;
! 375: else
! 376: resid = top->m_pkthdr.len;
! 377: /*
! 378: * In theory resid should be unsigned (since uio->uio_resid is).
! 379: * However, space must be signed, as it might be less than 0
! 380: * if we over-committed, and we must use a signed comparison
! 381: * of space and resid. On the other hand, a negative resid
! 382: * causes us to loop sending 0-length segments to the protocol.
! 383: * MSG_EOR on a SOCK_STREAM socket is also invalid.
! 384: */
! 385: if (resid < 0 ||
! 386: (so->so_type == SOCK_STREAM && (flags & MSG_EOR))) {
! 387: error = EINVAL;
! 388: goto out;
! 389: }
! 390: dontroute =
! 391: (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
! 392: (so->so_proto->pr_flags & PR_ATOMIC);
! 393: if (uio && uio->uio_procp)
! 394: uio->uio_procp->p_stats->p_ru.ru_msgsnd++;
! 395: if (control)
! 396: clen = control->m_len;
! 397: #define snderr(errno) { error = errno; splx(s); goto release; }
! 398:
! 399: restart:
! 400: if ((error = sblock(&so->so_snd, SBLOCKWAIT(flags))) != 0)
! 401: goto out;
! 402: so->so_state |= SS_ISSENDING;
! 403: do {
! 404: s = splsoftnet();
! 405: if (so->so_state & SS_CANTSENDMORE)
! 406: snderr(EPIPE);
! 407: if (so->so_error) {
! 408: error = so->so_error;
! 409: so->so_error = 0;
! 410: splx(s);
! 411: goto release;
! 412: }
! 413: if ((so->so_state & SS_ISCONNECTED) == 0) {
! 414: if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
! 415: if ((so->so_state & SS_ISCONFIRMING) == 0 &&
! 416: !(resid == 0 && clen != 0))
! 417: snderr(ENOTCONN);
! 418: } else if (addr == 0)
! 419: snderr(EDESTADDRREQ);
! 420: }
! 421: space = sbspace(&so->so_snd);
! 422: if (flags & MSG_OOB)
! 423: space += 1024;
! 424: if ((atomic && resid > so->so_snd.sb_hiwat) ||
! 425: clen > so->so_snd.sb_hiwat)
! 426: snderr(EMSGSIZE);
! 427: if (space < resid + clen && uio &&
! 428: (atomic || space < so->so_snd.sb_lowat || space < clen)) {
! 429: if (so->so_state & SS_NBIO)
! 430: snderr(EWOULDBLOCK);
! 431: sbunlock(&so->so_snd);
! 432: error = sbwait(&so->so_snd);
! 433: so->so_state &= ~SS_ISSENDING;
! 434: splx(s);
! 435: if (error)
! 436: goto out;
! 437: goto restart;
! 438: }
! 439: splx(s);
! 440: mp = ⊤
! 441: space -= clen;
! 442: do {
! 443: if (uio == NULL) {
! 444: /*
! 445: * Data is prepackaged in "top".
! 446: */
! 447: resid = 0;
! 448: if (flags & MSG_EOR)
! 449: top->m_flags |= M_EOR;
! 450: } else do {
! 451: if (top == 0) {
! 452: MGETHDR(m, M_WAIT, MT_DATA);
! 453: mlen = MHLEN;
! 454: m->m_pkthdr.len = 0;
! 455: m->m_pkthdr.rcvif = (struct ifnet *)0;
! 456: } else {
! 457: MGET(m, M_WAIT, MT_DATA);
! 458: mlen = MLEN;
! 459: }
! 460: if (resid >= MINCLSIZE && space >= MCLBYTES) {
! 461: MCLGET(m, M_WAIT);
! 462: if ((m->m_flags & M_EXT) == 0)
! 463: goto nopages;
! 464: mlen = MCLBYTES;
! 465: if (atomic && top == 0) {
! 466: len = lmin(MCLBYTES - max_hdr, resid);
! 467: m->m_data += max_hdr;
! 468: } else
! 469: len = lmin(MCLBYTES, resid);
! 470: space -= len;
! 471: } else {
! 472: nopages:
! 473: len = lmin(lmin(mlen, resid), space);
! 474: space -= len;
! 475: /*
! 476: * For datagram protocols, leave room
! 477: * for protocol headers in first mbuf.
! 478: */
! 479: if (atomic && top == 0 && len < mlen)
! 480: MH_ALIGN(m, len);
! 481: }
! 482: error = uiomove(mtod(m, caddr_t), (int)len,
! 483: uio);
! 484: resid = uio->uio_resid;
! 485: m->m_len = len;
! 486: *mp = m;
! 487: top->m_pkthdr.len += len;
! 488: if (error)
! 489: goto release;
! 490: mp = &m->m_next;
! 491: if (resid <= 0) {
! 492: if (flags & MSG_EOR)
! 493: top->m_flags |= M_EOR;
! 494: break;
! 495: }
! 496: } while (space > 0 && atomic);
! 497: if (dontroute)
! 498: so->so_options |= SO_DONTROUTE;
! 499: s = splsoftnet(); /* XXX */
! 500: if (resid <= 0)
! 501: so->so_state &= ~SS_ISSENDING;
! 502: error = (*so->so_proto->pr_usrreq)(so,
! 503: (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
! 504: top, addr, control);
! 505: splx(s);
! 506: if (dontroute)
! 507: so->so_options &= ~SO_DONTROUTE;
! 508: clen = 0;
! 509: control = 0;
! 510: top = 0;
! 511: mp = ⊤
! 512: if (error)
! 513: goto release;
! 514: } while (resid && space > 0);
! 515: } while (resid);
! 516:
! 517: release:
! 518: so->so_state &= ~SS_ISSENDING;
! 519: sbunlock(&so->so_snd);
! 520: out:
! 521: if (top)
! 522: m_freem(top);
! 523: if (control)
! 524: m_freem(control);
! 525: return (error);
! 526: }
! 527:
! 528: /*
! 529: * Implement receive operations on a socket.
! 530: * We depend on the way that records are added to the sockbuf
! 531: * by sbappend*. In particular, each record (mbufs linked through m_next)
! 532: * must begin with an address if the protocol so specifies,
! 533: * followed by an optional mbuf or mbufs containing ancillary data,
! 534: * and then zero or more mbufs of data.
! 535: * In order to avoid blocking network interrupts for the entire time here,
! 536: * we splx() while doing the actual copy to user space.
! 537: * Although the sockbuf is locked, new data may still be appended,
! 538: * and thus we must maintain consistency of the sockbuf during that time.
! 539: *
! 540: * The caller may receive the data as a single mbuf chain by supplying
! 541: * an mbuf **mp0 for use in returning the chain. The uio is then used
! 542: * only for the count in uio_resid.
! 543: */
! 544: int
! 545: soreceive(struct socket *so, struct mbuf **paddr, struct uio *uio,
! 546: struct mbuf **mp0, struct mbuf **controlp, int *flagsp)
! 547: {
! 548: struct mbuf *m, **mp;
! 549: int flags, len, error, s, offset;
! 550: struct protosw *pr = so->so_proto;
! 551: struct mbuf *nextrecord;
! 552: int moff, type = 0;
! 553: size_t orig_resid = uio->uio_resid;
! 554: int uio_error = 0;
! 555: int resid;
! 556:
! 557: mp = mp0;
! 558: if (paddr)
! 559: *paddr = 0;
! 560: if (controlp)
! 561: *controlp = 0;
! 562: if (flagsp)
! 563: flags = *flagsp &~ MSG_EOR;
! 564: else
! 565: flags = 0;
! 566: if (so->so_state & SS_NBIO)
! 567: flags |= MSG_DONTWAIT;
! 568: if (flags & MSG_OOB) {
! 569: m = m_get(M_WAIT, MT_DATA);
! 570: error = (*pr->pr_usrreq)(so, PRU_RCVOOB, m,
! 571: (struct mbuf *)(long)(flags & MSG_PEEK), NULL);
! 572: if (error)
! 573: goto bad;
! 574: do {
! 575: error = uiomove(mtod(m, caddr_t),
! 576: (int) min(uio->uio_resid, m->m_len), uio);
! 577: m = m_free(m);
! 578: } while (uio->uio_resid && error == 0 && m);
! 579: bad:
! 580: if (m)
! 581: m_freem(m);
! 582: return (error);
! 583: }
! 584: if (mp)
! 585: *mp = NULL;
! 586: if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)
! 587: (*pr->pr_usrreq)(so, PRU_RCVD, NULL, NULL, NULL);
! 588:
! 589: restart:
! 590: if ((error = sblock(&so->so_rcv, SBLOCKWAIT(flags))) != 0)
! 591: return (error);
! 592: s = splsoftnet();
! 593:
! 594: m = so->so_rcv.sb_mb;
! 595: /*
! 596: * If we have less data than requested, block awaiting more
! 597: * (subject to any timeout) if:
! 598: * 1. the current count is less than the low water mark,
! 599: * 2. MSG_WAITALL is set, and it is possible to do the entire
! 600: * receive operation at once if we block (resid <= hiwat), or
! 601: * 3. MSG_DONTWAIT is not set.
! 602: * If MSG_WAITALL is set but resid is larger than the receive buffer,
! 603: * we have to do the receive in sections, and thus risk returning
! 604: * a short count if a timeout or signal occurs after we start.
! 605: */
! 606: if (m == NULL || (((flags & MSG_DONTWAIT) == 0 &&
! 607: so->so_rcv.sb_cc < uio->uio_resid) &&
! 608: (so->so_rcv.sb_cc < so->so_rcv.sb_lowat ||
! 609: ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) &&
! 610: m->m_nextpkt == NULL && (pr->pr_flags & PR_ATOMIC) == 0)) {
! 611: #ifdef DIAGNOSTIC
! 612: if (m == NULL && so->so_rcv.sb_cc)
! 613: panic("receive 1");
! 614: #endif
! 615: if (so->so_error) {
! 616: if (m)
! 617: goto dontblock;
! 618: error = so->so_error;
! 619: if ((flags & MSG_PEEK) == 0)
! 620: so->so_error = 0;
! 621: goto release;
! 622: }
! 623: if (so->so_state & SS_CANTRCVMORE) {
! 624: if (m)
! 625: goto dontblock;
! 626: else
! 627: goto release;
! 628: }
! 629: for (; m; m = m->m_next)
! 630: if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) {
! 631: m = so->so_rcv.sb_mb;
! 632: goto dontblock;
! 633: }
! 634: if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
! 635: (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
! 636: error = ENOTCONN;
! 637: goto release;
! 638: }
! 639: if (uio->uio_resid == 0 && controlp == NULL)
! 640: goto release;
! 641: if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) {
! 642: error = EWOULDBLOCK;
! 643: goto release;
! 644: }
! 645: SBLASTRECORDCHK(&so->so_rcv, "soreceive sbwait 1");
! 646: SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 1");
! 647: sbunlock(&so->so_rcv);
! 648: error = sbwait(&so->so_rcv);
! 649: splx(s);
! 650: if (error)
! 651: return (error);
! 652: goto restart;
! 653: }
! 654: dontblock:
! 655: /*
! 656: * On entry here, m points to the first record of the socket buffer.
! 657: * While we process the initial mbufs containing address and control
! 658: * info, we save a copy of m->m_nextpkt into nextrecord.
! 659: */
! 660: if (uio->uio_procp)
! 661: uio->uio_procp->p_stats->p_ru.ru_msgrcv++;
! 662: KASSERT(m == so->so_rcv.sb_mb);
! 663: SBLASTRECORDCHK(&so->so_rcv, "soreceive 1");
! 664: SBLASTMBUFCHK(&so->so_rcv, "soreceive 1");
! 665: nextrecord = m->m_nextpkt;
! 666: if (pr->pr_flags & PR_ADDR) {
! 667: #ifdef DIAGNOSTIC
! 668: if (m->m_type != MT_SONAME)
! 669: panic("receive 1a");
! 670: #endif
! 671: orig_resid = 0;
! 672: if (flags & MSG_PEEK) {
! 673: if (paddr)
! 674: *paddr = m_copy(m, 0, m->m_len);
! 675: m = m->m_next;
! 676: } else {
! 677: sbfree(&so->so_rcv, m);
! 678: if (paddr) {
! 679: *paddr = m;
! 680: so->so_rcv.sb_mb = m->m_next;
! 681: m->m_next = 0;
! 682: m = so->so_rcv.sb_mb;
! 683: } else {
! 684: MFREE(m, so->so_rcv.sb_mb);
! 685: m = so->so_rcv.sb_mb;
! 686: }
! 687: }
! 688: }
! 689: while (m && m->m_type == MT_CONTROL && error == 0) {
! 690: if (flags & MSG_PEEK) {
! 691: if (controlp)
! 692: *controlp = m_copy(m, 0, m->m_len);
! 693: m = m->m_next;
! 694: } else {
! 695: sbfree(&so->so_rcv, m);
! 696: if (controlp) {
! 697: if (pr->pr_domain->dom_externalize &&
! 698: mtod(m, struct cmsghdr *)->cmsg_type ==
! 699: SCM_RIGHTS)
! 700: error = (*pr->pr_domain->dom_externalize)(m);
! 701: *controlp = m;
! 702: so->so_rcv.sb_mb = m->m_next;
! 703: m->m_next = 0;
! 704: m = so->so_rcv.sb_mb;
! 705: } else {
! 706: /*
! 707: * Dispose of any SCM_RIGHTS message that went
! 708: * through the read path rather than recv.
! 709: */
! 710: if (pr->pr_domain->dom_dispose &&
! 711: mtod(m, struct cmsghdr *)->cmsg_type == SCM_RIGHTS)
! 712: pr->pr_domain->dom_dispose(m);
! 713: MFREE(m, so->so_rcv.sb_mb);
! 714: m = so->so_rcv.sb_mb;
! 715: }
! 716: }
! 717: if (controlp) {
! 718: orig_resid = 0;
! 719: controlp = &(*controlp)->m_next;
! 720: }
! 721: }
! 722:
! 723: /*
! 724: * If m is non-NULL, we have some data to read. From now on,
! 725: * make sure to keep sb_lastrecord consistent when working on
! 726: * the last packet on the chain (nextrecord == NULL) and we
! 727: * change m->m_nextpkt.
! 728: */
! 729: if (m) {
! 730: if ((flags & MSG_PEEK) == 0) {
! 731: m->m_nextpkt = nextrecord;
! 732: /*
! 733: * If nextrecord == NULL (this is a single chain),
! 734: * then sb_lastrecord may not be valid here if m
! 735: * was changed earlier.
! 736: */
! 737: if (nextrecord == NULL) {
! 738: KASSERT(so->so_rcv.sb_mb == m);
! 739: so->so_rcv.sb_lastrecord = m;
! 740: }
! 741: }
! 742: type = m->m_type;
! 743: if (type == MT_OOBDATA)
! 744: flags |= MSG_OOB;
! 745: if (m->m_flags & M_BCAST)
! 746: flags |= MSG_BCAST;
! 747: if (m->m_flags & M_MCAST)
! 748: flags |= MSG_MCAST;
! 749: } else {
! 750: if ((flags & MSG_PEEK) == 0) {
! 751: KASSERT(so->so_rcv.sb_mb == m);
! 752: so->so_rcv.sb_mb = nextrecord;
! 753: SB_EMPTY_FIXUP(&so->so_rcv);
! 754: }
! 755: }
! 756: SBLASTRECORDCHK(&so->so_rcv, "soreceive 2");
! 757: SBLASTMBUFCHK(&so->so_rcv, "soreceive 2");
! 758:
! 759: moff = 0;
! 760: offset = 0;
! 761: while (m && uio->uio_resid > 0 && error == 0) {
! 762: if (m->m_type == MT_OOBDATA) {
! 763: if (type != MT_OOBDATA)
! 764: break;
! 765: } else if (type == MT_OOBDATA)
! 766: break;
! 767: #ifdef DIAGNOSTIC
! 768: else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
! 769: panic("receive 3");
! 770: #endif
! 771: so->so_state &= ~SS_RCVATMARK;
! 772: len = uio->uio_resid;
! 773: if (so->so_oobmark && len > so->so_oobmark - offset)
! 774: len = so->so_oobmark - offset;
! 775: if (len > m->m_len - moff)
! 776: len = m->m_len - moff;
! 777: /*
! 778: * If mp is set, just pass back the mbufs.
! 779: * Otherwise copy them out via the uio, then free.
! 780: * Sockbuf must be consistent here (points to current mbuf,
! 781: * it points to next record) when we drop priority;
! 782: * we must note any additions to the sockbuf when we
! 783: * block interrupts again.
! 784: */
! 785: if (mp == NULL && uio_error == 0) {
! 786: SBLASTRECORDCHK(&so->so_rcv, "soreceive uiomove");
! 787: SBLASTMBUFCHK(&so->so_rcv, "soreceive uiomove");
! 788: resid = uio->uio_resid;
! 789: splx(s);
! 790: uio_error =
! 791: uiomove(mtod(m, caddr_t) + moff, (int)len,
! 792: uio);
! 793: s = splsoftnet();
! 794: if (uio_error)
! 795: uio->uio_resid = resid - len;
! 796: } else
! 797: uio->uio_resid -= len;
! 798: if (len == m->m_len - moff) {
! 799: if (m->m_flags & M_EOR)
! 800: flags |= MSG_EOR;
! 801: if (flags & MSG_PEEK) {
! 802: m = m->m_next;
! 803: moff = 0;
! 804: } else {
! 805: nextrecord = m->m_nextpkt;
! 806: sbfree(&so->so_rcv, m);
! 807: if (mp) {
! 808: *mp = m;
! 809: mp = &m->m_next;
! 810: so->so_rcv.sb_mb = m = m->m_next;
! 811: *mp = NULL;
! 812: } else {
! 813: MFREE(m, so->so_rcv.sb_mb);
! 814: m = so->so_rcv.sb_mb;
! 815: }
! 816: /*
! 817: * If m != NULL, we also know that
! 818: * so->so_rcv.sb_mb != NULL.
! 819: */
! 820: KASSERT(so->so_rcv.sb_mb == m);
! 821: if (m) {
! 822: m->m_nextpkt = nextrecord;
! 823: if (nextrecord == NULL)
! 824: so->so_rcv.sb_lastrecord = m;
! 825: } else {
! 826: so->so_rcv.sb_mb = nextrecord;
! 827: SB_EMPTY_FIXUP(&so->so_rcv);
! 828: }
! 829: SBLASTRECORDCHK(&so->so_rcv, "soreceive 3");
! 830: SBLASTMBUFCHK(&so->so_rcv, "soreceive 3");
! 831: }
! 832: } else {
! 833: if (flags & MSG_PEEK)
! 834: moff += len;
! 835: else {
! 836: if (mp)
! 837: *mp = m_copym(m, 0, len, M_WAIT);
! 838: m->m_data += len;
! 839: m->m_len -= len;
! 840: so->so_rcv.sb_cc -= len;
! 841: so->so_rcv.sb_datacc -= len;
! 842: }
! 843: }
! 844: if (so->so_oobmark) {
! 845: if ((flags & MSG_PEEK) == 0) {
! 846: so->so_oobmark -= len;
! 847: if (so->so_oobmark == 0) {
! 848: so->so_state |= SS_RCVATMARK;
! 849: break;
! 850: }
! 851: } else {
! 852: offset += len;
! 853: if (offset == so->so_oobmark)
! 854: break;
! 855: }
! 856: }
! 857: if (flags & MSG_EOR)
! 858: break;
! 859: /*
! 860: * If the MSG_WAITALL flag is set (for non-atomic socket),
! 861: * we must not quit until "uio->uio_resid == 0" or an error
! 862: * termination. If a signal/timeout occurs, return
! 863: * with a short count but without error.
! 864: * Keep sockbuf locked against other readers.
! 865: */
! 866: while (flags & MSG_WAITALL && m == NULL && uio->uio_resid > 0 &&
! 867: !sosendallatonce(so) && !nextrecord) {
! 868: if (so->so_error || so->so_state & SS_CANTRCVMORE)
! 869: break;
! 870: SBLASTRECORDCHK(&so->so_rcv, "soreceive sbwait 2");
! 871: SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 2");
! 872: error = sbwait(&so->so_rcv);
! 873: if (error) {
! 874: sbunlock(&so->so_rcv);
! 875: splx(s);
! 876: return (0);
! 877: }
! 878: if ((m = so->so_rcv.sb_mb) != NULL)
! 879: nextrecord = m->m_nextpkt;
! 880: }
! 881: }
! 882:
! 883: if (m && pr->pr_flags & PR_ATOMIC) {
! 884: flags |= MSG_TRUNC;
! 885: if ((flags & MSG_PEEK) == 0)
! 886: (void) sbdroprecord(&so->so_rcv);
! 887: }
! 888: if ((flags & MSG_PEEK) == 0) {
! 889: if (m == NULL) {
! 890: /*
! 891: * First part is an inline SB_EMPTY_FIXUP(). Second
! 892: * part makes sure sb_lastrecord is up-to-date if
! 893: * there is still data in the socket buffer.
! 894: */
! 895: so->so_rcv.sb_mb = nextrecord;
! 896: if (so->so_rcv.sb_mb == NULL) {
! 897: so->so_rcv.sb_mbtail = NULL;
! 898: so->so_rcv.sb_lastrecord = NULL;
! 899: } else if (nextrecord->m_nextpkt == NULL)
! 900: so->so_rcv.sb_lastrecord = nextrecord;
! 901: }
! 902: SBLASTRECORDCHK(&so->so_rcv, "soreceive 4");
! 903: SBLASTMBUFCHK(&so->so_rcv, "soreceive 4");
! 904: if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
! 905: (*pr->pr_usrreq)(so, PRU_RCVD, NULL,
! 906: (struct mbuf *)(long)flags, NULL);
! 907: }
! 908: if (orig_resid == uio->uio_resid && orig_resid &&
! 909: (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) {
! 910: sbunlock(&so->so_rcv);
! 911: splx(s);
! 912: goto restart;
! 913: }
! 914:
! 915: if (uio_error)
! 916: error = uio_error;
! 917:
! 918: if (flagsp)
! 919: *flagsp |= flags;
! 920: release:
! 921: sbunlock(&so->so_rcv);
! 922: splx(s);
! 923: return (error);
! 924: }
! 925:
! 926: int
! 927: soshutdown(struct socket *so, int how)
! 928: {
! 929: struct protosw *pr = so->so_proto;
! 930:
! 931: switch (how) {
! 932: case SHUT_RD:
! 933: case SHUT_RDWR:
! 934: sorflush(so);
! 935: if (how == SHUT_RD)
! 936: return (0);
! 937: /* FALLTHROUGH */
! 938: case SHUT_WR:
! 939: return (*pr->pr_usrreq)(so, PRU_SHUTDOWN, NULL, NULL, NULL);
! 940: default:
! 941: return (EINVAL);
! 942: }
! 943: }
! 944:
! 945: void
! 946: sorflush(struct socket *so)
! 947: {
! 948: struct sockbuf *sb = &so->so_rcv;
! 949: struct protosw *pr = so->so_proto;
! 950: int s;
! 951: struct sockbuf asb;
! 952:
! 953: sb->sb_flags |= SB_NOINTR;
! 954: (void) sblock(sb, M_WAITOK);
! 955: s = splnet();
! 956: socantrcvmore(so);
! 957: sbunlock(sb);
! 958: asb = *sb;
! 959: bzero(sb, sizeof (*sb));
! 960: /* XXX - the bzero stumps all over so_rcv */
! 961: if (asb.sb_flags & SB_KNOTE) {
! 962: sb->sb_sel.si_note = asb.sb_sel.si_note;
! 963: sb->sb_flags = SB_KNOTE;
! 964: }
! 965: splx(s);
! 966: if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
! 967: (*pr->pr_domain->dom_dispose)(asb.sb_mb);
! 968: sbrelease(&asb);
! 969: }
! 970:
! 971: int
! 972: sosetopt(struct socket *so, int level, int optname, struct mbuf *m0)
! 973: {
! 974: int error = 0;
! 975: struct mbuf *m = m0;
! 976:
! 977: if (level != SOL_SOCKET) {
! 978: if (so->so_proto && so->so_proto->pr_ctloutput)
! 979: return ((*so->so_proto->pr_ctloutput)
! 980: (PRCO_SETOPT, so, level, optname, &m0));
! 981: error = ENOPROTOOPT;
! 982: } else {
! 983: switch (optname) {
! 984:
! 985: case SO_LINGER:
! 986: if (m == NULL || m->m_len != sizeof (struct linger) ||
! 987: mtod(m, struct linger *)->l_linger < 0 ||
! 988: mtod(m, struct linger *)->l_linger > SHRT_MAX) {
! 989: error = EINVAL;
! 990: goto bad;
! 991: }
! 992: so->so_linger = mtod(m, struct linger *)->l_linger;
! 993: /* FALLTHROUGH */
! 994:
! 995: case SO_DEBUG:
! 996: case SO_KEEPALIVE:
! 997: case SO_DONTROUTE:
! 998: case SO_USELOOPBACK:
! 999: case SO_BROADCAST:
! 1000: case SO_REUSEADDR:
! 1001: case SO_REUSEPORT:
! 1002: case SO_OOBINLINE:
! 1003: case SO_JUMBO:
! 1004: if (m == NULL || m->m_len < sizeof (int)) {
! 1005: error = EINVAL;
! 1006: goto bad;
! 1007: }
! 1008: if (*mtod(m, int *))
! 1009: so->so_options |= optname;
! 1010: else
! 1011: so->so_options &= ~optname;
! 1012: break;
! 1013:
! 1014: case SO_SNDBUF:
! 1015: case SO_RCVBUF:
! 1016: case SO_SNDLOWAT:
! 1017: case SO_RCVLOWAT:
! 1018: {
! 1019: u_long cnt;
! 1020:
! 1021: if (m == NULL || m->m_len < sizeof (int)) {
! 1022: error = EINVAL;
! 1023: goto bad;
! 1024: }
! 1025: cnt = *mtod(m, int *);
! 1026: if ((long)cnt <= 0)
! 1027: cnt = 1;
! 1028: switch (optname) {
! 1029:
! 1030: case SO_SNDBUF:
! 1031: if (sbcheckreserve(cnt, so->so_snd.sb_hiwat) ||
! 1032: sbreserve(&so->so_snd, cnt) == 0) {
! 1033: error = ENOBUFS;
! 1034: goto bad;
! 1035: }
! 1036: break;
! 1037:
! 1038: case SO_RCVBUF:
! 1039: if (sbcheckreserve(cnt, so->so_rcv.sb_hiwat) ||
! 1040: sbreserve(&so->so_rcv, cnt) == 0) {
! 1041: error = ENOBUFS;
! 1042: goto bad;
! 1043: }
! 1044: break;
! 1045:
! 1046: case SO_SNDLOWAT:
! 1047: so->so_snd.sb_lowat = (cnt > so->so_snd.sb_hiwat) ?
! 1048: so->so_snd.sb_hiwat : cnt;
! 1049: break;
! 1050: case SO_RCVLOWAT:
! 1051: so->so_rcv.sb_lowat = (cnt > so->so_rcv.sb_hiwat) ?
! 1052: so->so_rcv.sb_hiwat : cnt;
! 1053: break;
! 1054: }
! 1055: break;
! 1056: }
! 1057:
! 1058: case SO_SNDTIMEO:
! 1059: case SO_RCVTIMEO:
! 1060: {
! 1061: struct timeval *tv;
! 1062: short val;
! 1063:
! 1064: if (m == NULL || m->m_len < sizeof (*tv)) {
! 1065: error = EINVAL;
! 1066: goto bad;
! 1067: }
! 1068: tv = mtod(m, struct timeval *);
! 1069: if (tv->tv_sec > (SHRT_MAX - tv->tv_usec / tick) / hz) {
! 1070: error = EDOM;
! 1071: goto bad;
! 1072: }
! 1073: val = tv->tv_sec * hz + tv->tv_usec / tick;
! 1074: if (val == 0 && tv->tv_usec != 0)
! 1075: val = 1;
! 1076:
! 1077: switch (optname) {
! 1078:
! 1079: case SO_SNDTIMEO:
! 1080: so->so_snd.sb_timeo = val;
! 1081: break;
! 1082: case SO_RCVTIMEO:
! 1083: so->so_rcv.sb_timeo = val;
! 1084: break;
! 1085: }
! 1086: break;
! 1087: }
! 1088:
! 1089: default:
! 1090: error = ENOPROTOOPT;
! 1091: break;
! 1092: }
! 1093: if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) {
! 1094: (void) ((*so->so_proto->pr_ctloutput)
! 1095: (PRCO_SETOPT, so, level, optname, &m0));
! 1096: m = NULL; /* freed by protocol */
! 1097: }
! 1098: }
! 1099: bad:
! 1100: if (m)
! 1101: (void) m_free(m);
! 1102: return (error);
! 1103: }
! 1104:
! 1105: int
! 1106: sogetopt(struct socket *so, int level, int optname, struct mbuf **mp)
! 1107: {
! 1108: struct mbuf *m;
! 1109:
! 1110: if (level != SOL_SOCKET) {
! 1111: if (so->so_proto && so->so_proto->pr_ctloutput) {
! 1112: return ((*so->so_proto->pr_ctloutput)
! 1113: (PRCO_GETOPT, so, level, optname, mp));
! 1114: } else
! 1115: return (ENOPROTOOPT);
! 1116: } else {
! 1117: m = m_get(M_WAIT, MT_SOOPTS);
! 1118: m->m_len = sizeof (int);
! 1119:
! 1120: switch (optname) {
! 1121:
! 1122: case SO_LINGER:
! 1123: m->m_len = sizeof (struct linger);
! 1124: mtod(m, struct linger *)->l_onoff =
! 1125: so->so_options & SO_LINGER;
! 1126: mtod(m, struct linger *)->l_linger = so->so_linger;
! 1127: break;
! 1128:
! 1129: case SO_USELOOPBACK:
! 1130: case SO_DONTROUTE:
! 1131: case SO_DEBUG:
! 1132: case SO_KEEPALIVE:
! 1133: case SO_REUSEADDR:
! 1134: case SO_REUSEPORT:
! 1135: case SO_BROADCAST:
! 1136: case SO_OOBINLINE:
! 1137: case SO_JUMBO:
! 1138: *mtod(m, int *) = so->so_options & optname;
! 1139: break;
! 1140:
! 1141: case SO_TYPE:
! 1142: *mtod(m, int *) = so->so_type;
! 1143: break;
! 1144:
! 1145: case SO_ERROR:
! 1146: *mtod(m, int *) = so->so_error;
! 1147: so->so_error = 0;
! 1148: break;
! 1149:
! 1150: case SO_SNDBUF:
! 1151: *mtod(m, int *) = so->so_snd.sb_hiwat;
! 1152: break;
! 1153:
! 1154: case SO_RCVBUF:
! 1155: *mtod(m, int *) = so->so_rcv.sb_hiwat;
! 1156: break;
! 1157:
! 1158: case SO_SNDLOWAT:
! 1159: *mtod(m, int *) = so->so_snd.sb_lowat;
! 1160: break;
! 1161:
! 1162: case SO_RCVLOWAT:
! 1163: *mtod(m, int *) = so->so_rcv.sb_lowat;
! 1164: break;
! 1165:
! 1166: case SO_SNDTIMEO:
! 1167: case SO_RCVTIMEO:
! 1168: {
! 1169: int val = (optname == SO_SNDTIMEO ?
! 1170: so->so_snd.sb_timeo : so->so_rcv.sb_timeo);
! 1171:
! 1172: m->m_len = sizeof(struct timeval);
! 1173: mtod(m, struct timeval *)->tv_sec = val / hz;
! 1174: mtod(m, struct timeval *)->tv_usec =
! 1175: (val % hz) * tick;
! 1176: break;
! 1177: }
! 1178:
! 1179: default:
! 1180: (void)m_free(m);
! 1181: return (ENOPROTOOPT);
! 1182: }
! 1183: *mp = m;
! 1184: return (0);
! 1185: }
! 1186: }
! 1187:
! 1188: void
! 1189: sohasoutofband(struct socket *so)
! 1190: {
! 1191: csignal(so->so_pgid, SIGURG, so->so_siguid, so->so_sigeuid);
! 1192: selwakeup(&so->so_rcv.sb_sel);
! 1193: }
! 1194:
! 1195: int
! 1196: soo_kqfilter(struct file *fp, struct knote *kn)
! 1197: {
! 1198: struct socket *so = (struct socket *)kn->kn_fp->f_data;
! 1199: struct sockbuf *sb;
! 1200: int s;
! 1201:
! 1202: switch (kn->kn_filter) {
! 1203: case EVFILT_READ:
! 1204: if (so->so_options & SO_ACCEPTCONN)
! 1205: kn->kn_fop = &solisten_filtops;
! 1206: else
! 1207: kn->kn_fop = &soread_filtops;
! 1208: sb = &so->so_rcv;
! 1209: break;
! 1210: case EVFILT_WRITE:
! 1211: kn->kn_fop = &sowrite_filtops;
! 1212: sb = &so->so_snd;
! 1213: break;
! 1214: default:
! 1215: return (1);
! 1216: }
! 1217:
! 1218: s = splnet();
! 1219: SLIST_INSERT_HEAD(&sb->sb_sel.si_note, kn, kn_selnext);
! 1220: sb->sb_flags |= SB_KNOTE;
! 1221: splx(s);
! 1222: return (0);
! 1223: }
! 1224:
! 1225: void
! 1226: filt_sordetach(struct knote *kn)
! 1227: {
! 1228: struct socket *so = (struct socket *)kn->kn_fp->f_data;
! 1229: int s = splnet();
! 1230:
! 1231: SLIST_REMOVE(&so->so_rcv.sb_sel.si_note, kn, knote, kn_selnext);
! 1232: if (SLIST_EMPTY(&so->so_rcv.sb_sel.si_note))
! 1233: so->so_rcv.sb_flags &= ~SB_KNOTE;
! 1234: splx(s);
! 1235: }
! 1236:
! 1237: /*ARGSUSED*/
! 1238: int
! 1239: filt_soread(struct knote *kn, long hint)
! 1240: {
! 1241: struct socket *so = (struct socket *)kn->kn_fp->f_data;
! 1242:
! 1243: kn->kn_data = so->so_rcv.sb_cc;
! 1244: if (so->so_state & SS_CANTRCVMORE) {
! 1245: kn->kn_flags |= EV_EOF;
! 1246: kn->kn_fflags = so->so_error;
! 1247: return (1);
! 1248: }
! 1249: if (so->so_error) /* temporary udp error */
! 1250: return (1);
! 1251: if (kn->kn_sfflags & NOTE_LOWAT)
! 1252: return (kn->kn_data >= kn->kn_sdata);
! 1253: return (kn->kn_data >= so->so_rcv.sb_lowat);
! 1254: }
! 1255:
! 1256: void
! 1257: filt_sowdetach(struct knote *kn)
! 1258: {
! 1259: struct socket *so = (struct socket *)kn->kn_fp->f_data;
! 1260: int s = splnet();
! 1261:
! 1262: SLIST_REMOVE(&so->so_snd.sb_sel.si_note, kn, knote, kn_selnext);
! 1263: if (SLIST_EMPTY(&so->so_snd.sb_sel.si_note))
! 1264: so->so_snd.sb_flags &= ~SB_KNOTE;
! 1265: splx(s);
! 1266: }
! 1267:
! 1268: /*ARGSUSED*/
! 1269: int
! 1270: filt_sowrite(struct knote *kn, long hint)
! 1271: {
! 1272: struct socket *so = (struct socket *)kn->kn_fp->f_data;
! 1273:
! 1274: kn->kn_data = sbspace(&so->so_snd);
! 1275: if (so->so_state & SS_CANTSENDMORE) {
! 1276: kn->kn_flags |= EV_EOF;
! 1277: kn->kn_fflags = so->so_error;
! 1278: return (1);
! 1279: }
! 1280: if (so->so_error) /* temporary udp error */
! 1281: return (1);
! 1282: if (((so->so_state & SS_ISCONNECTED) == 0) &&
! 1283: (so->so_proto->pr_flags & PR_CONNREQUIRED))
! 1284: return (0);
! 1285: if (kn->kn_sfflags & NOTE_LOWAT)
! 1286: return (kn->kn_data >= kn->kn_sdata);
! 1287: return (kn->kn_data >= so->so_snd.sb_lowat);
! 1288: }
! 1289:
! 1290: /*ARGSUSED*/
! 1291: int
! 1292: filt_solisten(struct knote *kn, long hint)
! 1293: {
! 1294: struct socket *so = (struct socket *)kn->kn_fp->f_data;
! 1295:
! 1296: kn->kn_data = so->so_qlen;
! 1297: return (so->so_qlen != 0);
! 1298: }
CVSweb