| version 1.159, 2008/04/14 15:42:20 |
version 1.159.2.2, 2008/06/04 02:05:40 |
|
|
| * 2. Redistributions in binary form must reproduce the above copyright |
* 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
* notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
* documentation and/or other materials provided with the distribution. |
| * 3. All advertising materials mentioning features or use of this software |
|
| * must display the following acknowledgement: |
|
| * This product includes software developed by the NetBSD |
|
| * Foundation, Inc. and its contributors. |
|
| * 4. Neither the name of The NetBSD Foundation nor the names of its |
|
| * contributors may be used to endorse or promote products derived |
|
| * from this software without specific prior written permission. |
|
| * |
* |
| * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
| * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
| Line 76 __KERNEL_RCSID(0, "$NetBSD$"); |
|
| Line 69 __KERNEL_RCSID(0, "$NetBSD$"); |
|
| #include "opt_sosend_loan.h" |
#include "opt_sosend_loan.h" |
| #include "opt_mbuftrace.h" |
#include "opt_mbuftrace.h" |
| #include "opt_somaxkva.h" |
#include "opt_somaxkva.h" |
| |
#include "opt_multiprocessor.h" /* XXX */ |
| |
|
| #include <sys/param.h> |
#include <sys/param.h> |
| #include <sys/systm.h> |
#include <sys/systm.h> |
| Line 91 __KERNEL_RCSID(0, "$NetBSD$"); |
|
| Line 85 __KERNEL_RCSID(0, "$NetBSD$"); |
|
| #include <sys/socketvar.h> |
#include <sys/socketvar.h> |
| #include <sys/signalvar.h> |
#include <sys/signalvar.h> |
| #include <sys/resourcevar.h> |
#include <sys/resourcevar.h> |
| #include <sys/pool.h> |
|
| #include <sys/event.h> |
#include <sys/event.h> |
| #include <sys/poll.h> |
#include <sys/poll.h> |
| #include <sys/kauth.h> |
#include <sys/kauth.h> |
| Line 100 __KERNEL_RCSID(0, "$NetBSD$"); |
|
| Line 93 __KERNEL_RCSID(0, "$NetBSD$"); |
|
| |
|
| #include <uvm/uvm.h> |
#include <uvm/uvm.h> |
| |
|
| POOL_INIT(socket_pool, sizeof(struct socket), 0, 0, 0, "sockpl", NULL, |
|
| IPL_SOFTNET); |
|
| |
|
| MALLOC_DEFINE(M_SOOPTS, "soopts", "socket options"); |
MALLOC_DEFINE(M_SOOPTS, "soopts", "socket options"); |
| MALLOC_DEFINE(M_SONAME, "soname", "socket name"); |
MALLOC_DEFINE(M_SONAME, "soname", "socket name"); |
| |
|
| Line 110 extern const struct fileops socketops; |
|
| Line 100 extern const struct fileops socketops; |
|
| |
|
| extern int somaxconn; /* patchable (XXX sysctl) */ |
extern int somaxconn; /* patchable (XXX sysctl) */ |
| int somaxconn = SOMAXCONN; |
int somaxconn = SOMAXCONN; |
| |
kmutex_t *softnet_lock; |
| |
|
| #ifdef SOSEND_COUNTERS |
#ifdef SOSEND_COUNTERS |
| #include <sys/device.h> |
#include <sys/device.h> |
| Line 137 EVCNT_ATTACH_STATIC(sosend_kvalimit); |
|
| Line 128 EVCNT_ATTACH_STATIC(sosend_kvalimit); |
|
| |
|
| static struct callback_entry sokva_reclaimerentry; |
static struct callback_entry sokva_reclaimerentry; |
| |
|
| #ifdef SOSEND_NO_LOAN |
#if defined(SOSEND_NO_LOAN) || defined(MULTIPROCESSOR) |
| int sock_loan_thresh = -1; |
int sock_loan_thresh = -1; |
| #else |
#else |
| int sock_loan_thresh = 4096; |
int sock_loan_thresh = 4096; |
| Line 277 sodopendfree(void) |
|
| Line 268 sodopendfree(void) |
|
| { |
{ |
| size_t rv; |
size_t rv; |
| |
|
| |
if (__predict_true(so_pendfree == NULL)) |
| |
return 0; |
| |
|
| mutex_enter(&so_pendfree_lock); |
mutex_enter(&so_pendfree_lock); |
| rv = sodopendfreel(); |
rv = sodopendfreel(); |
| mutex_exit(&so_pendfree_lock); |
mutex_exit(&so_pendfree_lock); |
| Line 365 sosend_loan(struct socket *so, struct ui |
|
| Line 359 sosend_loan(struct socket *so, struct ui |
|
| len = eva - sva; |
len = eva - sva; |
| npgs = len >> PAGE_SHIFT; |
npgs = len >> PAGE_SHIFT; |
| |
|
| /* XXX KDASSERT */ |
|
| KASSERT(npgs <= M_EXT_MAXPAGES); |
KASSERT(npgs <= M_EXT_MAXPAGES); |
| |
|
| lva = sokvaalloc(len, so); |
lva = sokvaalloc(len, so); |
|
|
| { |
{ |
| |
|
| mutex_init(&so_pendfree_lock, MUTEX_DEFAULT, IPL_VM); |
mutex_init(&so_pendfree_lock, MUTEX_DEFAULT, IPL_VM); |
| |
softnet_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); |
| cv_init(&socurkva_cv, "sokva"); |
cv_init(&socurkva_cv, "sokva"); |
| |
soinit2(); |
| |
|
| /* Set the initial adjusted socket buffer size. */ |
/* Set the initial adjusted socket buffer size. */ |
| if (sb_max_set(sb_max)) |
if (sb_max_set(sb_max)) |
|
|
| */ |
*/ |
| /*ARGSUSED*/ |
/*ARGSUSED*/ |
| int |
int |
| socreate(int dom, struct socket **aso, int type, int proto, struct lwp *l) |
socreate(int dom, struct socket **aso, int type, int proto, struct lwp *l, |
| |
struct socket *lockso) |
| { |
{ |
| const struct protosw *prp; |
const struct protosw *prp; |
| struct socket *so; |
struct socket *so; |
| uid_t uid; |
uid_t uid; |
| int error, s; |
int error; |
| |
kmutex_t *lock; |
| |
|
| error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_SOCKET, |
error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_SOCKET, |
| KAUTH_REQ_NETWORK_SOCKET_OPEN, KAUTH_ARG(dom), KAUTH_ARG(type), |
KAUTH_REQ_NETWORK_SOCKET_OPEN, KAUTH_ARG(dom), KAUTH_ARG(type), |
| Line 490 socreate(int dom, struct socket **aso, i |
|
| Line 487 socreate(int dom, struct socket **aso, i |
|
| return EPROTONOSUPPORT; |
return EPROTONOSUPPORT; |
| if (prp->pr_type != type) |
if (prp->pr_type != type) |
| return EPROTOTYPE; |
return EPROTOTYPE; |
| s = splsoftnet(); |
|
| so = pool_get(&socket_pool, PR_WAITOK); |
so = soget(true); |
| memset(so, 0, sizeof(*so)); |
|
| TAILQ_INIT(&so->so_q0); |
|
| TAILQ_INIT(&so->so_q); |
|
| so->so_type = type; |
so->so_type = type; |
| so->so_proto = prp; |
so->so_proto = prp; |
| so->so_send = sosend; |
so->so_send = sosend; |
| Line 504 socreate(int dom, struct socket **aso, i |
|
| Line 498 socreate(int dom, struct socket **aso, i |
|
| so->so_snd.sb_mowner = &prp->pr_domain->dom_mowner; |
so->so_snd.sb_mowner = &prp->pr_domain->dom_mowner; |
| so->so_mowner = &prp->pr_domain->dom_mowner; |
so->so_mowner = &prp->pr_domain->dom_mowner; |
| #endif |
#endif |
| selinit(&so->so_rcv.sb_sel); |
|
| selinit(&so->so_snd.sb_sel); |
|
| uid = kauth_cred_geteuid(l->l_cred); |
uid = kauth_cred_geteuid(l->l_cred); |
| so->so_uidinfo = uid_find(uid); |
so->so_uidinfo = uid_find(uid); |
| |
if (lockso != NULL) { |
| |
/* Caller wants us to share a lock. */ |
| |
lock = lockso->so_lock; |
| |
so->so_lock = lock; |
| |
mutex_obj_hold(lock); |
| |
mutex_enter(lock); |
| |
} else { |
| |
/* Lock assigned and taken during PRU_ATTACH. */ |
| |
} |
| error = (*prp->pr_usrreq)(so, PRU_ATTACH, NULL, |
error = (*prp->pr_usrreq)(so, PRU_ATTACH, NULL, |
| (struct mbuf *)(long)proto, NULL, l); |
(struct mbuf *)(long)proto, NULL, l); |
| |
KASSERT(solocked(so)); |
| if (error != 0) { |
if (error != 0) { |
| so->so_state |= SS_NOFDREF; |
so->so_state |= SS_NOFDREF; |
| sofree(so); |
sofree(so); |
| splx(s); |
|
| return error; |
return error; |
| } |
} |
| splx(s); |
sounlock(so); |
| *aso = so; |
*aso = so; |
| return 0; |
return 0; |
| } |
} |
| Line 537 fsocreate(int domain, struct socket **so |
|
| Line 538 fsocreate(int domain, struct socket **so |
|
| fp->f_flag = FREAD|FWRITE; |
fp->f_flag = FREAD|FWRITE; |
| fp->f_type = DTYPE_SOCKET; |
fp->f_type = DTYPE_SOCKET; |
| fp->f_ops = &socketops; |
fp->f_ops = &socketops; |
| error = socreate(domain, &so, type, protocol, l); |
error = socreate(domain, &so, type, protocol, l, NULL); |
| if (error != 0) { |
if (error != 0) { |
| fd_abort(curproc, fp, fd); |
fd_abort(curproc, fp, fd); |
| } else { |
} else { |
| Line 553 fsocreate(int domain, struct socket **so |
|
| Line 554 fsocreate(int domain, struct socket **so |
|
| int |
int |
| sobind(struct socket *so, struct mbuf *nam, struct lwp *l) |
sobind(struct socket *so, struct mbuf *nam, struct lwp *l) |
| { |
{ |
| int s, error; |
int error; |
| |
|
| s = splsoftnet(); |
solock(so); |
| error = (*so->so_proto->pr_usrreq)(so, PRU_BIND, NULL, nam, NULL, l); |
error = (*so->so_proto->pr_usrreq)(so, PRU_BIND, NULL, nam, NULL, l); |
| splx(s); |
sounlock(so); |
| return error; |
return error; |
| } |
} |
| |
|
| int |
int |
| solisten(struct socket *so, int backlog, struct lwp *l) |
solisten(struct socket *so, int backlog, struct lwp *l) |
| { |
{ |
| int s, error; |
int error; |
| |
|
| s = splsoftnet(); |
solock(so); |
| if ((so->so_state & (SS_ISCONNECTED | SS_ISCONNECTING | |
if ((so->so_state & (SS_ISCONNECTED | SS_ISCONNECTING | |
| SS_ISDISCONNECTING)) != 0) |
SS_ISDISCONNECTING)) != 0) { |
| |
sounlock(so); |
| return (EOPNOTSUPP); |
return (EOPNOTSUPP); |
| |
} |
| error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, NULL, |
error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, NULL, |
| NULL, NULL, l); |
NULL, NULL, l); |
| if (error != 0) { |
if (error != 0) { |
| splx(s); |
sounlock(so); |
| return error; |
return error; |
| } |
} |
| if (TAILQ_EMPTY(&so->so_q)) |
if (TAILQ_EMPTY(&so->so_q)) |
| Line 581 solisten(struct socket *so, int backlog, |
|
| Line 584 solisten(struct socket *so, int backlog, |
|
| if (backlog < 0) |
if (backlog < 0) |
| backlog = 0; |
backlog = 0; |
| so->so_qlimit = min(backlog, somaxconn); |
so->so_qlimit = min(backlog, somaxconn); |
| splx(s); |
sounlock(so); |
| return 0; |
return 0; |
| } |
} |
| |
|
| void |
void |
| sofree(struct socket *so) |
sofree(struct socket *so) |
| { |
{ |
| |
u_int refs; |
| |
|
| if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) |
KASSERT(solocked(so)); |
| |
|
| |
if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) { |
| |
sounlock(so); |
| return; |
return; |
| |
} |
| if (so->so_head) { |
if (so->so_head) { |
| /* |
/* |
| * We must not decommission a socket that's on the accept(2) |
* We must not decommission a socket that's on the accept(2) |
| * queue. If we do, then accept(2) may hang after select(2) |
* queue. If we do, then accept(2) may hang after select(2) |
| * indicated that the listening socket was ready. |
* indicated that the listening socket was ready. |
| */ |
*/ |
| if (!soqremque(so, 0)) |
if (!soqremque(so, 0)) { |
| |
sounlock(so); |
| return; |
return; |
| |
} |
| } |
} |
| if (so->so_rcv.sb_hiwat) |
if (so->so_rcv.sb_hiwat) |
| (void)chgsbsize(so->so_uidinfo, &so->so_rcv.sb_hiwat, 0, |
(void)chgsbsize(so->so_uidinfo, &so->so_rcv.sb_hiwat, 0, |
| Line 607 sofree(struct socket *so) |
|
| Line 617 sofree(struct socket *so) |
|
| (void)chgsbsize(so->so_uidinfo, &so->so_snd.sb_hiwat, 0, |
(void)chgsbsize(so->so_uidinfo, &so->so_snd.sb_hiwat, 0, |
| RLIM_INFINITY); |
RLIM_INFINITY); |
| sbrelease(&so->so_snd, so); |
sbrelease(&so->so_snd, so); |
| |
KASSERT(!cv_has_waiters(&so->so_cv)); |
| |
KASSERT(!cv_has_waiters(&so->so_rcv.sb_cv)); |
| |
KASSERT(!cv_has_waiters(&so->so_snd.sb_cv)); |
| sorflush(so); |
sorflush(so); |
| seldestroy(&so->so_rcv.sb_sel); |
refs = so->so_aborting; /* XXX */ |
| seldestroy(&so->so_snd.sb_sel); |
sounlock(so); |
| pool_put(&socket_pool, so); |
if (refs == 0) /* XXX */ |
| |
soput(so); |
| } |
} |
| |
|
| /* |
/* |
|
|
| soclose(struct socket *so) |
soclose(struct socket *so) |
| { |
{ |
| struct socket *so2; |
struct socket *so2; |
| int s, error; |
int error; |
| |
int error2; |
| |
|
| error = 0; |
error = 0; |
| s = splsoftnet(); /* conservative */ |
solock(so); |
| if (so->so_options & SO_ACCEPTCONN) { |
if (so->so_options & SO_ACCEPTCONN) { |
| while ((so2 = TAILQ_FIRST(&so->so_q0)) != 0) { |
do { |
| (void) soqremque(so2, 0); |
if ((so2 = TAILQ_FIRST(&so->so_q0)) != 0) { |
| (void) soabort(so2); |
KASSERT(solocked2(so, so2)); |
| } |
(void) soqremque(so2, 0); |
| while ((so2 = TAILQ_FIRST(&so->so_q)) != 0) { |
/* soabort drops the lock. */ |
| (void) soqremque(so2, 1); |
(void) soabort(so2); |
| (void) soabort(so2); |
solock(so); |
| } |
continue; |
| |
} |
| |
if ((so2 = TAILQ_FIRST(&so->so_q)) != 0) { |
| |
KASSERT(solocked2(so, so2)); |
| |
(void) soqremque(so2, 1); |
| |
/* soabort drops the lock. */ |
| |
(void) soabort(so2); |
| |
solock(so); |
| |
continue; |
| |
} |
| |
} while (0); |
| } |
} |
| if (so->so_pcb == 0) |
if (so->so_pcb == 0) |
| goto discard; |
goto discard; |
| Line 648 soclose(struct socket *so) |
|
| Line 673 soclose(struct socket *so) |
|
| if ((so->so_state & SS_ISDISCONNECTING) && so->so_nbio) |
if ((so->so_state & SS_ISDISCONNECTING) && so->so_nbio) |
| goto drop; |
goto drop; |
| while (so->so_state & SS_ISCONNECTED) { |
while (so->so_state & SS_ISCONNECTED) { |
| error = tsleep((void *)&so->so_timeo, |
error = sowait(so, so->so_linger * hz); |
| PSOCK | PCATCH, netcls, |
|
| so->so_linger * hz); |
|
| if (error) |
if (error) |
| break; |
break; |
| } |
} |
| Line 658 soclose(struct socket *so) |
|
| Line 681 soclose(struct socket *so) |
|
| } |
} |
| drop: |
drop: |
| if (so->so_pcb) { |
if (so->so_pcb) { |
| int error2 = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, |
error2 = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, |
| NULL, NULL, NULL, NULL); |
NULL, NULL, NULL, NULL); |
| if (error == 0) |
if (error == 0) |
| error = error2; |
error = error2; |
| Line 668 soclose(struct socket *so) |
|
| Line 691 soclose(struct socket *so) |
|
| panic("soclose: NOFDREF"); |
panic("soclose: NOFDREF"); |
| so->so_state |= SS_NOFDREF; |
so->so_state |= SS_NOFDREF; |
| sofree(so); |
sofree(so); |
| splx(s); |
|
| return (error); |
return (error); |
| } |
} |
| |
|
| /* |
/* |
| * Must be called at splsoftnet... |
* Must be called with the socket locked.. Will return with it unlocked. |
| */ |
*/ |
| int |
int |
| soabort(struct socket *so) |
soabort(struct socket *so) |
| { |
{ |
| |
u_int refs; |
| int error; |
int error; |
| |
|
| |
KASSERT(solocked(so)); |
| KASSERT(so->so_head == NULL); |
KASSERT(so->so_head == NULL); |
| |
|
| |
so->so_aborting++; /* XXX */ |
| error = (*so->so_proto->pr_usrreq)(so, PRU_ABORT, NULL, |
error = (*so->so_proto->pr_usrreq)(so, PRU_ABORT, NULL, |
| NULL, NULL, NULL); |
NULL, NULL, NULL); |
| if (error) { |
refs = --so->so_aborting; /* XXX */ |
| |
if (error || (refs == 0)) { |
| sofree(so); |
sofree(so); |
| |
} else { |
| |
sounlock(so); |
| } |
} |
| return error; |
return error; |
| } |
} |
| Line 692 soabort(struct socket *so) |
|
| Line 721 soabort(struct socket *so) |
|
| int |
int |
| soaccept(struct socket *so, struct mbuf *nam) |
soaccept(struct socket *so, struct mbuf *nam) |
| { |
{ |
| int s, error; |
int error; |
| |
|
| |
KASSERT(solocked(so)); |
| |
|
| error = 0; |
error = 0; |
| s = splsoftnet(); |
|
| if ((so->so_state & SS_NOFDREF) == 0) |
if ((so->so_state & SS_NOFDREF) == 0) |
| panic("soaccept: !NOFDREF"); |
panic("soaccept: !NOFDREF"); |
| so->so_state &= ~SS_NOFDREF; |
so->so_state &= ~SS_NOFDREF; |
| Line 706 soaccept(struct socket *so, struct mbuf |
|
| Line 736 soaccept(struct socket *so, struct mbuf |
|
| else |
else |
| error = ECONNABORTED; |
error = ECONNABORTED; |
| |
|
| splx(s); |
|
| return (error); |
return (error); |
| } |
} |
| |
|
| int |
int |
| soconnect(struct socket *so, struct mbuf *nam, struct lwp *l) |
soconnect(struct socket *so, struct mbuf *nam, struct lwp *l) |
| { |
{ |
| int s, error; |
int error; |
| |
|
| |
KASSERT(solocked(so)); |
| |
|
| if (so->so_options & SO_ACCEPTCONN) |
if (so->so_options & SO_ACCEPTCONN) |
| return (EOPNOTSUPP); |
return (EOPNOTSUPP); |
| s = splsoftnet(); |
|
| /* |
/* |
| * If protocol is connection-based, can only connect once. |
* If protocol is connection-based, can only connect once. |
| * Otherwise, if connected, try to disconnect first. |
* Otherwise, if connected, try to disconnect first. |
| Line 731 soconnect(struct socket *so, struct mbuf |
|
| Line 761 soconnect(struct socket *so, struct mbuf |
|
| else |
else |
| error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, |
error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, |
| NULL, nam, NULL, l); |
NULL, nam, NULL, l); |
| splx(s); |
|
| return (error); |
return (error); |
| } |
} |
| |
|
| int |
int |
| soconnect2(struct socket *so1, struct socket *so2) |
soconnect2(struct socket *so1, struct socket *so2) |
| { |
{ |
| int s, error; |
int error; |
| |
|
| |
KASSERT(solocked2(so1, so2)); |
| |
|
| s = splsoftnet(); |
|
| error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, |
error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, |
| NULL, (struct mbuf *)so2, NULL, NULL); |
NULL, (struct mbuf *)so2, NULL, NULL); |
| splx(s); |
|
| return (error); |
return (error); |
| } |
} |
| |
|
| int |
int |
| sodisconnect(struct socket *so) |
sodisconnect(struct socket *so) |
| { |
{ |
| int s, error; |
int error; |
| |
|
| |
KASSERT(solocked(so)); |
| |
|
| s = splsoftnet(); |
|
| if ((so->so_state & SS_ISCONNECTED) == 0) { |
if ((so->so_state & SS_ISCONNECTED) == 0) { |
| error = ENOTCONN; |
error = ENOTCONN; |
| goto bad; |
} else if (so->so_state & SS_ISDISCONNECTING) { |
| } |
|
| if (so->so_state & SS_ISDISCONNECTING) { |
|
| error = EALREADY; |
error = EALREADY; |
| goto bad; |
} else { |
| |
error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, |
| |
NULL, NULL, NULL, NULL); |
| } |
} |
| error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, |
|
| NULL, NULL, NULL, NULL); |
|
| bad: |
|
| splx(s); |
|
| sodopendfree(); |
sodopendfree(); |
| return (error); |
return (error); |
| } |
} |
| Line 798 sosend(struct socket *so, struct mbuf *a |
|
| Line 824 sosend(struct socket *so, struct mbuf *a |
|
| |
|
| p = l->l_proc; |
p = l->l_proc; |
| sodopendfree(); |
sodopendfree(); |
| |
|
| clen = 0; |
clen = 0; |
| |
|
| |
/* |
| |
* solock() provides atomicity of access. splsoftnet() prevents |
| |
* protocol processing soft interrupts from interrupting us and |
| |
* blocking (expensive). |
| |
*/ |
| |
s = splsoftnet(); |
| |
solock(so); |
| atomic = sosendallatonce(so) || top; |
atomic = sosendallatonce(so) || top; |
| if (uio) |
if (uio) |
| resid = uio->uio_resid; |
resid = uio->uio_resid; |
| Line 819 sosend(struct socket *so, struct mbuf *a |
|
| Line 852 sosend(struct socket *so, struct mbuf *a |
|
| dontroute = |
dontroute = |
| (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && |
(flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && |
| (so->so_proto->pr_flags & PR_ATOMIC); |
(so->so_proto->pr_flags & PR_ATOMIC); |
| if (l) |
l->l_ru.ru_msgsnd++; |
| l->l_ru.ru_msgsnd++; |
|
| if (control) |
if (control) |
| clen = control->m_len; |
clen = control->m_len; |
| #define snderr(errno) { error = errno; splx(s); goto release; } |
|
| |
|
| restart: |
restart: |
| if ((error = sblock(&so->so_snd, SBLOCKWAIT(flags))) != 0) |
if ((error = sblock(&so->so_snd, SBLOCKWAIT(flags))) != 0) |
| goto out; |
goto out; |
| do { |
do { |
| s = splsoftnet(); |
if (so->so_state & SS_CANTSENDMORE) { |
| if (so->so_state & SS_CANTSENDMORE) |
error = EPIPE; |
| snderr(EPIPE); |
goto release; |
| |
} |
| if (so->so_error) { |
if (so->so_error) { |
| error = so->so_error; |
error = so->so_error; |
| so->so_error = 0; |
so->so_error = 0; |
| splx(s); |
|
| goto release; |
goto release; |
| } |
} |
| if ((so->so_state & SS_ISCONNECTED) == 0) { |
if ((so->so_state & SS_ISCONNECTED) == 0) { |
| if (so->so_proto->pr_flags & PR_CONNREQUIRED) { |
if (so->so_proto->pr_flags & PR_CONNREQUIRED) { |
| if ((so->so_state & SS_ISCONFIRMING) == 0 && |
if ((so->so_state & SS_ISCONFIRMING) == 0 && |
| !(resid == 0 && clen != 0)) |
!(resid == 0 && clen != 0)) { |
| snderr(ENOTCONN); |
error = ENOTCONN; |
| } else if (addr == 0) |
goto release; |
| snderr(EDESTADDRREQ); |
} |
| |
} else if (addr == 0) { |
| |
error = EDESTADDRREQ; |
| |
goto release; |
| |
} |
| } |
} |
| space = sbspace(&so->so_snd); |
space = sbspace(&so->so_snd); |
| if (flags & MSG_OOB) |
if (flags & MSG_OOB) |
| space += 1024; |
space += 1024; |
| if ((atomic && resid > so->so_snd.sb_hiwat) || |
if ((atomic && resid > so->so_snd.sb_hiwat) || |
| clen > so->so_snd.sb_hiwat) |
clen > so->so_snd.sb_hiwat) { |
| snderr(EMSGSIZE); |
error = EMSGSIZE; |
| |
goto release; |
| |
} |
| if (space < resid + clen && |
if (space < resid + clen && |
| (atomic || space < so->so_snd.sb_lowat || space < clen)) { |
(atomic || space < so->so_snd.sb_lowat || space < clen)) { |
| if (so->so_nbio) |
if (so->so_nbio) { |
| snderr(EWOULDBLOCK); |
error = EWOULDBLOCK; |
| |
goto release; |
| |
} |
| sbunlock(&so->so_snd); |
sbunlock(&so->so_snd); |
| error = sbwait(&so->so_snd); |
error = sbwait(&so->so_snd); |
| splx(s); |
|
| if (error) |
if (error) |
| goto out; |
goto out; |
| goto restart; |
goto restart; |
| } |
} |
| splx(s); |
|
| mp = ⊤ |
mp = ⊤ |
| space -= clen; |
space -= clen; |
| do { |
do { |
| Line 875 sosend(struct socket *so, struct mbuf *a |
|
| Line 911 sosend(struct socket *so, struct mbuf *a |
|
| if (flags & MSG_EOR) |
if (flags & MSG_EOR) |
| top->m_flags |= M_EOR; |
top->m_flags |= M_EOR; |
| } else do { |
} else do { |
| |
sounlock(so); |
| |
splx(s); |
| if (top == NULL) { |
if (top == NULL) { |
| m = m_gethdr(M_WAIT, MT_DATA); |
m = m_gethdr(M_WAIT, MT_DATA); |
| mlen = MHLEN; |
mlen = MHLEN; |
| Line 925 sosend(struct socket *so, struct mbuf *a |
|
| Line 963 sosend(struct socket *so, struct mbuf *a |
|
| m->m_len = len; |
m->m_len = len; |
| *mp = m; |
*mp = m; |
| top->m_pkthdr.len += len; |
top->m_pkthdr.len += len; |
| |
s = splsoftnet(); |
| |
solock(so); |
| if (error != 0) |
if (error != 0) |
| goto release; |
goto release; |
| mp = &m->m_next; |
mp = &m->m_next; |
| Line 935 sosend(struct socket *so, struct mbuf *a |
|
| Line 975 sosend(struct socket *so, struct mbuf *a |
|
| } |
} |
| } while (space > 0 && atomic); |
} while (space > 0 && atomic); |
| |
|
| s = splsoftnet(); |
if (so->so_state & SS_CANTSENDMORE) { |
| |
error = EPIPE; |
| if (so->so_state & SS_CANTSENDMORE) |
goto release; |
| snderr(EPIPE); |
} |
| |
|
| if (dontroute) |
if (dontroute) |
| so->so_options |= SO_DONTROUTE; |
so->so_options |= SO_DONTROUTE; |
| if (resid > 0) |
if (resid > 0) |
| so->so_state |= SS_MORETOCOME; |
so->so_state |= SS_MORETOCOME; |
| error = (*so->so_proto->pr_usrreq)(so, |
error = (*so->so_proto->pr_usrreq)(so, |
| (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, |
(flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, |
| top, addr, control, curlwp); /* XXX */ |
top, addr, control, curlwp); |
| if (dontroute) |
if (dontroute) |
| so->so_options &= ~SO_DONTROUTE; |
so->so_options &= ~SO_DONTROUTE; |
| if (resid > 0) |
if (resid > 0) |
| so->so_state &= ~SS_MORETOCOME; |
so->so_state &= ~SS_MORETOCOME; |
| splx(s); |
|
| |
|
| clen = 0; |
clen = 0; |
| control = NULL; |
control = NULL; |
| top = NULL; |
top = NULL; |
| Line 965 sosend(struct socket *so, struct mbuf *a |
|
| Line 1002 sosend(struct socket *so, struct mbuf *a |
|
| release: |
release: |
| sbunlock(&so->so_snd); |
sbunlock(&so->so_snd); |
| out: |
out: |
| |
sounlock(so); |
| |
splx(s); |
| if (top) |
if (top) |
| m_freem(top); |
m_freem(top); |
| if (control) |
if (control) |
|
|
| sbsync(struct sockbuf *sb, struct mbuf *nextrecord) |
sbsync(struct sockbuf *sb, struct mbuf *nextrecord) |
| { |
{ |
| |
|
| |
KASSERT(solocked(sb->sb_so)); |
| |
|
| /* |
/* |
| * First, update for the new value of nextrecord. If necessary, |
* First, update for the new value of nextrecord. If necessary, |
| * make it the first record. |
* make it the first record. |
| Line 1028 soreceive(struct socket *so, struct mbuf |
|
| Line 1069 soreceive(struct socket *so, struct mbuf |
|
| struct mbuf **mp0, struct mbuf **controlp, int *flagsp) |
struct mbuf **mp0, struct mbuf **controlp, int *flagsp) |
| { |
{ |
| struct lwp *l = curlwp; |
struct lwp *l = curlwp; |
| struct mbuf *m, **mp; |
struct mbuf *m, **mp, *mt; |
| int atomic, flags, len, error, s, offset, moff, type, orig_resid; |
int atomic, flags, len, error, s, offset, moff, type, orig_resid; |
| const struct protosw *pr; |
const struct protosw *pr; |
| struct mbuf *nextrecord; |
struct mbuf *nextrecord; |
| Line 1056 soreceive(struct socket *so, struct mbuf |
|
| Line 1097 soreceive(struct socket *so, struct mbuf |
|
| |
|
| if (flags & MSG_OOB) { |
if (flags & MSG_OOB) { |
| m = m_get(M_WAIT, MT_DATA); |
m = m_get(M_WAIT, MT_DATA); |
| |
solock(so); |
| error = (*pr->pr_usrreq)(so, PRU_RCVOOB, m, |
error = (*pr->pr_usrreq)(so, PRU_RCVOOB, m, |
| (struct mbuf *)(long)(flags & MSG_PEEK), NULL, l); |
(struct mbuf *)(long)(flags & MSG_PEEK), NULL, l); |
| |
sounlock(so); |
| if (error) |
if (error) |
| goto bad; |
goto bad; |
| do { |
do { |
| Line 1072 soreceive(struct socket *so, struct mbuf |
|
| Line 1115 soreceive(struct socket *so, struct mbuf |
|
| } |
} |
| if (mp != NULL) |
if (mp != NULL) |
| *mp = NULL; |
*mp = NULL; |
| |
|
| |
/* |
| |
* solock() provides atomicity of access. splsoftnet() prevents |
| |
* protocol processing soft interrupts from interrupting us and |
| |
* blocking (expensive). |
| |
*/ |
| |
s = splsoftnet(); |
| |
solock(so); |
| if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) |
if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) |
| (*pr->pr_usrreq)(so, PRU_RCVD, NULL, NULL, NULL, l); |
(*pr->pr_usrreq)(so, PRU_RCVD, NULL, NULL, NULL, l); |
| |
|
| restart: |
restart: |
| if ((error = sblock(&so->so_rcv, SBLOCKWAIT(flags))) != 0) |
if ((error = sblock(&so->so_rcv, SBLOCKWAIT(flags))) != 0) { |
| |
sounlock(so); |
| |
splx(s); |
| return error; |
return error; |
| s = splsoftnet(); |
} |
| |
|
| m = so->so_rcv.sb_mb; |
m = so->so_rcv.sb_mb; |
| /* |
/* |
| Line 1137 soreceive(struct socket *so, struct mbuf |
|
| Line 1190 soreceive(struct socket *so, struct mbuf |
|
| SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 1"); |
SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 1"); |
| sbunlock(&so->so_rcv); |
sbunlock(&so->so_rcv); |
| error = sbwait(&so->so_rcv); |
error = sbwait(&so->so_rcv); |
| splx(s); |
if (error != 0) { |
| if (error != 0) |
sounlock(so); |
| |
splx(s); |
| return error; |
return error; |
| |
} |
| goto restart; |
goto restart; |
| } |
} |
| dontblock: |
dontblock: |
| Line 1149 soreceive(struct socket *so, struct mbuf |
|
| Line 1204 soreceive(struct socket *so, struct mbuf |
|
| * pointer to the next record in the socket buffer. We must keep the |
* pointer to the next record in the socket buffer. We must keep the |
| * various socket buffer pointers and local stack versions of the |
* various socket buffer pointers and local stack versions of the |
| * pointers in sync, pushing out modifications before dropping the |
* pointers in sync, pushing out modifications before dropping the |
| * IPL, and re-reading them when picking it up. |
* socket lock, and re-reading them when picking it up. |
| * |
* |
| * Otherwise, we will race with the network stack appending new data |
* Otherwise, we will race with the network stack appending new data |
| * or records onto the socket buffer by using inconsistent/stale |
* or records onto the socket buffer by using inconsistent/stale |
| Line 1226 soreceive(struct socket *so, struct mbuf |
|
| Line 1281 soreceive(struct socket *so, struct mbuf |
|
| if (controlp != NULL) { |
if (controlp != NULL) { |
| if (dom->dom_externalize != NULL && |
if (dom->dom_externalize != NULL && |
| type == SCM_RIGHTS) { |
type == SCM_RIGHTS) { |
| |
sounlock(so); |
| splx(s); |
splx(s); |
| error = (*dom->dom_externalize)(cm, l); |
error = (*dom->dom_externalize)(cm, l); |
| s = splsoftnet(); |
s = splsoftnet(); |
| |
solock(so); |
| } |
} |
| *controlp = cm; |
*controlp = cm; |
| while (*controlp != NULL) |
while (*controlp != NULL) |
| Line 1240 soreceive(struct socket *so, struct mbuf |
|
| Line 1297 soreceive(struct socket *so, struct mbuf |
|
| */ |
*/ |
| if (dom->dom_dispose != NULL && |
if (dom->dom_dispose != NULL && |
| type == SCM_RIGHTS) { |
type == SCM_RIGHTS) { |
| splx(s); |
sounlock(so); |
| (*dom->dom_dispose)(cm); |
(*dom->dom_dispose)(cm); |
| s = splsoftnet(); |
solock(so); |
| } |
} |
| m_freem(cm); |
m_freem(cm); |
| } |
} |
| Line 1292 soreceive(struct socket *so, struct mbuf |
|
| Line 1349 soreceive(struct socket *so, struct mbuf |
|
| if (mp == NULL) { |
if (mp == NULL) { |
| SBLASTRECORDCHK(&so->so_rcv, "soreceive uiomove"); |
SBLASTRECORDCHK(&so->so_rcv, "soreceive uiomove"); |
| SBLASTMBUFCHK(&so->so_rcv, "soreceive uiomove"); |
SBLASTMBUFCHK(&so->so_rcv, "soreceive uiomove"); |
| |
sounlock(so); |
| splx(s); |
splx(s); |
| error = uiomove(mtod(m, char *) + moff, (int)len, uio); |
error = uiomove(mtod(m, char *) + moff, (int)len, uio); |
| s = splsoftnet(); |
s = splsoftnet(); |
| |
solock(so); |
| if (error != 0) { |
if (error != 0) { |
| /* |
/* |
| * If any part of the record has been removed |
* If any part of the record has been removed |
| Line 1351 soreceive(struct socket *so, struct mbuf |
|
| Line 1410 soreceive(struct socket *so, struct mbuf |
|
| } else if (flags & MSG_PEEK) |
} else if (flags & MSG_PEEK) |
| moff += len; |
moff += len; |
| else { |
else { |
| if (mp != NULL) |
if (mp != NULL) { |
| *mp = m_copym(m, 0, len, M_WAIT); |
mt = m_copym(m, 0, len, M_NOWAIT); |
| |
if (__predict_false(mt == NULL)) { |
| |
sounlock(so); |
| |
mt = m_copym(m, 0, len, M_WAIT); |
| |
solock(so); |
| |
} |
| |
*mp = mt; |
| |
} |
| m->m_data += len; |
m->m_data += len; |
| m->m_len -= len; |
m->m_len -= len; |
| so->so_rcv.sb_cc -= len; |
so->so_rcv.sb_cc -= len; |
| Line 1402 soreceive(struct socket *so, struct mbuf |
|
| Line 1468 soreceive(struct socket *so, struct mbuf |
|
| error = sbwait(&so->so_rcv); |
error = sbwait(&so->so_rcv); |
| if (error != 0) { |
if (error != 0) { |
| sbunlock(&so->so_rcv); |
sbunlock(&so->so_rcv); |
| |
sounlock(so); |
| splx(s); |
splx(s); |
| return 0; |
return 0; |
| } |
} |
| Line 1438 soreceive(struct socket *so, struct mbuf |
|
| Line 1505 soreceive(struct socket *so, struct mbuf |
|
| if (orig_resid == uio->uio_resid && orig_resid && |
if (orig_resid == uio->uio_resid && orig_resid && |
| (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) { |
(flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) { |
| sbunlock(&so->so_rcv); |
sbunlock(&so->so_rcv); |
| splx(s); |
|
| goto restart; |
goto restart; |
| } |
} |
| |
|
| Line 1446 soreceive(struct socket *so, struct mbuf |
|
| Line 1512 soreceive(struct socket *so, struct mbuf |
|
| *flagsp |= flags; |
*flagsp |= flags; |
| release: |
release: |
| sbunlock(&so->so_rcv); |
sbunlock(&so->so_rcv); |
| |
sounlock(so); |
| splx(s); |
splx(s); |
| return error; |
return error; |
| } |
} |
|
|
| soshutdown(struct socket *so, int how) |
soshutdown(struct socket *so, int how) |
| { |
{ |
| const struct protosw *pr; |
const struct protosw *pr; |
| |
int error; |
| |
|
| |
KASSERT(solocked(so)); |
| |
|
| pr = so->so_proto; |
pr = so->so_proto; |
| if (!(how == SHUT_RD || how == SHUT_WR || how == SHUT_RDWR)) |
if (!(how == SHUT_RD || how == SHUT_WR || how == SHUT_RDWR)) |
| return (EINVAL); |
return (EINVAL); |
| |
|
| if (how == SHUT_RD || how == SHUT_RDWR) |
if (how == SHUT_RD || how == SHUT_RDWR) { |
| sorflush(so); |
sorflush(so); |
| |
error = 0; |
| |
} |
| if (how == SHUT_WR || how == SHUT_RDWR) |
if (how == SHUT_WR || how == SHUT_RDWR) |
| return (*pr->pr_usrreq)(so, PRU_SHUTDOWN, NULL, |
error = (*pr->pr_usrreq)(so, PRU_SHUTDOWN, NULL, |
| NULL, NULL, NULL); |
NULL, NULL, NULL); |
| return 0; |
|
| |
return error; |
| } |
} |
| |
|
| void |
void |
| Line 1472 sorflush(struct socket *so) |
|
| Line 1545 sorflush(struct socket *so) |
|
| { |
{ |
| struct sockbuf *sb, asb; |
struct sockbuf *sb, asb; |
| const struct protosw *pr; |
const struct protosw *pr; |
| int s; |
|
| |
KASSERT(solocked(so)); |
| |
|
| sb = &so->so_rcv; |
sb = &so->so_rcv; |
| pr = so->so_proto; |
pr = so->so_proto; |
| sb->sb_flags |= SB_NOINTR; |
|
| (void) sblock(sb, M_WAITOK); |
|
| s = splnet(); |
|
| socantrcvmore(so); |
socantrcvmore(so); |
| |
sb->sb_flags |= SB_NOINTR; |
| |
(void )sblock(sb, M_WAITOK); |
| sbunlock(sb); |
sbunlock(sb); |
| asb = *sb; |
asb = *sb; |
| /* |
/* |
| Line 1488 sorflush(struct socket *so) |
|
| Line 1561 sorflush(struct socket *so) |
|
| */ |
*/ |
| memset(&sb->sb_startzero, 0, |
memset(&sb->sb_startzero, 0, |
| sizeof(*sb) - offsetof(struct sockbuf, sb_startzero)); |
sizeof(*sb) - offsetof(struct sockbuf, sb_startzero)); |
| splx(s); |
if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) { |
| if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) |
sounlock(so); |
| (*pr->pr_domain->dom_dispose)(asb.sb_mb); |
(*pr->pr_domain->dom_dispose)(asb.sb_mb); |
| |
solock(so); |
| |
} |
| sbrelease(&asb, so); |
sbrelease(&asb, so); |
| } |
} |
| |
|
| Line 1611 sosetopt(struct socket *so, int level, i |
|
| Line 1686 sosetopt(struct socket *so, int level, i |
|
| { |
{ |
| int error, prerr; |
int error, prerr; |
| |
|
| |
solock(so); |
| if (level == SOL_SOCKET) |
if (level == SOL_SOCKET) |
| error = sosetopt1(so, level, optname, m); |
error = sosetopt1(so, level, optname, m); |
| else |
else |
| Line 1627 sosetopt(struct socket *so, int level, i |
|
| Line 1703 sosetopt(struct socket *so, int level, i |
|
| error = prerr; |
error = prerr; |
| } else if (m != NULL) |
} else if (m != NULL) |
| (void)m_free(m); |
(void)m_free(m); |
| |
sounlock(so); |
| return error; |
return error; |
| } |
} |
| |
|
|
|
| sogetopt(struct socket *so, int level, int optname, struct mbuf **mp) |
sogetopt(struct socket *so, int level, int optname, struct mbuf **mp) |
| { |
{ |
| struct mbuf *m; |
struct mbuf *m; |
| |
int error; |
| |
|
| |
solock(so); |
| if (level != SOL_SOCKET) { |
if (level != SOL_SOCKET) { |
| if (so->so_proto && so->so_proto->pr_ctloutput) { |
if (so->so_proto && so->so_proto->pr_ctloutput) { |
| return ((*so->so_proto->pr_ctloutput) |
error = ((*so->so_proto->pr_ctloutput) |
| (PRCO_GETOPT, so, level, optname, mp)); |
(PRCO_GETOPT, so, level, optname, mp)); |
| } else |
} else |
| return (ENOPROTOOPT); |
error = (ENOPROTOOPT); |
| } else { |
} else { |
| m = m_get(M_WAIT, MT_SOOPTS); |
m = m_get(M_WAIT, MT_SOOPTS); |
| m->m_len = sizeof(int); |
m->m_len = sizeof(int); |
| Line 1709 sogetopt(struct socket *so, int level, i |
|
| Line 1788 sogetopt(struct socket *so, int level, i |
|
| break; |
break; |
| |
|
| default: |
default: |
| |
sounlock(so); |
| (void)m_free(m); |
(void)m_free(m); |
| return (ENOPROTOOPT); |
return (ENOPROTOOPT); |
| } |
} |
| *mp = m; |
*mp = m; |
| return (0); |
error = 0; |
| } |
} |
| |
|
| |
sounlock(so); |
| |
return (error); |
| } |
} |
| |
|
| void |
void |
| Line 1731 filt_sordetach(struct knote *kn) |
|
| Line 1814 filt_sordetach(struct knote *kn) |
|
| struct socket *so; |
struct socket *so; |
| |
|
| so = ((file_t *)kn->kn_obj)->f_data; |
so = ((file_t *)kn->kn_obj)->f_data; |
| |
solock(so); |
| SLIST_REMOVE(&so->so_rcv.sb_sel.sel_klist, kn, knote, kn_selnext); |
SLIST_REMOVE(&so->so_rcv.sb_sel.sel_klist, kn, knote, kn_selnext); |
| if (SLIST_EMPTY(&so->so_rcv.sb_sel.sel_klist)) |
if (SLIST_EMPTY(&so->so_rcv.sb_sel.sel_klist)) |
| so->so_rcv.sb_flags &= ~SB_KNOTE; |
so->so_rcv.sb_flags &= ~SB_KNOTE; |
| |
sounlock(so); |
| } |
} |
| |
|
| /*ARGSUSED*/ |
/*ARGSUSED*/ |
|
|
| filt_soread(struct knote *kn, long hint) |
filt_soread(struct knote *kn, long hint) |
| { |
{ |
| struct socket *so; |
struct socket *so; |
| |
int rv; |
| |
|
| so = ((file_t *)kn->kn_obj)->f_data; |
so = ((file_t *)kn->kn_obj)->f_data; |
| |
if (hint != NOTE_SUBMIT) |
| |
solock(so); |
| kn->kn_data = so->so_rcv.sb_cc; |
kn->kn_data = so->so_rcv.sb_cc; |
| if (so->so_state & SS_CANTRCVMORE) { |
if (so->so_state & SS_CANTRCVMORE) { |
| kn->kn_flags |= EV_EOF; |
kn->kn_flags |= EV_EOF; |
| kn->kn_fflags = so->so_error; |
kn->kn_fflags = so->so_error; |
| return (1); |
rv = 1; |
| } |
} else if (so->so_error) /* temporary udp error */ |
| if (so->so_error) /* temporary udp error */ |
rv = 1; |
| return (1); |
else if (kn->kn_sfflags & NOTE_LOWAT) |
| if (kn->kn_sfflags & NOTE_LOWAT) |
rv = (kn->kn_data >= kn->kn_sdata); |
| return (kn->kn_data >= kn->kn_sdata); |
else |
| return (kn->kn_data >= so->so_rcv.sb_lowat); |
rv = (kn->kn_data >= so->so_rcv.sb_lowat); |
| |
if (hint != NOTE_SUBMIT) |
| |
sounlock(so); |
| |
return rv; |
| } |
} |
| |
|
| static void |
static void |
| Line 1762 filt_sowdetach(struct knote *kn) |
|
| Line 1853 filt_sowdetach(struct knote *kn) |
|
| struct socket *so; |
struct socket *so; |
| |
|
| so = ((file_t *)kn->kn_obj)->f_data; |
so = ((file_t *)kn->kn_obj)->f_data; |
| |
solock(so); |
| SLIST_REMOVE(&so->so_snd.sb_sel.sel_klist, kn, knote, kn_selnext); |
SLIST_REMOVE(&so->so_snd.sb_sel.sel_klist, kn, knote, kn_selnext); |
| if (SLIST_EMPTY(&so->so_snd.sb_sel.sel_klist)) |
if (SLIST_EMPTY(&so->so_snd.sb_sel.sel_klist)) |
| so->so_snd.sb_flags &= ~SB_KNOTE; |
so->so_snd.sb_flags &= ~SB_KNOTE; |
| |
sounlock(so); |
| } |
} |
| |
|
| /*ARGSUSED*/ |
/*ARGSUSED*/ |
|
|
| filt_sowrite(struct knote *kn, long hint) |
filt_sowrite(struct knote *kn, long hint) |
| { |
{ |
| struct socket *so; |
struct socket *so; |
| |
int rv; |
| |
|
| so = ((file_t *)kn->kn_obj)->f_data; |
so = ((file_t *)kn->kn_obj)->f_data; |
| |
if (hint != NOTE_SUBMIT) |
| |
solock(so); |
| kn->kn_data = sbspace(&so->so_snd); |
kn->kn_data = sbspace(&so->so_snd); |
| if (so->so_state & SS_CANTSENDMORE) { |
if (so->so_state & SS_CANTSENDMORE) { |
| kn->kn_flags |= EV_EOF; |
kn->kn_flags |= EV_EOF; |
| kn->kn_fflags = so->so_error; |
kn->kn_fflags = so->so_error; |
| return (1); |
rv = 1; |
| } |
} else if (so->so_error) /* temporary udp error */ |
| if (so->so_error) /* temporary udp error */ |
rv = 1; |
| return (1); |
else if (((so->so_state & SS_ISCONNECTED) == 0) && |
| if (((so->so_state & SS_ISCONNECTED) == 0) && |
|
| (so->so_proto->pr_flags & PR_CONNREQUIRED)) |
(so->so_proto->pr_flags & PR_CONNREQUIRED)) |
| return (0); |
rv = 0; |
| if (kn->kn_sfflags & NOTE_LOWAT) |
else if (kn->kn_sfflags & NOTE_LOWAT) |
| return (kn->kn_data >= kn->kn_sdata); |
rv = (kn->kn_data >= kn->kn_sdata); |
| return (kn->kn_data >= so->so_snd.sb_lowat); |
else |
| |
rv = (kn->kn_data >= so->so_snd.sb_lowat); |
| |
if (hint != NOTE_SUBMIT) |
| |
sounlock(so); |
| |
return rv; |
| } |
} |
| |
|
| /*ARGSUSED*/ |
/*ARGSUSED*/ |
|
|
| filt_solisten(struct knote *kn, long hint) |
filt_solisten(struct knote *kn, long hint) |
| { |
{ |
| struct socket *so; |
struct socket *so; |
| |
int rv; |
| |
|
| so = ((file_t *)kn->kn_obj)->f_data; |
so = ((file_t *)kn->kn_obj)->f_data; |
| |
|
| Line 1802 filt_solisten(struct knote *kn, long hin |
|
| Line 1902 filt_solisten(struct knote *kn, long hin |
|
| * Set kn_data to number of incoming connections, not |
* Set kn_data to number of incoming connections, not |
| * counting partial (incomplete) connections. |
* counting partial (incomplete) connections. |
| */ |
*/ |
| |
if (hint != NOTE_SUBMIT) |
| |
solock(so); |
| kn->kn_data = so->so_qlen; |
kn->kn_data = so->so_qlen; |
| return (kn->kn_data > 0); |
rv = (kn->kn_data > 0); |
| |
if (hint != NOTE_SUBMIT) |
| |
sounlock(so); |
| |
return rv; |
| } |
} |
| |
|
| static const struct filterops solisten_filtops = |
static const struct filterops solisten_filtops = |
| Line 1820 soo_kqfilter(struct file *fp, struct kno |
|
| Line 1925 soo_kqfilter(struct file *fp, struct kno |
|
| struct sockbuf *sb; |
struct sockbuf *sb; |
| |
|
| so = ((file_t *)kn->kn_obj)->f_data; |
so = ((file_t *)kn->kn_obj)->f_data; |
| |
solock(so); |
| switch (kn->kn_filter) { |
switch (kn->kn_filter) { |
| case EVFILT_READ: |
case EVFILT_READ: |
| if (so->so_options & SO_ACCEPTCONN) |
if (so->so_options & SO_ACCEPTCONN) |
| Line 1833 soo_kqfilter(struct file *fp, struct kno |
|
| Line 1939 soo_kqfilter(struct file *fp, struct kno |
|
| sb = &so->so_snd; |
sb = &so->so_snd; |
| break; |
break; |
| default: |
default: |
| |
sounlock(so); |
| return (EINVAL); |
return (EINVAL); |
| } |
} |
| SLIST_INSERT_HEAD(&sb->sb_sel.sel_klist, kn, kn_selnext); |
SLIST_INSERT_HEAD(&sb->sb_sel.sel_klist, kn, kn_selnext); |
| sb->sb_flags |= SB_KNOTE; |
sb->sb_flags |= SB_KNOTE; |
| |
sounlock(so); |
| return (0); |
return (0); |
| } |
} |
| |
|
|
|
| sopoll(struct socket *so, int events) |
sopoll(struct socket *so, int events) |
| { |
{ |
| int revents = 0; |
int revents = 0; |
| int s; |
|
| |
|
| |
#ifndef DIAGNOSTIC |
| |
/* |
| |
* Do a quick, unlocked check in expectation that the socket |
| |
* will be ready for I/O. Don't do this check if DIAGNOSTIC, |
| |
* as the solocked() assertions will fail. |
| |
*/ |
| if ((revents = sodopoll(so, events)) != 0) |
if ((revents = sodopoll(so, events)) != 0) |
| return revents; |
return revents; |
| |
#endif |
| |
|
| KERNEL_LOCK(1, curlwp); |
solock(so); |
| s = splsoftnet(); |
|
| |
|
| if ((revents = sodopoll(so, events)) == 0) { |
if ((revents = sodopoll(so, events)) == 0) { |
| if (events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) { |
if (events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) { |
| selrecord(curlwp, &so->so_rcv.sb_sel); |
selrecord(curlwp, &so->so_rcv.sb_sel); |
| so->so_rcv.sb_flags |= SB_SEL; |
so->so_rcv.sb_flags |= SB_NOTIFY; |
| } |
} |
| |
|
| if (events & (POLLOUT | POLLWRNORM)) { |
if (events & (POLLOUT | POLLWRNORM)) { |
| selrecord(curlwp, &so->so_snd.sb_sel); |
selrecord(curlwp, &so->so_snd.sb_sel); |
| so->so_snd.sb_flags |= SB_SEL; |
so->so_snd.sb_flags |= SB_NOTIFY; |
| } |
} |
| } |
} |
| |
sounlock(so); |
| splx(s); |
|
| KERNEL_UNLOCK_ONE(curlwp); |
|
| |
|
| return revents; |
return revents; |
| } |
} |