version 1.91, 2008/04/24 11:38:36 |
version 1.91.2.5, 2010/03/11 15:04:20 |
|
|
* 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 85 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 78 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <sys/signalvar.h> |
#include <sys/signalvar.h> |
#include <sys/kauth.h> |
#include <sys/kauth.h> |
#include <sys/pool.h> |
#include <sys/pool.h> |
|
#include <sys/uidinfo.h> |
|
|
/* |
/* |
* Primitive routines for operating on sockets and socket buffers. |
* Primitive routines for operating on sockets and socket buffers. |
Line 127 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 121 __KERNEL_RCSID(0, "$NetBSD$"); |
|
* domains. |
* domains. |
*/ |
*/ |
|
|
static POOL_INIT(socket_pool, sizeof(struct socket), 0, 0, 0, "sockpl", NULL, |
static pool_cache_t socket_cache; |
IPL_SOFTNET); |
|
|
|
u_long sb_max = SB_MAX; /* maximum socket buffer size */ |
u_long sb_max = SB_MAX; /* maximum socket buffer size */ |
static u_long sb_max_adj; /* adjusted sb_max */ |
static u_long sb_max_adj; /* adjusted sb_max */ |
Line 185 soisconnected(struct socket *so) |
|
Line 178 soisconnected(struct socket *so) |
|
|
|
so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING); |
so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING); |
so->so_state |= SS_ISCONNECTED; |
so->so_state |= SS_ISCONNECTED; |
if (head && soqremque(so, 0)) { |
if (head && so->so_onq == &head->so_q0) { |
soqinsque(head, so, 1); |
if ((so->so_options & SO_ACCEPTFILTER) == 0) { |
sorwakeup(head); |
soqremque(so, 0); |
cv_broadcast(&head->so_cv); |
soqinsque(head, so, 1); |
|
sorwakeup(head); |
|
cv_broadcast(&head->so_cv); |
|
} else { |
|
so->so_upcall = |
|
head->so_accf->so_accept_filter->accf_callback; |
|
so->so_upcallarg = head->so_accf->so_accept_filter_arg; |
|
so->so_rcv.sb_flags |= SB_UPCALL; |
|
so->so_options &= ~SO_ACCEPTFILTER; |
|
(*so->so_upcall)(so, so->so_upcallarg, |
|
POLLIN|POLLRDNORM, M_DONTWAIT); |
|
} |
} else { |
} else { |
cv_broadcast(&so->so_cv); |
cv_broadcast(&so->so_cv); |
sorwakeup(so); |
sorwakeup(so); |
Line 222 soisdisconnected(struct socket *so) |
|
Line 226 soisdisconnected(struct socket *so) |
|
sorwakeup(so); |
sorwakeup(so); |
} |
} |
|
|
|
void |
|
soinit2(void) |
|
{ |
|
|
|
socket_cache = pool_cache_init(sizeof(struct socket), 0, 0, 0, |
|
"socket", NULL, IPL_SOFTNET, NULL, NULL, NULL); |
|
} |
|
|
/* |
/* |
* When an attempt at a new connection is noted on a socket |
* When an attempt at a new connection is noted on a socket |
* which accepts connections, sonewconn is called. If the |
* which accepts connections, sonewconn is called. If the |
Line 236 sonewconn(struct socket *head, int conns |
|
Line 248 sonewconn(struct socket *head, int conns |
|
struct socket *so; |
struct socket *so; |
int soqueue, error; |
int soqueue, error; |
|
|
|
KASSERT(connstatus == 0 || connstatus == SS_ISCONFIRMING || |
|
connstatus == SS_ISCONNECTED); |
KASSERT(solocked(head)); |
KASSERT(solocked(head)); |
|
|
|
if ((head->so_options & SO_ACCEPTFILTER) != 0) |
|
connstatus = 0; |
soqueue = connstatus ? 1 : 0; |
soqueue = connstatus ? 1 : 0; |
if (head->so_qlen + head->so_q0len > 3 * head->so_qlimit / 2) |
if (head->so_qlen + head->so_q0len > 3 * head->so_qlimit / 2) |
return ((struct socket *)0); |
return NULL; |
so = soget(false); |
so = soget(false); |
if (so == NULL) |
if (so == NULL) |
return (NULL); |
return NULL; |
mutex_obj_hold(head->so_lock); |
mutex_obj_hold(head->so_lock); |
so->so_lock = head->so_lock; |
so->so_lock = head->so_lock; |
so->so_type = head->so_type; |
so->so_type = head->so_type; |
Line 257 sonewconn(struct socket *head, int conns |
|
Line 273 sonewconn(struct socket *head, int conns |
|
so->so_send = head->so_send; |
so->so_send = head->so_send; |
so->so_receive = head->so_receive; |
so->so_receive = head->so_receive; |
so->so_uidinfo = head->so_uidinfo; |
so->so_uidinfo = head->so_uidinfo; |
|
so->so_cpid = head->so_cpid; |
#ifdef MBUFTRACE |
#ifdef MBUFTRACE |
so->so_mowner = head->so_mowner; |
so->so_mowner = head->so_mowner; |
so->so_rcv.sb_mowner = head->so_rcv.sb_mowner; |
so->so_rcv.sb_mowner = head->so_rcv.sb_mowner; |
so->so_snd.sb_mowner = head->so_snd.sb_mowner; |
so->so_snd.sb_mowner = head->so_snd.sb_mowner; |
#endif |
#endif |
(void) soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat); |
if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat) != 0) |
|
goto out; |
so->so_snd.sb_lowat = head->so_snd.sb_lowat; |
so->so_snd.sb_lowat = head->so_snd.sb_lowat; |
so->so_rcv.sb_lowat = head->so_rcv.sb_lowat; |
so->so_rcv.sb_lowat = head->so_rcv.sb_lowat; |
so->so_rcv.sb_timeo = head->so_rcv.sb_timeo; |
so->so_rcv.sb_timeo = head->so_rcv.sb_timeo; |
Line 275 sonewconn(struct socket *head, int conns |
|
Line 293 sonewconn(struct socket *head, int conns |
|
KASSERT(solocked(so)); |
KASSERT(solocked(so)); |
if (error != 0) { |
if (error != 0) { |
(void) soqremque(so, soqueue); |
(void) soqremque(so, soqueue); |
|
out: |
|
/* |
|
* Remove acccept filter if one is present. |
|
* XXX Is this really needed? |
|
*/ |
|
if (so->so_accf != NULL) |
|
(void)accept_filt_clear(so); |
soput(so); |
soput(so); |
return (NULL); |
return NULL; |
} |
} |
if (connstatus) { |
if (connstatus) { |
sorwakeup(head); |
sorwakeup(head); |
cv_broadcast(&head->so_cv); |
cv_broadcast(&head->so_cv); |
so->so_state |= connstatus; |
so->so_state |= connstatus; |
} |
} |
return (so); |
return so; |
} |
} |
|
|
struct socket * |
struct socket * |
Line 291 soget(bool waitok) |
|
Line 316 soget(bool waitok) |
|
{ |
{ |
struct socket *so; |
struct socket *so; |
|
|
so = pool_get(&socket_pool, (waitok ? PR_WAITOK : PR_NOWAIT)); |
so = pool_cache_get(socket_cache, (waitok ? PR_WAITOK : PR_NOWAIT)); |
if (__predict_false(so == NULL)) |
if (__predict_false(so == NULL)) |
return (NULL); |
return (NULL); |
memset(so, 0, sizeof(*so)); |
memset(so, 0, sizeof(*so)); |
Line 320 soput(struct socket *so) |
|
Line 345 soput(struct socket *so) |
|
cv_destroy(&so->so_cv); |
cv_destroy(&so->so_cv); |
cv_destroy(&so->so_rcv.sb_cv); |
cv_destroy(&so->so_rcv.sb_cv); |
cv_destroy(&so->so_snd.sb_cv); |
cv_destroy(&so->so_snd.sb_cv); |
pool_put(&socket_pool, so); |
pool_cache_put(socket_cache, so); |
} |
} |
|
|
void |
void |
Line 447 sowakeup(struct socket *so, struct sockb |
|
Line 472 sowakeup(struct socket *so, struct sockb |
|
if (sb->sb_flags & SB_ASYNC) |
if (sb->sb_flags & SB_ASYNC) |
fownsignal(so->so_pgid, SIGIO, code, band, so); |
fownsignal(so->so_pgid, SIGIO, code, band, so); |
if (sb->sb_flags & SB_UPCALL) |
if (sb->sb_flags & SB_UPCALL) |
(*so->so_upcall)(so, so->so_upcallarg, M_DONTWAIT); |
(*so->so_upcall)(so, so->so_upcallarg, band, M_DONTWAIT); |
|
} |
|
|
|
/* |
|
* Reset a socket's lock pointer. Wake all threads waiting on the |
|
* socket's condition variables so that they can restart their waits |
|
* using the new lock. The existing lock must be held. |
|
*/ |
|
void |
|
solockreset(struct socket *so, kmutex_t *lock) |
|
{ |
|
|
|
KASSERT(solocked(so)); |
|
|
|
so->so_lock = lock; |
|
cv_broadcast(&so->so_snd.sb_cv); |
|
cv_broadcast(&so->so_rcv.sb_cv); |
|
cv_broadcast(&so->so_cv); |
} |
} |
|
|
/* |
/* |
Line 553 sbreserve(struct sockbuf *sb, u_long cc, |
|
Line 595 sbreserve(struct sockbuf *sb, u_long cc, |
|
|
|
if (cc == 0 || cc > sb_max_adj) |
if (cc == 0 || cc > sb_max_adj) |
return (0); |
return (0); |
if (so) { |
|
if (kauth_cred_geteuid(l->l_cred) == so->so_uidinfo->ui_uid) |
maxcc = l->l_proc->p_rlimit[RLIMIT_SBSIZE].rlim_cur; |
maxcc = l->l_proc->p_rlimit[RLIMIT_SBSIZE].rlim_cur; |
|
else |
uidinfo = so->so_uidinfo; |
maxcc = RLIM_INFINITY; |
|
uidinfo = so->so_uidinfo; |
|
} else { |
|
uidinfo = uid_find(0); /* XXX: nothing better */ |
|
maxcc = RLIM_INFINITY; |
|
} |
|
if (!chgsbsize(uidinfo, &sb->sb_hiwat, cc, maxcc)) |
if (!chgsbsize(uidinfo, &sb->sb_hiwat, cc, maxcc)) |
return 0; |
return 0; |
sb->sb_mbmax = min(cc * 2, sb_max); |
sb->sb_mbmax = min(cc * 2, sb_max); |
Line 1394 sbunlock(struct sockbuf *sb) |
|
Line 1430 sbunlock(struct sockbuf *sb) |
|
} |
} |
|
|
int |
int |
sowait(struct socket *so, int timo) |
sowait(struct socket *so, bool catch, int timo) |
{ |
{ |
kmutex_t *lock; |
kmutex_t *lock; |
int error; |
int error; |
|
|
KASSERT(solocked(so)); |
KASSERT(solocked(so)); |
|
KASSERT(catch || timo != 0); |
|
|
lock = so->so_lock; |
lock = so->so_lock; |
error = cv_timedwait_sig(&so->so_cv, lock, timo); |
if (catch) |
|
error = cv_timedwait_sig(&so->so_cv, lock, timo); |
|
else |
|
error = cv_timedwait(&so->so_cv, lock, timo); |
if (__predict_false(lock != so->so_lock)) |
if (__predict_false(lock != so->so_lock)) |
solockretry(so, lock); |
solockretry(so, lock); |
return error; |
return error; |